From 84e1e12b66a3eb51a763cca2554b82ddeba1daa0 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 20 Dec 2016 02:59:47 +1300 Subject: [PATCH] #900 - Error - Can't fetch JsonDB field - org.postgresql.util.PSQLException: ERROR: could not identify an equality operator for type json --- .../java/io/ebeaninternal/api/SpiQuery.java | 5 ++ .../server/query/CQueryBuilder.java | 40 ++++++------- .../server/query/DefaultDbSqlContext.java | 8 +-- .../ebeaninternal/server/query/SqlTree.java | 9 ++- .../server/query/SqlTreeBuilder.java | 53 ++++++++++++++--- .../server/query/SqlTreeNode.java | 8 ++- .../server/query/SqlTreeNodeBean.java | 20 +++++-- .../server/query/SqlTreeNodeExtraJoin.java | 5 ++ .../server/query/SqlTreeNodeManyRoot.java | 9 +++ .../query/SqlTreeNodeManyWhereJoin.java | 5 ++ .../server/query/SqlTreeNodeRoot.java | 12 ++++ .../server/querydefn/DefaultOrmQuery.java | 5 ++ .../IsEmptyExpressionQueryTest.java | 14 ++++- .../java/org/tests/json/TestJsonMapBasic.java | 35 +++++++++++ .../org/tests/model/json/EBasicJsonMap.java | 15 +++++ .../java/org/tests/model/pview/TestPview.java | 5 +- .../TestImplicitJoinOnParentRelationship.java | 34 ++++++++--- .../org/tests/query/TestManyWhereJoin.java | 59 +++++++++++++------ .../joins/TestDisjunctWhereOuterOnMany.java | 12 +++- .../orderby/TestOrderByWithDistinct.java | 21 +++++-- .../orderby/TestOrderByWithDistinctTake2.java | 29 ++++++--- .../other/TestQueryConversationRowCount.java | 15 +++-- .../other/TestQueryRowCountWithMany.java | 23 +++++--- 23 files changed, 339 insertions(+), 102 deletions(-) diff --git a/src/main/java/io/ebeaninternal/api/SpiQuery.java b/src/main/java/io/ebeaninternal/api/SpiQuery.java index 3ab778f71..5dd405414 100644 --- a/src/main/java/io/ebeaninternal/api/SpiQuery.java +++ b/src/main/java/io/ebeaninternal/api/SpiQuery.java @@ -674,6 +674,11 @@ public interface SpiQuery extends Query { */ boolean isDistinctQuery(); + /** + * Return true if this was internally set to sql distinct (ie. many where predicate). + */ + boolean isSqlDistinct(); + /** * Return true if this query has been specified by a user to use DISTINCT. */ diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index 45fff963c..9e1f3c1fa 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.query; +import io.ebean.Platform; import io.ebean.RawSql; import io.ebean.RawSql.ColumnMapping; import io.ebean.RawSql.ColumnMapping.Column; @@ -39,8 +40,8 @@ import java.util.List; */ class CQueryBuilder { - private final String tableAliasPlaceHolder; - private final String columnAliasPrefix; + protected final String tableAliasPlaceHolder; + protected final String columnAliasPrefix; private final SqlLimiter sqlLimiter; @@ -110,7 +111,7 @@ class CQueryBuilder { predicates.prepare(true); - SqlTree sqlTree = createSqlTree(request, predicates, getHistorySupport(query), getDraftSupport(query)); + SqlTree sqlTree = createSqlTree(request, predicates); String sql; if (type.equals("Delete")) { @@ -186,7 +187,7 @@ class CQueryBuilder { // use RawSql or generated Sql predicates.prepare(true); - SqlTree sqlTree = createSqlTree(request, predicates, getHistorySupport(query), getDraftSupport(query)); + SqlTree sqlTree = createSqlTree(request, predicates); SqlLimitResponse s = buildSql(null, request, predicates, sqlTree); queryPlan = new CQueryPlan(request, s.getSql(), sqlTree, false, s.isIncludesRowNumberColumn(), predicates.getLogWhereSql()); @@ -206,14 +207,14 @@ class CQueryBuilder { /** * Return the history support if this query needs it (is a 'as of' type query). */ - private CQueryHistorySupport getHistorySupport(SpiQuery query) { + CQueryHistorySupport getHistorySupport(SpiQuery query) { return query.getTemporalMode() != SpiQuery.TemporalMode.CURRENT ? historySupport : null; } /** * Return the draft support (or null) for a 'asDraft' query. */ - private CQueryDraftSupport getDraftSupport(SpiQuery query) { + CQueryDraftSupport getDraftSupport(SpiQuery query) { return query.getTemporalMode() == SpiQuery.TemporalMode.DRAFT ? draftSupport : null; } @@ -248,7 +249,7 @@ class CQueryBuilder { predicates.prepare(true); - SqlTree sqlTree = createSqlTree(request, predicates, getHistorySupport(query), getDraftSupport(query)); + SqlTree sqlTree = createSqlTree(request, predicates); if (SpiQuery.TemporalMode.CURRENT == query.getTemporalMode()) { sqlTree.addSoftDeletePredicate(query); } @@ -306,7 +307,7 @@ class CQueryBuilder { // Build the tree structure that represents the query. SpiQuery query = request.getQuery(); - SqlTree sqlTree = createSqlTree(request, predicates, getHistorySupport(query), getDraftSupport(query)); + SqlTree sqlTree = createSqlTree(request, predicates); if (query.isAsOfQuery()) { sqlTree.addAsOfTableAlias(query); } else if (SpiQuery.TemporalMode.CURRENT == query.getTemporalMode()) { @@ -347,7 +348,7 @@ class CQueryBuilder { * order by clauses that are not already included for the select clause. *

*/ - private SqlTree createSqlTree(OrmQueryRequest request, CQueryPredicates predicates, CQueryHistorySupport historySupport, CQueryDraftSupport draftSupport) { + private SqlTree createSqlTree(OrmQueryRequest request, CQueryPredicates predicates) { if (request.isNativeSql()) { return createNativeSqlTree(request, predicates); @@ -355,7 +356,7 @@ class CQueryBuilder { if (request.isRawSql()) { return createRawSqlSqlTree(request, predicates); } - return new SqlTreeBuilder(tableAliasPlaceHolder, columnAliasPrefix, request, predicates, historySupport, draftSupport).build(); + return new SqlTreeBuilder(this, request, predicates).build(); } /** @@ -517,13 +518,18 @@ class CQueryBuilder { sb.append("select "); if (query.isDistinctQuery()) { sb.append("distinct "); + String distinctOn = select.getDistinctOn(); + if (distinctOn != null) { + sb.append("on ("); + sb.append(distinctOn).append(") "); + } } } sb.append(select.getSelectSql()); if (query.isDistinctQuery() && dbOrderBy != null && !query.isSingleAttribute()) { // add the orderBy columns to the select clause (due to distinct) - sb.append(", ").append(convertDbOrderByForSelect(dbOrderBy)); + sb.append(", ").append(DbOrderByTrim.trim(dbOrderBy)); } } @@ -639,17 +645,11 @@ class CQueryBuilder { return true; } - /** - * Convert the dbOrderBy clause to be safe for adding to select. This is done when 'distinct' is - * used. - */ - private String convertDbOrderByForSelect(String dbOrderBy) { - // just remove the ASC and DESC keywords - return dbOrderBy.replaceAll("(?i)\\b asc\\b|\\b desc\\b", ""); - } - private boolean isEmpty(String s) { return s == null || s.isEmpty(); } + boolean isPlatformDistinctOn() { + return dbPlatform.isPlatform(Platform.POSTGRES); + } } diff --git a/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java b/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java index 4a271255d..8f4ce4aee 100644 --- a/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java +++ b/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java @@ -54,12 +54,12 @@ class DefaultDbSqlContext implements DbSqlContext { /** * Construct for SELECT clause (with column alias settings). */ - DefaultDbSqlContext(SqlTreeAlias alias, String tableAliasPlaceHolder, - String columnAliasPrefix, boolean alwaysUseColumnAlias, CQueryHistorySupport historySupport, CQueryDraftSupport draftSupport) { + DefaultDbSqlContext(SqlTreeAlias alias, CQueryBuilder builder, + boolean alwaysUseColumnAlias, CQueryHistorySupport historySupport, CQueryDraftSupport draftSupport) { this.alias = alias; - this.tableAliasPlaceHolder = tableAliasPlaceHolder; - this.columnAliasPrefix = columnAliasPrefix; + this.tableAliasPlaceHolder = builder.tableAliasPlaceHolder; + this.columnAliasPrefix = builder.columnAliasPrefix; this.useColumnAlias = alwaysUseColumnAlias; this.draftSupport = draftSupport; this.historySupport = historySupport; diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTree.java b/src/main/java/io/ebeaninternal/server/query/SqlTree.java index a6a81459f..8e7d1a2ee 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTree.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTree.java @@ -27,6 +27,8 @@ class SqlTree { */ private final String summary; + private final String distinctOn; + private final String selectSql; private final String fromSql; @@ -48,11 +50,12 @@ class SqlTree { /** * Create the SqlSelectClause. */ - SqlTree(String summary, SqlTreeNode rootNode, String selectSql, String fromSql, String groupBy, String inheritanceWhereSql, + SqlTree(String summary, SqlTreeNode rootNode, String distinctOn, String selectSql, String fromSql, String groupBy, String inheritanceWhereSql, BeanProperty[] encryptedProps, BeanPropertyAssocMany manyProperty, Set includes, boolean includeJoins) { this.summary = summary; this.rootNode = rootNode; + this.distinctOn = distinctOn; this.selectSql = selectSql; this.fromSql = fromSql; this.groupBy = groupBy; @@ -100,6 +103,10 @@ class SqlTree { return includes; } + String getDistinctOn() { + return distinctOn; + } + /** * Return the String for the actual SQL. */ diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java index 864e8819b..d202f9572 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java @@ -46,6 +46,7 @@ public class SqlTreeBuilder { private final boolean subQuery; + private final boolean distinctOnPlatform; /** * Property if resultSet contains master and detail rows. */ @@ -85,6 +86,7 @@ public class SqlTreeBuilder { this.disableLazyLoad = request.getQuery().isDisableLazyLoading(); this.query = null; this.subQuery = false; + this.distinctOnPlatform = false; this.queryDetail = queryDetail; this.predicates = predicates; this.temporalMode = SpiQuery.TemporalMode.CURRENT; @@ -99,8 +101,7 @@ public class SqlTreeBuilder { * support the where and/or order by clause. If so these extra joins are added * to the root node. */ - public SqlTreeBuilder(String tableAliasPlaceHolder, String columnAliasPrefix, - OrmQueryRequest request, CQueryPredicates predicates, CQueryHistorySupport historySupport, CQueryDraftSupport draftSupport) { + public SqlTreeBuilder(CQueryBuilder builder, OrmQueryRequest request, CQueryPredicates predicates) { this.rawSql = false; this.rawNoId = false; @@ -115,7 +116,11 @@ public class SqlTreeBuilder { this.predicates = predicates; this.alias = new SqlTreeAlias(request.getBaseTableAlias()); - this.ctx = new DefaultDbSqlContext(alias, tableAliasPlaceHolder, columnAliasPrefix, !subQuery, historySupport, draftSupport); + this.distinctOnPlatform = builder.isPlatformDistinctOn(); + + CQueryHistorySupport historySupport = builder.getHistorySupport(query); + CQueryDraftSupport draftSupport = builder.getDraftSupport(query); + this.ctx = new DefaultDbSqlContext(alias, builder, !subQuery, historySupport, draftSupport); } /** @@ -129,6 +134,7 @@ public class SqlTreeBuilder { buildRoot(desc); // build the actual String + String distinctOn = null; String selectSql = null; String fromSql = null; String inheritanceWhereSql = null; @@ -139,12 +145,13 @@ public class SqlTreeBuilder { fromSql = buildFromClause(); inheritanceWhereSql = buildWhereClause(); groupBy = buildGroupByClause(); + distinctOn = buildDistinctOn(); encryptedProps = ctx.getEncryptedProps(); } boolean includeJoins = alias != null && alias.isIncludeJoins(); - return new SqlTree(summary.toString(), rootNode, selectSql, fromSql, groupBy, inheritanceWhereSql, encryptedProps, + return new SqlTree(summary.toString(), rootNode, distinctOn, selectSql, fromSql, groupBy, inheritanceWhereSql, encryptedProps, manyProperty, queryDetail.getFetchPaths(), includeJoins); } @@ -164,18 +171,46 @@ public class SqlTreeBuilder { } ctx.startGroupBy(); rootNode.appendGroupBy(ctx, subQuery); - String groupBy = ctx.getContent(); - return trimComma(groupBy); + return trimComma(ctx.getContent()); + } + + private String buildDistinctOn() { + + if (rawSql || !distinctOnPlatform || !query.isSqlDistinct() || Type.COUNT == query.getType()) { + return null; + } + ctx.startGroupBy(); + rootNode.appendDistinctOn(ctx, subQuery); + String idCols = trimComma(ctx.getContent()); + return idCols == null ? null : mergeOnDistinct(idCols, predicates.getDbOrderBy()); + } + + static String mergeOnDistinct(String idCols, String dbOrderBy) { + if (dbOrderBy == null) { + return idCols; + } + dbOrderBy = DbOrderByTrim.trim(dbOrderBy); + StringBuilder sb = new StringBuilder(dbOrderBy.length() + idCols.length() + 2); + sb.append(dbOrderBy); + String[] split = idCols.split(","); + for (String col : split) { + col = col.trim(); + if (!dbOrderBy.contains(col)) { + sb.append(", ").append(col); + } + } + return sb.toString(); } /** * Trim the first comma. */ private String trimComma(String groupBy) { - if (groupBy.length() >= SqlTreeNode.COMMA.length()) { - groupBy = groupBy.substring(SqlTreeNode.COMMA.length()); + if (groupBy.length() < SqlTreeNode.COMMA.length()) { + return null; + } else { + return groupBy.substring(SqlTreeNode.COMMA.length()); } - return groupBy; } private String buildWhereClause() { diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java index 8787caba6..27e60cbc8 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java @@ -25,8 +25,12 @@ interface SqlTreeNode { boolean isAggregation(); /** - * Append the required column information to the SELECT part of the sql - * statement. + * Append the distinct on clause (Id properties of root and many root only). + */ + void appendDistinctOn(DbSqlContext ctx, boolean subQuery); + + /** + * Append the required column information to the select clause. */ void appendSelect(DbSqlContext ctx, boolean subQuery); diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java index c2ed06810..1335f60ea 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -33,7 +33,7 @@ class SqlTreeNodeBean implements SqlTreeNode { protected final BeanDescriptor desc; - private final IdBinder idBinder; + protected final IdBinder idBinder; /** * The children which will be other SelectBean or SelectProxyBean. @@ -57,7 +57,7 @@ class SqlTreeNodeBean implements SqlTreeNode { /** * False if report bean and has no id property. */ - private final boolean readId; + protected final boolean readId; private final boolean disableLazyLoad; @@ -171,10 +171,10 @@ class SqlTreeNodeBean implements SqlTreeNode { property.buildRawSqlSelectChain(prefix, selectChain); } // recursively continue reading... - for (SqlTreeNode aChildren : children) { + for (SqlTreeNode child : children) { // read each child... and let them set their // values back to this localBean - aChildren.buildRawSqlSelectChain(selectChain); + child.buildRawSqlSelectChain(selectChain); } } @@ -401,6 +401,15 @@ class SqlTreeNodeBean implements SqlTreeNode { ctx.popJoin(); } + /** + * Append the property columns to the buffer. + */ + public void appendDistinctOn(DbSqlContext ctx, boolean subQuery) { + for (SqlTreeNode child : children) { + child.appendDistinctOn(ctx, subQuery); + } + } + /** * Append the property columns to the buffer. */ @@ -451,8 +460,7 @@ class SqlTreeNodeBean implements SqlTreeNode { } } - private void appendSelectId(DbSqlContext ctx, BeanProperty prop) { - + protected void appendSelectId(DbSqlContext ctx, BeanProperty prop) { if (prop != null) { prop.appendSelect(ctx, false); } diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java index 1caaea1aa..71a06be0a 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java @@ -56,6 +56,11 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode { // nothing to do here } + @Override + public void appendDistinctOn(DbSqlContext ctx, boolean subQuery) { + // do nothing here ... + } + @Override public boolean isAggregation() { return false; diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java index 5a38ab192..0bfe6ff90 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java @@ -19,6 +19,15 @@ final class SqlTreeNodeManyRoot extends SqlTreeNodeBean { this.manyProp = prop; } + /** + * Append the property columns to the buffer. + */ + public void appendDistinctOn(DbSqlContext ctx, boolean subQuery) { + ctx.pushTableAlias(prefix); + appendSelectId(ctx, idBinder.getBeanProperty()); + ctx.popTableAlias(); + } + @Override public EntityBean load(DbReadContext cquery, EntityBean parentBean, EntityBean contextParent) throws SQLException { // pass in null for parentBean because the localBean diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java index 165aef3e9..ff09a1e85 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java @@ -60,6 +60,11 @@ class SqlTreeNodeManyWhereJoin implements SqlTreeNode { return false; } + @Override + public void appendDistinctOn(DbSqlContext ctx, boolean subQuery) { + // do nothing here ... + } + @Override public void appendGroupBy(DbSqlContext ctx, boolean subQuery) { // do nothing here diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java index e8e23ec8b..112cf16cf 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java @@ -25,6 +25,18 @@ final class SqlTreeNodeRoot extends SqlTreeNodeBean { this.includeJoin = includeJoin; } + /** + * Append the property columns to the buffer. + */ + public void appendDistinctOn(DbSqlContext ctx, boolean subQuery) { + if (readId) { + ctx.pushTableAlias(prefix); + appendSelectId(ctx, idBinder.getBeanProperty()); + ctx.popTableAlias(); + super.appendDistinctOn(ctx, subQuery); + } + } + /** * Set AsOf support (at root level). */ diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 81fc58b97..7a7644226 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -1351,6 +1351,11 @@ public class DefaultOrmQuery implements SpiQuery { return distinct || sqlDistinct; } + @Override + public boolean isSqlDistinct() { + return sqlDistinct; + } + /** * Internally set to use SQL DISTINCT on the query but still have id property included. */ diff --git a/src/test/java/io/ebeaninternal/server/expression/IsEmptyExpressionQueryTest.java b/src/test/java/io/ebeaninternal/server/expression/IsEmptyExpressionQueryTest.java index f0c22fdd6..3222af9d0 100644 --- a/src/test/java/io/ebeaninternal/server/expression/IsEmptyExpressionQueryTest.java +++ b/src/test/java/io/ebeaninternal/server/expression/IsEmptyExpressionQueryTest.java @@ -94,7 +94,12 @@ public class IsEmptyExpressionQueryTest extends BaseTestCase { .query(); query.findList(); - assertThat(sqlOf(query)).contains("select distinct t0.id from o_customer t0 join contact u1 on u1.customer_id = t0.id where not exists (select 1 from contact_note where contact_id = u1.id)"); + if (isPostgres()) { + assertThat(sqlOf(query)).contains("select distinct on (t0.id) t0.id from o_customer t0 join contact u1 on u1.customer_id = t0.id where not exists (select 1 from contact_note where contact_id = u1.id)"); + + } else { + assertThat(sqlOf(query)).contains("select distinct t0.id from o_customer t0 join contact u1 on u1.customer_id = t0.id where not exists (select 1 from contact_note where contact_id = u1.id)"); + } } @Test @@ -108,7 +113,12 @@ public class IsEmptyExpressionQueryTest extends BaseTestCase { .query(); query.findList(); - assertThat(sqlOf(query)).contains("select distinct t0.id from o_customer t0 join contact u1 on u1.customer_id = t0.id where exists (select 1 from contact_note where contact_id = u1.id)"); + if (isPostgres()) { + assertThat(sqlOf(query)).contains("select distinct on (t0.id) t0.id from o_customer t0 join contact u1 on u1.customer_id = t0.id where exists (select 1 from contact_note where contact_id = u1.id)"); + + } else { + assertThat(sqlOf(query)).contains("select distinct t0.id from o_customer t0 join contact u1 on u1.customer_id = t0.id where exists (select 1 from contact_note where contact_id = u1.id)"); + } } } diff --git a/src/test/java/org/tests/json/TestJsonMapBasic.java b/src/test/java/org/tests/json/TestJsonMapBasic.java index 202205dd8..2edad3554 100644 --- a/src/test/java/org/tests/json/TestJsonMapBasic.java +++ b/src/test/java/org/tests/json/TestJsonMapBasic.java @@ -2,17 +2,52 @@ package org.tests.json; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import io.ebean.Query; import io.ebean.text.json.EJson; import org.tests.model.json.EBasicJsonMap; import org.junit.Test; +import org.tests.model.json.EBasicJsonMapDetail; import java.io.IOException; import java.util.Map; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; public class TestJsonMapBasic extends BaseTestCase { + @Test + public void whereManyPredicate() { + + if (!isPostgres()) { + // testing postgres specific select distinct on clause + return; + } + + EBasicJsonMap bean = new EBasicJsonMap(); + bean.setName("own1"); + bean.getDetails().add(new EBasicJsonMapDetail("detail1")); + bean.getDetails().add(new EBasicJsonMapDetail("detail2")); + + Ebean.save(bean); + + Query query1 = Ebean.find(EBasicJsonMap.class) + .fetch("details") + .where().startsWith("details.name", "detail") + .query(); + + query1.findList(); + + assertThat(query1.getGeneratedSql()).contains("select distinct on (t0.id, t1.id) "); + + Query query2 = Ebean.find(EBasicJsonMap.class) + .where().startsWith("details.name", "detail") + .query(); + query2.findList(); + + assertThat(query2.getGeneratedSql()).contains("select distinct on (t0.id) "); + } + @Test public void testInsertUpdateDelete() throws IOException { diff --git a/src/test/java/org/tests/model/json/EBasicJsonMap.java b/src/test/java/org/tests/model/json/EBasicJsonMap.java index f18408154..520016df9 100644 --- a/src/test/java/org/tests/model/json/EBasicJsonMap.java +++ b/src/test/java/org/tests/model/json/EBasicJsonMap.java @@ -2,9 +2,13 @@ package org.tests.model.json; import io.ebean.annotation.DbJson; +import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.Id; +import javax.persistence.OneToMany; import javax.persistence.Version; +import java.util.ArrayList; +import java.util.List; import java.util.Map; @Entity @@ -21,6 +25,9 @@ public class EBasicJsonMap { @DbJson Map content; + @OneToMany(mappedBy = "owner", cascade = CascadeType.ALL) + List details = new ArrayList<>(); + public Long getId() { return id; } @@ -37,6 +44,14 @@ public class EBasicJsonMap { this.version = version; } + public List getDetails() { + return details; + } + + public void setDetails(List details) { + this.details = details; + } + public String getName() { return name; } diff --git a/src/test/java/org/tests/model/pview/TestPview.java b/src/test/java/org/tests/model/pview/TestPview.java index 2ef00487b..2b9f55b1f 100644 --- a/src/test/java/org/tests/model/pview/TestPview.java +++ b/src/test/java/org/tests/model/pview/TestPview.java @@ -3,11 +3,12 @@ package org.tests.model.pview; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Query; -import org.junit.Assert; import org.junit.Test; import java.util.UUID; +import static org.assertj.core.api.Assertions.assertThat; + public class TestPview extends BaseTestCase { @Test @@ -22,7 +23,7 @@ public class TestPview extends BaseTestCase { query.findList(); String generatedSql = sqlOf(query, 1); - Assert.assertTrue(generatedSql.contains("select distinct t0.amount, t1.value from paggview t0 join pp u1 on u1.id = t0.pview_id join pp_to_ww u2z_ on u2z_.pp_id = u1.id join wview u2 on u2.id = u2z_.ww_id left join pp t1 on t1.id = t0.pview_id where u2.id = ? order by t1.value")); + assertThat(generatedSql).contains("select distinct t0.amount, t1.value from paggview t0 join pp u1 on u1.id = t0.pview_id join pp_to_ww u2z_ on u2z_.pp_id = u1.id join wview u2 on u2.id = u2z_.ww_id left join pp t1 on t1.id = t0.pview_id where u2.id = ? order by t1.value"); } diff --git a/src/test/java/org/tests/query/TestImplicitJoinOnParentRelationship.java b/src/test/java/org/tests/query/TestImplicitJoinOnParentRelationship.java index 5b100d92e..92faa6f94 100644 --- a/src/test/java/org/tests/query/TestImplicitJoinOnParentRelationship.java +++ b/src/test/java/org/tests/query/TestImplicitJoinOnParentRelationship.java @@ -3,10 +3,11 @@ package org.tests.query; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Query; +import org.junit.Test; import org.tests.model.basic.Customer; import org.tests.model.basic.ResetBasicData; -import org.junit.Assert; -import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; public class TestImplicitJoinOnParentRelationship extends BaseTestCase { @@ -22,8 +23,14 @@ public class TestImplicitJoinOnParentRelationship extends BaseTestCase { query.findList(); - String expectedSql = "select distinct t0.id, t0.name from o_customer t0 join o_order u1 on u1.kcustomer_id = t0.id join o_order_detail u2 on u2.order_id = u1.id join o_product u3 on u3.id = u2.product_id where u3.name = ? "; - Assert.assertEquals(expectedSql, sqlOf(query, 1)); + if (isPostgres()) { + String expectedSql = "select distinct on (t0.id) t0.id, t0.name from o_customer t0 join o_order u1 on u1.kcustomer_id = t0.id join o_order_detail u2 on u2.order_id = u1.id join o_product u3 on u3.id = u2.product_id where u3.name = ? "; + assertThat(sqlOf(query, 1)).contains(expectedSql); + + } else { + String expectedSql = "select distinct t0.id, t0.name from o_customer t0 join o_order u1 on u1.kcustomer_id = t0.id join o_order_detail u2 on u2.order_id = u1.id join o_product u3 on u3.id = u2.product_id where u3.name = ? "; + assertThat(sqlOf(query, 1)).contains(expectedSql); + } // select distinct t0.id c0, t0.name c1 // from o_customer t0 @@ -47,8 +54,13 @@ public class TestImplicitJoinOnParentRelationship extends BaseTestCase { query.findList(); - String expectedSql = "select distinct t0.id, t0.name from o_customer t0 left join o_order u1 on u1.kcustomer_id = t0.id left join o_order_detail u2 on u2.order_id = u1.id left join o_product u3 on u3.id = u2.product_id where (u3.name = ? or t0.id = ? ) "; - Assert.assertEquals(expectedSql, sqlOf(query, 1)); + if (isPostgres()) { + String expectedSql = "select distinct on (t0.id) t0.id, t0.name from o_customer t0 left join o_order u1 on u1.kcustomer_id = t0.id left join o_order_detail u2 on u2.order_id = u1.id left join o_product u3 on u3.id = u2.product_id where (u3.name = ? or t0.id = ? ) "; + assertThat(sqlOf(query, 1)).contains(expectedSql); + } else { + String expectedSql = "select distinct t0.id, t0.name from o_customer t0 left join o_order u1 on u1.kcustomer_id = t0.id left join o_order_detail u2 on u2.order_id = u1.id left join o_product u3 on u3.id = u2.product_id where (u3.name = ? or t0.id = ? ) "; + assertThat(sqlOf(query, 1)).contains(expectedSql); + } } @Test @@ -63,7 +75,13 @@ public class TestImplicitJoinOnParentRelationship extends BaseTestCase { query.findList(); - String expectedSql = "select distinct t0.id, t0.name from o_customer t0 left join o_order u1 on u1.kcustomer_id = t0.id left join o_order_detail u2 on u2.order_id = u1.id left join o_product u3 on u3.id = u2.product_id where (u3.name = ? or t0.id = ? ) "; - Assert.assertEquals(expectedSql, sqlOf(query, 1)); + if (isPostgres()) { + String expectedSql = "select distinct on (t0.id) t0.id, t0.name from o_customer t0 left join o_order u1 on u1.kcustomer_id = t0.id left join o_order_detail u2 on u2.order_id = u1.id left join o_product u3 on u3.id = u2.product_id where (u3.name = ? or t0.id = ? ) "; + assertThat(sqlOf(query, 1)).contains(expectedSql); + + } else { + String expectedSql = "select distinct t0.id, t0.name from o_customer t0 left join o_order u1 on u1.kcustomer_id = t0.id left join o_order_detail u2 on u2.order_id = u1.id left join o_product u3 on u3.id = u2.product_id where (u3.name = ? or t0.id = ? ) "; + assertThat(sqlOf(query, 1)).contains(expectedSql); + } } } diff --git a/src/test/java/org/tests/query/TestManyWhereJoin.java b/src/test/java/org/tests/query/TestManyWhereJoin.java index 4ee1fc62d..4060dc714 100644 --- a/src/test/java/org/tests/query/TestManyWhereJoin.java +++ b/src/test/java/org/tests/query/TestManyWhereJoin.java @@ -7,9 +7,10 @@ import org.tests.model.basic.Customer; import org.tests.model.basic.Order; import org.tests.model.basic.Product; import org.tests.model.basic.ResetBasicData; -import org.junit.Assert; import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; + public class TestManyWhereJoin extends BaseTestCase { @Test @@ -33,10 +34,14 @@ public class TestManyWhereJoin extends BaseTestCase { // join o_order u1 on u1.kcustomer_id = t0.id // where u1.status = ? ; --bind(NEW) - Assert.assertTrue(sql.contains("select distinct ")); - Assert.assertTrue(sql.contains("join o_order ")); - Assert.assertTrue(sql.contains(".status = ?")); - Assert.assertTrue(sql.contains("select distinct t0.id, t0.status from o_customer t0 join o_order u1 on u1.kcustomer_id = t0.id where u1.status = ?")); + if (isPostgres()) { + assertThat(sql).contains("select distinct on (t0.id) t0.id, "); + } else { + assertThat(sql).contains("select distinct t0.id"); + } + assertThat(sql).contains("join o_order "); + assertThat(sql).contains(".status = ?"); + assertThat(sql).contains("t0.id, t0.status from o_customer t0 join o_order u1 on u1.kcustomer_id = t0.id where u1.status = ?"); } @Test @@ -65,10 +70,14 @@ public class TestManyWhereJoin extends BaseTestCase { // where t1.order_date is not null and u1.status = ? // order by t0.id; --bind(NEW) - Assert.assertTrue(sql.contains("select distinct t0.id, t0.status, t1.id, t1.status,")); - Assert.assertTrue(sql.contains("left join o_order t1 on ")); - Assert.assertTrue(sql.contains("join o_order u1 on ")); - Assert.assertTrue(sql.contains(" u1.status = ?")); + if (isPostgres()) { + assertThat(sql).contains("select distinct on (t0.id, t1.id) t0.id, t0.status,"); + } else { + assertThat(sql).contains("select distinct t0.id, t0.status, t1.id, t1.status,"); + } + assertThat(sql).contains("left join o_order t1 on "); + assertThat(sql).contains("join o_order u1 on "); + assertThat(sql).contains(" u1.status = ?"); } @Test @@ -92,9 +101,13 @@ public class TestManyWhereJoin extends BaseTestCase { // where u1.product_id = ? // order by t0.cretime; --bind(1) - Assert.assertTrue(sql.contains("select distinct t0.id, t0.status,")); - Assert.assertTrue(sql.contains(" join o_order_detail u1 on u1.order_id = t0.id")); - Assert.assertTrue(sql.contains(" where u1.product_id = ?")); + if (isPostgres()) { + assertThat(sql).contains("select distinct on (t0.cretime, t0.id) t0.id, t0.status,"); + } else { + assertThat(sql).contains("select distinct t0.id, t0.status,"); + } + assertThat(sql).contains(" join o_order_detail u1 on u1.order_id = t0.id"); + assertThat(sql).contains(" where u1.product_id = ?"); } /** @@ -122,9 +135,13 @@ public class TestManyWhereJoin extends BaseTestCase { // where u1.product_id = ? // order by t0.cretime - Assert.assertTrue(sql.contains("select distinct t0.id, t0.status,")); - Assert.assertTrue(sql.contains(" join o_order_detail u1 on u1.order_id = t0.id")); - Assert.assertTrue(sql.contains(" where u1.product_id = ?")); + if (isPostgres()) { + assertThat(sql).contains("select distinct on (t0.cretime, t0.id) t0.id, t0.status,"); + } else { + assertThat(sql).contains("select distinct t0.id, t0.status,"); + } + assertThat(sql).contains(" join o_order_detail u1 on u1.order_id = t0.id"); + assertThat(sql).contains(" where u1.product_id = ?"); } /** @@ -154,11 +171,15 @@ public class TestManyWhereJoin extends BaseTestCase { // where t1.id > 0 and u1.product_id = ? // order by t0.cretime, t0.id, t1.id asc, t1.order_qty asc, t1.cretime desc; --bind(1) - Assert.assertTrue(sql.contains("select distinct t0.id, t0.status,")); - Assert.assertTrue(sql.contains(" join o_order_detail u1 on u1.order_id = t0.id")); - Assert.assertTrue(sql.contains(" u1.product_id = ?")); + if (isPostgres()) { + assertThat(sql).contains("select distinct on (t0.cretime, t0.id, t1.id, t1.order_qty, t1.cretime) t0.id, t0.status,"); + } else { + assertThat(sql).contains("select distinct t0.id, t0.status,"); + } + assertThat(sql).contains(" join o_order_detail u1 on u1.order_id = t0.id"); + assertThat(sql).contains(" u1.product_id = ?"); // additional join for fetching the many details - Assert.assertTrue(sql.contains(" left join o_order_detail t1 on t1.order_id = t0.id")); + assertThat(sql).contains(" left join o_order_detail t1 on t1.order_id = t0.id"); } } diff --git a/src/test/java/org/tests/query/joins/TestDisjunctWhereOuterOnMany.java b/src/test/java/org/tests/query/joins/TestDisjunctWhereOuterOnMany.java index 84368a490..1cdd79c0d 100644 --- a/src/test/java/org/tests/query/joins/TestDisjunctWhereOuterOnMany.java +++ b/src/test/java/org/tests/query/joins/TestDisjunctWhereOuterOnMany.java @@ -10,6 +10,8 @@ import org.junit.Test; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; + public class TestDisjunctWhereOuterOnMany extends BaseTestCase { @Test @@ -55,8 +57,14 @@ public class TestDisjunctWhereOuterOnMany extends BaseTestCase { Assert.assertEquals(2, list.size()); Assert.assertEquals(2, rowCount); - String expectedSql = "select distinct t0.id, t0.name from uuone t0 left join uutwo u1 on u1.master_id = t0.id where (t0.name = ? or u1.name = ? ) "; - Assert.assertEquals(expectedSql, sqlOf(query, 1)); + if (isPostgres()) { + String expectedSql = "select distinct on (t0.id) t0.id, t0.name from uuone t0 left join uutwo u1 on u1.master_id = t0.id where (t0.name = ? or u1.name = ? ) "; + assertThat(sqlOf(query, 1)).contains(expectedSql); + + } else { + String expectedSql = "select distinct t0.id, t0.name from uuone t0 left join uutwo u1 on u1.master_id = t0.id where (t0.name = ? or u1.name = ? ) "; + assertThat(sqlOf(query, 1)).contains(expectedSql); + } } diff --git a/src/test/java/org/tests/query/orderby/TestOrderByWithDistinct.java b/src/test/java/org/tests/query/orderby/TestOrderByWithDistinct.java index f0e0f0062..4b5b2292a 100644 --- a/src/test/java/org/tests/query/orderby/TestOrderByWithDistinct.java +++ b/src/test/java/org/tests/query/orderby/TestOrderByWithDistinct.java @@ -84,9 +84,14 @@ public class TestOrderByWithDistinct extends BaseTestCase { Assert.assertEquals(1, list.size()); Assert.assertEquals(user1, list.get(0)); String generatedSql = query.getGeneratedSql(); - Assert.assertTrue(generatedSql.contains("select distinct t0.userid")); // using distinct - Assert.assertTrue(generatedSql.contains("order by t1.name,")); // name in order by - Assert.assertTrue(generatedSql.contains("t1.name"));// name in select + if (isPostgres()) { + assertThat(generatedSql).contains("select distinct on (t1.name, t0.user_name, t0.userid) t0.userid"); // using distinct + + } else { + assertThat(generatedSql).contains("select distinct t0.userid"); // using distinct + } + assertThat(generatedSql).contains("order by t1.name,"); // name in order by + assertThat(generatedSql).contains("t1.name");// name in select // repeat with slight variation, not sure this really produces a different execution path @@ -114,9 +119,13 @@ public class TestOrderByWithDistinct extends BaseTestCase { // order by t1.name; --bind(A) generatedSql = query.getGeneratedSql(); - Assert.assertTrue(generatedSql.contains("select distinct t0.userid")); // using distinct - Assert.assertTrue(generatedSql.contains("order by t1.name")); // name in order by - Assert.assertTrue(generatedSql.contains("t1.name"));// name in select + if (isPostgres()) { + assertThat(generatedSql).contains("select distinct on (t1.name, t0.userid) t0.userid"); // using distinct + } else { + assertThat(generatedSql).contains("select distinct t0.userid"); // using distinct + } + assertThat(generatedSql).contains("order by t1.name"); // name in order by + assertThat(generatedSql).contains("t1.name");// name in select } diff --git a/src/test/java/org/tests/query/orderby/TestOrderByWithDistinctTake2.java b/src/test/java/org/tests/query/orderby/TestOrderByWithDistinctTake2.java index 5f3cd9266..c80be3698 100644 --- a/src/test/java/org/tests/query/orderby/TestOrderByWithDistinctTake2.java +++ b/src/test/java/org/tests/query/orderby/TestOrderByWithDistinctTake2.java @@ -7,6 +7,8 @@ import org.tests.model.basic.Customer; import org.junit.Assert; import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; + public class TestOrderByWithDistinctTake2 extends BaseTestCase { @Test @@ -23,7 +25,7 @@ public class TestOrderByWithDistinctTake2 extends BaseTestCase { public void test() { Query query = Ebean.find(Customer.class) - .select("id") + .select("id, name") .where().ilike("contacts.firstName", "R%") .order("name desc"); @@ -36,10 +38,15 @@ public class TestOrderByWithDistinctTake2 extends BaseTestCase { // where lower(u1.first_name) like ? // order by t0.name; --bind(r%) - Assert.assertTrue("t0.name added to the select clause", generatedSql.contains("select distinct t0.id, t0.name")); - Assert.assertTrue(generatedSql.contains("order by t0.name desc")); - Assert.assertTrue(generatedSql.contains("from o_customer t0 join contact u1 on u1.customer_id = t0.id")); - Assert.assertTrue(generatedSql.contains("where lower(u1.first_name) like ?")); + if (isPostgres()) { + assertThat(generatedSql).contains("select distinct on (t0.name, t0.id) t0.id, t0.name"); + + } else { + assertThat(generatedSql).contains("select distinct t0.id, t0.name"); + } + assertThat(generatedSql).contains("order by t0.name desc"); + assertThat(generatedSql).contains("from o_customer t0 join contact u1 on u1.customer_id = t0.id"); + assertThat(generatedSql).contains("where lower(u1.first_name) like ?"); } @Test @@ -54,10 +61,14 @@ public class TestOrderByWithDistinctTake2 extends BaseTestCase { String generatedSql = sqlOf(query); - Assert.assertTrue("t0.name added to the select clause", generatedSql.contains("select distinct t0.id, t0.name, t0.id")); - Assert.assertTrue(generatedSql.contains("order by t0.name, t0.id desc")); - Assert.assertTrue(generatedSql.contains("from o_customer t0 join contact u1 on u1.customer_id = t0.id")); - Assert.assertTrue(generatedSql.contains("where lower(u1.first_name) like ?")); + if (isPostgres()) { + assertThat(generatedSql).contains("select distinct on (t0.name, t0.id) t0.id, t0.name, t0.id"); + } else { + assertThat(generatedSql).contains("select distinct t0.id, t0.name, t0.id"); + } + assertThat(generatedSql).contains("order by t0.name, t0.id desc"); + assertThat(generatedSql).contains("from o_customer t0 join contact u1 on u1.customer_id = t0.id"); + assertThat(generatedSql).contains("where lower(u1.first_name) like ?"); } } diff --git a/src/test/java/org/tests/query/other/TestQueryConversationRowCount.java b/src/test/java/org/tests/query/other/TestQueryConversationRowCount.java index db4d874a7..181a58a14 100644 --- a/src/test/java/org/tests/query/other/TestQueryConversationRowCount.java +++ b/src/test/java/org/tests/query/other/TestQueryConversationRowCount.java @@ -10,6 +10,8 @@ import org.junit.Test; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; + public class TestQueryConversationRowCount extends BaseTestCase { @Test @@ -40,9 +42,14 @@ public class TestQueryConversationRowCount extends BaseTestCase { // where t0.group_id = ? and ((t0.open = ? and u1.user_id = ? ) or t0.open = ? ) // order by t0.when_created desc; - Assert.assertTrue(generatedSql.contains("select distinct t0.id, t0.title, t0.isopen")); - Assert.assertTrue(generatedSql.contains("left join c_participation u1 on u1.conversation_id = t0.id")); - Assert.assertTrue(generatedSql.contains("where t0.group_id = ? and ((t0.isopen = ? and u1.user_id = ? ) or t0.isopen = ? )")); + if (isPostgres()) { + assertThat(generatedSql).contains("select distinct on (t0.when_created, t0.id) t0.id, t0.title, t0.isopen"); + + } else { + assertThat(generatedSql).contains("select distinct t0.id, t0.title, t0.isopen"); + } + assertThat(generatedSql).contains("left join c_participation u1 on u1.conversation_id = t0.id"); + assertThat(generatedSql).contains("where t0.group_id = ? and ((t0.isopen = ? and u1.user_id = ? ) or t0.isopen = ? )"); LoggedSqlCollector.start(); @@ -59,7 +66,7 @@ public class TestQueryConversationRowCount extends BaseTestCase { Assert.assertEquals(1, loggedSql.size()); String countSql = trimSql(loggedSql.get(0), 0); - Assert.assertTrue(countSql.contains("select count(*) from ( select distinct t0.id from c_conversation t0 left join c_participation u1 on u1.conversation_id = t0.id where t0.group_id = ? and ((t0.isopen = ? and u1.user_id = ? ) or t0.isopen = ? )")); + assertThat(countSql).contains("select count(*) from ( select distinct t0.id from c_conversation t0 left join c_participation u1 on u1.conversation_id = t0.id where t0.group_id = ? and ((t0.isopen = ? and u1.user_id = ? ) or t0.isopen = ? )"); } } diff --git a/src/test/java/org/tests/query/other/TestQueryRowCountWithMany.java b/src/test/java/org/tests/query/other/TestQueryRowCountWithMany.java index bc773a79c..0721a4d3c 100644 --- a/src/test/java/org/tests/query/other/TestQueryRowCountWithMany.java +++ b/src/test/java/org/tests/query/other/TestQueryRowCountWithMany.java @@ -11,6 +11,8 @@ import org.junit.Test; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; + public class TestQueryRowCountWithMany extends BaseTestCase { @Test @@ -39,11 +41,16 @@ public class TestQueryRowCountWithMany extends BaseTestCase { // order by t0.cretime, t0.id, t1.id asc, t1.order_qty asc, t1.cretime desc; --bind(1) String generatedSql = sqlOf(query, 1); - Assert.assertTrue(generatedSql.contains("select distinct t0.id, t0.status,")); // need the distinct - Assert.assertTrue(generatedSql.contains("left join o_order_detail t1 on t1.order_id = t0.id")); //fetch join - Assert.assertTrue(generatedSql.contains("join o_order_detail u1 on u1.order_id = t0.id")); //predicate join - Assert.assertTrue(generatedSql.contains(" u1.product_id = ?")); // u1 as predicate alias - Assert.assertTrue(generatedSql.contains(" order by t0.cretime")); + if (isPostgres()) { + assertThat(generatedSql).contains("select distinct on (t0.cretime, t0.id, t1.id, t1.order_qty, t1.cretime) t0.id, t0.status,"); // need the distinct + + } else { + assertThat(generatedSql).contains("select distinct t0.id, t0.status,"); // need the distinct + } + assertThat(generatedSql).contains("left join o_order_detail t1 on t1.order_id = t0.id"); //fetch join + assertThat(generatedSql).contains("join o_order_detail u1 on u1.order_id = t0.id"); //predicate join + assertThat(generatedSql).contains(" u1.product_id = ?"); // u1 as predicate alias + assertThat(generatedSql).contains(" order by t0.cretime"); int rowCount = query.findCount(); @@ -61,8 +68,8 @@ public class TestQueryRowCountWithMany extends BaseTestCase { Assert.assertEquals(list.size(), rowCount); Assert.assertEquals(2, sqlLogged.size()); - Assert.assertTrue(trimSql(sqlLogged.get(1), 1).contains( - "select count(*) from ( select distinct t0.id from o_order t0 join o_order_detail u1 on u1.order_id = t0.id where u1.product_id = ? )")); + assertThat(trimSql(sqlLogged.get(1), 1)).contains( + "select count(*) from ( select distinct t0.id from o_order t0 join o_order_detail u1 on u1.order_id = t0.id where u1.product_id = ? )"); } @@ -87,7 +94,7 @@ public class TestQueryRowCountWithMany extends BaseTestCase { List sqlLogged = LoggedSqlCollector.stop(); Assert.assertEquals(1, sqlLogged.size()); - Assert.assertTrue(trimSql(sqlLogged.get(0), 1).contains("select count(*) from ( select distinct t0.id from o_order t0 join o_order_detail u1 on u1.order_id = t0.id where u1.product_id = ? )")); + assertThat(trimSql(sqlLogged.get(0), 1)).contains("select count(*) from ( select distinct t0.id from o_order t0 join o_order_detail u1 on u1.order_id = t0.id where u1.product_id = ? )"); query.findList(); }