You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2017/03/21 12:55:33 UTC
cayenne git commit: CAY-2272 ColumnSelect: methods to manually
control DISTINCT clause
Repository: cayenne
Updated Branches:
refs/heads/master 8c4f1ad0f -> 32bdcda54
CAY-2272 ColumnSelect: methods to manually control DISTINCT clause
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/32bdcda5
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/32bdcda5
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/32bdcda5
Branch: refs/heads/master
Commit: 32bdcda545077bf6867fbc7e856109ae14fc01b1
Parents: 8c4f1ad
Author: Nikita Timofeev <st...@gmail.com>
Authored: Tue Mar 21 15:51:33 2017 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Tue Mar 21 15:51:33 2017 +0300
----------------------------------------------------------------------
.../cayenne/lifecycle/id/StringIdQuery.java | 5 ++
.../apache/cayenne/access/DataDomainQuery.java | 5 ++
.../cayenne/access/DataDomainQueryAction.java | 13 +++--
.../access/ObjectsFromDataRowsQuery.java | 5 ++
.../cayenne/access/jdbc/SelectAction.java | 3 +-
.../select/DefaultSelectTranslator.java | 13 +++--
.../apache/cayenne/query/BaseQueryMetadata.java | 8 +++
.../org/apache/cayenne/query/ColumnSelect.java | 22 ++++++++
.../cayenne/query/DefaultQueryMetadata.java | 8 +++
.../org/apache/cayenne/query/QueryMetadata.java | 5 ++
.../cayenne/query/QueryMetadataProxy.java | 5 ++
.../org/apache/cayenne/query/SelectQuery.java | 8 +++
.../cayenne/query/SelectQueryMetadata.java | 16 ++++++
.../apache/cayenne/query/ColumnSelectIT.java | 58 +++++++++++++++++++-
.../apache/cayenne/query/ColumnSelectTest.java | 18 ++++++
.../apache/cayenne/query/MockQueryMetadata.java | 5 ++
docs/doc/src/main/resources/RELEASE-NOTES.txt | 1 +
17 files changed, 184 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/id/StringIdQuery.java
----------------------------------------------------------------------
diff --git a/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/id/StringIdQuery.java b/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/id/StringIdQuery.java
index 2b28f44..56c500f 100644
--- a/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/id/StringIdQuery.java
+++ b/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/id/StringIdQuery.java
@@ -238,6 +238,11 @@ public class StringIdQuery implements Query {
public int getStatementFetchSize() {
return QueryMetadata.STATEMENT_FETCH_SIZE_DEFAULT;
}
+
+ @Override
+ public boolean isSuppressingDistinct() {
+ return false;
+ }
};
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainQuery.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainQuery.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainQuery.java
index 0488065..7d20356 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainQuery.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainQuery.java
@@ -160,4 +160,9 @@ class DataDomainQuery implements Query, QueryMetadata {
public int getStatementFetchSize() {
return 0;
}
+
+ @Override
+ public boolean isSuppressingDistinct() {
+ return false;
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java
index 6e9b9f8..7e00cca 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java
@@ -769,11 +769,14 @@ class DataDomainQueryAction implements QueryRouter, OperationObserver {
}
}
}
- Set<List<?>> seen = new HashSet<>(mainRows.size());
- Iterator<Object[]> it = mainRows.iterator();
- while (it.hasNext()) {
- if (!seen.add(Arrays.asList(it.next()))) {
- it.remove();
+
+ if(!metadata.isSuppressingDistinct()) {
+ Set<List<?>> seen = new HashSet<>(mainRows.size());
+ Iterator<Object[]> it = mainRows.iterator();
+ while (it.hasNext()) {
+ if (!seen.add(Arrays.asList(it.next()))) {
+ it.remove();
+ }
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/main/java/org/apache/cayenne/access/ObjectsFromDataRowsQuery.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/ObjectsFromDataRowsQuery.java b/cayenne-server/src/main/java/org/apache/cayenne/access/ObjectsFromDataRowsQuery.java
index ee23454..f0f319e 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/ObjectsFromDataRowsQuery.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/ObjectsFromDataRowsQuery.java
@@ -160,4 +160,9 @@ class ObjectsFromDataRowsQuery implements Query, QueryMetadata {
public int getStatementFetchSize() {
return 0;
}
+
+ @Override
+ public boolean isSuppressingDistinct() {
+ return false;
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SelectAction.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SelectAction.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SelectAction.java
index ce2a22b..8001067 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SelectAction.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SelectAction.java
@@ -180,7 +180,8 @@ public class SelectAction extends BaseSQLAction {
}
private <T> ResultIterator<T> forSuppressedDistinct(ResultIterator<T> iterator, SelectTranslator translator) {
- if (!translator.isSuppressingDistinct()) {
+ if (!translator.isSuppressingDistinct() ||
+ queryMetadata.isSuppressingDistinct()) {
return iterator;
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java
index 42ac0b8..61aec97 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java
@@ -153,12 +153,13 @@ public class DefaultSelectTranslator extends QueryAssembler implements SelectTra
// check if DISTINCT is appropriate
// side effect: "suppressingDistinct" flag may end up being flipped here
if (forcingDistinct || getSelectQuery().isDistinct()) {
- suppressingDistinct = false;
-
- for (ColumnDescriptor column : resultColumns) {
- if (isUnsupportedForDistinct(column.getJdbcType())) {
- suppressingDistinct = true;
- break;
+ suppressingDistinct = queryMetadata.isSuppressingDistinct();
+ if(!suppressingDistinct) {
+ for (ColumnDescriptor column : resultColumns) {
+ if (isUnsupportedForDistinct(column.getJdbcType())) {
+ suppressingDistinct = true;
+ break;
+ }
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/main/java/org/apache/cayenne/query/BaseQueryMetadata.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/query/BaseQueryMetadata.java b/cayenne-server/src/main/java/org/apache/cayenne/query/BaseQueryMetadata.java
index 8c523f5..92b7835 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/BaseQueryMetadata.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/BaseQueryMetadata.java
@@ -517,4 +517,12 @@ class BaseQueryMetadata implements QueryMetadata, XMLSerializable, Serializable
prefetchTree.removePath(prefetch);
}
}
+
+ /**
+ * @since 4.0
+ */
+ @Override
+ public boolean isSuppressingDistinct() {
+ return false;
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/main/java/org/apache/cayenne/query/ColumnSelect.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/query/ColumnSelect.java b/cayenne-server/src/main/java/org/apache/cayenne/query/ColumnSelect.java
index 69494b8..b0f708c 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/ColumnSelect.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/ColumnSelect.java
@@ -62,6 +62,8 @@ public class ColumnSelect<T> extends FluentSelect<T, ColumnSelect<T>> {
// package private for tests
boolean singleColumn = true;
private Expression having;
+ boolean distinct;
+ boolean suppressDistinct;
protected ColumnSelect() {
super();
@@ -93,6 +95,8 @@ public class ColumnSelect<T> extends FluentSelect<T, ColumnSelect<T>> {
replacement.setColumns(columns);
replacement.setHavingQualifier(having);
replacement.setCanReturnScalarValue(singleColumn);
+ replacement.setDistinct(distinct);
+ replacement.setSuppressDistinct(suppressDistinct);
return replacement;
}
@@ -286,6 +290,24 @@ public class ColumnSelect<T> extends FluentSelect<T, ColumnSelect<T>> {
return this;
}
+ /**
+ * Explicitly request distinct in query.
+ */
+ public ColumnSelect<T> distinct() {
+ this.suppressDistinct = false;
+ this.distinct = true;
+ return this;
+ }
+
+ /**
+ * Explicitly suppress distinct in query.
+ */
+ public ColumnSelect<T> suppressDistinct() {
+ this.suppressDistinct = true;
+ this.distinct = false;
+ return this;
+ }
+
private void setActiveExpression(Expression exp) {
if(havingExpressionIsActive) {
having = exp;
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/main/java/org/apache/cayenne/query/DefaultQueryMetadata.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/query/DefaultQueryMetadata.java b/cayenne-server/src/main/java/org/apache/cayenne/query/DefaultQueryMetadata.java
index 10dff3c..47aa751 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/DefaultQueryMetadata.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/DefaultQueryMetadata.java
@@ -163,4 +163,12 @@ class DefaultQueryMetadata implements QueryMetadata {
public int getStatementFetchSize() {
return QueryMetadata.STATEMENT_FETCH_SIZE_DEFAULT;
}
+
+ /**
+ * @since 4.0
+ */
+ @Override
+ public boolean isSuppressingDistinct() {
+ return false;
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/main/java/org/apache/cayenne/query/QueryMetadata.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/query/QueryMetadata.java b/cayenne-server/src/main/java/org/apache/cayenne/query/QueryMetadata.java
index 15a3057..3de4737 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/QueryMetadata.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/QueryMetadata.java
@@ -257,4 +257,9 @@ public interface QueryMetadata {
* @since 3.0
*/
int getStatementFetchSize();
+
+ /**
+ * @since 4.0
+ */
+ boolean isSuppressingDistinct();
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/main/java/org/apache/cayenne/query/QueryMetadataProxy.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/query/QueryMetadataProxy.java b/cayenne-server/src/main/java/org/apache/cayenne/query/QueryMetadataProxy.java
index 53ec1bf..259aa51 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/QueryMetadataProxy.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/QueryMetadataProxy.java
@@ -143,4 +143,9 @@ public class QueryMetadataProxy implements QueryMetadata {
public int getStatementFetchSize() {
return mdDelegate.getStatementFetchSize();
}
+
+ @Override
+ public boolean isSuppressingDistinct() {
+ return mdDelegate.isSuppressingDistinct();
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQuery.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQuery.java b/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQuery.java
index 97153cc..ff9660e 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQuery.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQuery.java
@@ -614,6 +614,14 @@ public class SelectQuery<T> extends AbstractQuery implements ParameterizedQuery,
}
/**
+ * Sets <code>distinct</code> property that determines whether this query
+ * returns distinct row.
+ */
+ public void setSuppressDistinct(boolean suppressDistinct) {
+ this.metaData.setSuppressingDistinct(suppressDistinct);
+ }
+
+ /**
* Adds one or more aliases for the qualifier expression path. Aliases serve
* to instruct Cayenne to generate separate sets of joins for overlapping
* paths, that maybe needed for complex conditions. An example of an
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQueryMetadata.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQueryMetadata.java b/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQueryMetadata.java
index 158fbea..cb4d195 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQueryMetadata.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQueryMetadata.java
@@ -59,6 +59,7 @@ class SelectQueryMetadata extends BaseQueryMetadata {
Map<String, String> pathSplitAliases;
boolean isSingleResultSetMapping;
+ boolean suppressingDistinct;
@Override
void copyFromInfo(QueryMetadata info) {
@@ -383,4 +384,19 @@ class SelectQueryMetadata extends BaseQueryMetadata {
public boolean isSingleResultSetMapping() {
return isSingleResultSetMapping;
}
+
+ /**
+ * @since 4.0
+ */
+ @Override
+ public boolean isSuppressingDistinct() {
+ return suppressingDistinct;
+ }
+
+ /**
+ * @since 4.0
+ */
+ public void setSuppressingDistinct(boolean suppressingDistinct) {
+ this.suppressingDistinct = suppressingDistinct;
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java b/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java
index 02102c5..2d79d29 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java
@@ -51,6 +51,7 @@ import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -75,7 +76,7 @@ public class ColumnSelectIT extends ServerCase {
// Format: d/m/YY
private static final DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
- private TableHelper tArtist;
+ private TableHelper tArtist, tPaintings;
@Before
public void createArtistsDataSet() throws Exception {
@@ -95,7 +96,7 @@ public class ColumnSelectIT extends ServerCase {
tGallery.setColumns("GALLERY_ID", "GALLERY_NAME");
tGallery.insert(1, "tate modern");
- TableHelper tPaintings = new TableHelper(dbHelper, "PAINTING");
+ tPaintings = new TableHelper(dbHelper, "PAINTING");
tPaintings.setColumns("PAINTING_ID", "PAINTING_TITLE", "ARTIST_ID", "GALLERY_ID", "ESTIMATED_PRICE");
for (int i = 1; i <= 20; i++) {
tPaintings.insert(i, "painting" + i, i % 5 + 1, 1, 22 - i);
@@ -839,4 +840,57 @@ public class ColumnSelectIT extends ServerCase {
assertEquals(4, result.size());
}
+ /*
+ * Test distinct() / suppressDistinct() methods
+ */
+
+ @Test
+ public void testExplicitDistinct() throws Exception {
+ tArtist.insert(21, "artist1", null);
+
+ List<String> result = ObjectSelect
+ .columnQuery(Artist.class, Artist.ARTIST_NAME)
+ .select(context);
+ assertEquals(21, result.size());
+
+ List<String> result2 = ObjectSelect
+ .columnQuery(Artist.class, Artist.ARTIST_NAME)
+ .suppressDistinct()
+ .select(context);
+ assertEquals(result, result2);
+
+ result = ObjectSelect
+ .columnQuery(Artist.class, Artist.ARTIST_NAME)
+ .distinct()
+ .select(context);
+ assertEquals(20, result.size());
+ }
+
+
+ @Test
+ public void testSuppressDistinct() throws Exception {
+ // create non unique artist name / painting name pair
+ tArtist.insert(21, "artist1", null);
+ tPaintings.insert(22, "painting10", 21, 1, 23);
+
+ List<Object[]> result = ObjectSelect
+ .columnQuery(Artist.class, Artist.ARTIST_NAME, Artist.PAINTING_ARRAY.dot(Painting.PAINTING_TITLE))
+ .select(context);
+ assertEquals(21, result.size());
+
+ List<Object[]> result2 = ObjectSelect
+ .columnQuery(Artist.class, Artist.ARTIST_NAME, Artist.PAINTING_ARRAY.dot(Painting.PAINTING_TITLE))
+ .distinct()
+ .select(context);
+ assertEquals(result.size(), result2.size());
+ for(int i=0; i<result.size(); i++) {
+ assertArrayEquals(result.get(i), result2.get(i));
+ }
+
+ result = ObjectSelect
+ .columnQuery(Artist.class, Artist.ARTIST_NAME, Artist.PAINTING_ARRAY.dot(Painting.PAINTING_TITLE))
+ .suppressDistinct()
+ .select(context);
+ assertEquals(22, result.size());
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectTest.java b/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectTest.java
index 188455f..eb09967 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectTest.java
@@ -237,4 +237,22 @@ public class ColumnSelectTest {
assertEquals(properties, q.getColumns());
}
+ @Test
+ public void testDistinct() {
+ ColumnSelect<Artist> q = new ColumnSelect<>();
+
+ assertFalse(q.distinct);
+ assertFalse(q.suppressDistinct);
+
+ q.distinct();
+
+ assertTrue(q.distinct);
+ assertFalse(q.suppressDistinct);
+
+ q.suppressDistinct();
+
+ assertFalse(q.distinct);
+ assertTrue(q.suppressDistinct);
+ }
+
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/cayenne-server/src/test/java/org/apache/cayenne/query/MockQueryMetadata.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/query/MockQueryMetadata.java b/cayenne-server/src/test/java/org/apache/cayenne/query/MockQueryMetadata.java
index 80c18d1..1b7df00 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/query/MockQueryMetadata.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/MockQueryMetadata.java
@@ -120,4 +120,9 @@ public class MockQueryMetadata implements QueryMetadata {
public int getStatementFetchSize() {
return 0;
}
+
+ @Override
+ public boolean isSuppressingDistinct() {
+ return false;
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/32bdcda5/docs/doc/src/main/resources/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/docs/doc/src/main/resources/RELEASE-NOTES.txt b/docs/doc/src/main/resources/RELEASE-NOTES.txt
index 7c88496..d658bae 100644
--- a/docs/doc/src/main/resources/RELEASE-NOTES.txt
+++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt
@@ -22,6 +22,7 @@ CAY-2259 QueryCache: support for referencing type-safe caches
CAY-2269 Add support for date/time components extraction in expression functions
CAY-2270 Update function support in expression parser
CAY-2271 ColumnSelect: support for prefetch and limit
+CAY-2272 ColumnSelect: methods to manually control DISTINCT clause
Bug Fixes: