Skip to content

Commit 099106f

Browse files
committed
Adding distinct to query fix
1 parent d0a760e commit 099106f

File tree

5 files changed

+164
-25
lines changed

5 files changed

+164
-25
lines changed

cayenne-server/src/main/java/org/apache/cayenne/DataRow.java

+50
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919

2020
package org.apache.cayenne;
2121

22+
import java.util.Arrays;
2223
import java.util.HashMap;
2324
import java.util.Map;
25+
import java.util.Objects;
2426
import java.util.concurrent.atomic.AtomicLong;
2527

2628
import org.apache.cayenne.map.DbRelationship;
@@ -149,4 +151,52 @@ public String getEntityName() {
149151
public void setEntityName(String entityName) {
150152
this.entityName = entityName;
151153
}
154+
155+
public int hashCode() {
156+
int h = 0;
157+
for (Entry<String, Object> curr : entrySet()) {
158+
if (curr.getValue() instanceof byte[]) {
159+
h += Objects.hashCode(curr.getKey()) ^ Arrays.hashCode((byte[]) curr.getValue());
160+
} else {
161+
h += curr.hashCode();
162+
}
163+
}
164+
return h;
165+
}
166+
167+
public boolean equals(Object o) {
168+
if (o == this)
169+
return true;
170+
171+
if (!(o instanceof Map))
172+
return false;
173+
Map<?,?> m = (Map<?,?>) o;
174+
if (m.size() != size())
175+
return false;
176+
177+
try {
178+
for (Entry<String, Object> e : entrySet()) {
179+
String key = e.getKey();
180+
Object value = e.getValue();
181+
if (value == null) {
182+
if (!(m.get(key) == null && m.containsKey(key)))
183+
return false;
184+
} else {
185+
if (e.getValue() instanceof byte[] && m.get(key) instanceof byte[]) {
186+
if (!Arrays.equals((byte[]) value, (byte[]) m.get(key))) {
187+
return false;
188+
}
189+
} else {
190+
if (!value.equals(m.get(key)))
191+
return false;
192+
}
193+
}
194+
195+
}
196+
} catch (ClassCastException | NullPointerException unused) {
197+
return false;
198+
}
199+
200+
return true;
201+
}
152202
}

cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/DistinctResultIterator.java

+36-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.util.Map;
3333
import java.util.NoSuchElementException;
3434
import java.util.Set;
35+
import java.util.Arrays;
3536

3637
/**
3738
* A ResultIterator that does in-memory filtering of rows to return only
@@ -144,13 +145,20 @@ private void checkNextUniqueRow() {
144145
while (delegate.hasNextRow()) {
145146
T next = delegate.nextRow();
146147

147-
if (fetchedIds.add(next)) {
148+
if (isUnique(next)) {
148149
this.nextDataRow = next;
149150
break;
150151
}
151152
}
152153
}
153154

155+
private boolean isUnique(T next) {
156+
if(next instanceof Object[]){
157+
return fetchedIds.add(new ObjectArrayWrapper((Object[]) next));
158+
}
159+
return fetchedIds.add(next);
160+
}
161+
154162
private void checkNextRowWithUniqueId() {
155163
nextDataRow = null;
156164
while (delegate.hasNextRow()) {
@@ -165,11 +173,37 @@ private void checkNextRowWithUniqueId() {
165173
id.put(pk.getName(), ((DataRow)next).get(pk.getName()));
166174
}
167175

168-
if (fetchedIds.add(id)) {
176+
if (isUnique((T) id)) {
169177
this.nextDataRow = next;
170178
break;
171179
}
172180
}
173181
}
174182

183+
class ObjectArrayWrapper{
184+
private Object[] objects;
185+
186+
ObjectArrayWrapper(Object[] objects){
187+
this.objects = objects;
188+
}
189+
190+
Object[] getObjects(){
191+
return objects;
192+
}
193+
194+
public int hashCode(){
195+
return Arrays.deepHashCode(objects);
196+
}
197+
198+
public boolean equals(Object o){
199+
if (o == this)
200+
return true;
201+
202+
if (!(o instanceof DistinctResultIterator.ObjectArrayWrapper))
203+
return false;
204+
205+
return Arrays.deepEquals(this.getObjects(),((ObjectArrayWrapper)o).getObjects());
206+
}
207+
}
208+
175209
}

cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ <T> List<ColumnDescriptor> appendOverriddenColumns(List<ColumnDescriptor> column
455455
int type = getJdbcTypeForProperty(property);
456456
ColumnDescriptor descriptor;
457457
if(property.getType() != null) {
458-
descriptor = new ColumnDescriptor(builder.toString(), type, property.getType().getName());
458+
descriptor = new ColumnDescriptor(builder.toString(), type, property.getType().getCanonicalName());
459459
} else {
460460
descriptor = new ColumnDescriptor(builder.toString(), type);
461461
}

cayenne-server/src/test/java/org/apache/cayenne/DataRowTest.java

+52
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import org.junit.Test;
2323

2424
import static org.junit.Assert.assertFalse;
25+
import static org.junit.Assert.assertTrue;
26+
import static org.junit.Assert.assertEquals;
2527

2628
public class DataRowTest {
2729

@@ -35,4 +37,54 @@ public void testVersion() throws Exception {
3537
assertFalse(s3.getVersion() == s1.getVersion());
3638
}
3739

40+
@Test
41+
public void testEquals(){
42+
DataRow d1 = new DataRow(1);
43+
d1.put("FIELD", "test".getBytes());
44+
45+
assertTrue(d1.equals(d1));
46+
47+
DataRow d2 = new DataRow(1);
48+
d2.put("FIELD", "test".getBytes());
49+
50+
assertTrue(d1.equals(d2));
51+
assertTrue(d2.equals(d1));
52+
53+
DataRow d3 = new DataRow(1);
54+
d3.put("FIELD", "test".getBytes());
55+
56+
assertTrue(d2.equals(d3));
57+
assertTrue(d1.equals(d3));
58+
59+
assertFalse(d1.equals(null));
60+
61+
DataRow d4 = new DataRow(1);
62+
d4.put("FIELD1", "test".getBytes());
63+
64+
for(int i = 0; i < 5; i++) {
65+
assertFalse(d3.equals(d4));
66+
}
67+
68+
DataRow d5 = new DataRow(1);
69+
d5.put("FIELD", "test1".getBytes());
70+
71+
DataRow d6 = new DataRow(1);
72+
d6.put("FIELD", "test".getBytes());
73+
74+
assertFalse(d5.equals(d6));
75+
}
76+
77+
@Test
78+
public void testHashCode(){
79+
DataRow d1 = new DataRow(1);
80+
d1.put("FIELD", "test".getBytes());
81+
82+
assertEquals(d1.hashCode(), d1.hashCode());
83+
84+
DataRow d2 = new DataRow(1);
85+
d2.put("FIELD", "test".getBytes());
86+
87+
assertTrue(d1.equals(d2));
88+
assertEquals(d1.hashCode(), d2.hashCode());
89+
}
3890
}

cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SelectActionIT.java

+25-22
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@
2525
import org.apache.cayenne.di.Inject;
2626
import org.apache.cayenne.exp.Expression;
2727
import org.apache.cayenne.exp.ExpressionFactory;
28+
import org.apache.cayenne.query.CapsStrategy;
2829
import org.apache.cayenne.query.ObjectSelect;
2930
import org.apache.cayenne.query.SQLTemplate;
3031
import org.apache.cayenne.query.SelectQuery;
32+
import org.apache.cayenne.query.EJBQLQuery;
3133
import org.apache.cayenne.test.jdbc.DBHelper;
3234
import org.apache.cayenne.test.jdbc.TableHelper;
3335
import org.apache.cayenne.testdo.lob.ClobTestEntity;
@@ -96,28 +98,6 @@ public void testColumnSelect_DistinctResultIterator() throws Exception {
9698
@Test
9799
public void testAddingDistinctToQuery() throws Exception{
98100
if (accessStackAdapter.supportsLobs()){
99-
// DistEntity obj = context.newObject(DistEntity.class);
100-
// obj.setName("ABC");
101-
// obj.setField("test".getBytes());
102-
// DistEntity obj2 = context.newObject(DistEntity.class);
103-
// obj2.setName("ABC1");
104-
// obj2.setField("test".getBytes());
105-
//
106-
// DistEntityRel objRel1 = context.newObject(DistEntityRel.class);
107-
// objRel1.setNum(5);
108-
// DistEntityRel objRel2 = context.newObject(DistEntityRel.class);
109-
// objRel2.setNum(6);
110-
// DistEntityRel objRel3 = context.newObject(DistEntityRel.class);
111-
// objRel3.setNum(7);
112-
// DistEntityRel objRel4 = context.newObject(DistEntityRel.class);
113-
// objRel4.setNum(5);
114-
//
115-
// obj.addToDistRel(objRel1);
116-
// obj.addToDistRel(objRel2);
117-
// obj.addToDistRel(objRel3);
118-
// obj2.addToDistRel(objRel4);
119-
120-
// context.commitChanges();
121101

122102
TableHelper tDistEntity = new TableHelper(dbHelper, "DIST_ENTITY");
123103
tDistEntity.setColumns("ID", "NAME", "FIELD");
@@ -141,7 +121,9 @@ public void testAddingDistinctToQuery() throws Exception{
141121
ObjectContext objectContext = serverRuntime.newContext();
142122

143123
SQLTemplate select = new SQLTemplate(DistEntity.class, "SELECT t0.FIELD, t0.NAME, t0.ID FROM DIST_ENTITY t0 JOIN DIST_ENTITY_REL t1 ON (t0.ID = t1.DIST_ID) WHERE (t1.NUM > 0) AND (t0.NAME LIKE 'dist_entity1')");
124+
select.setColumnNamesCapitalization(CapsStrategy.UPPER);
144125
List<DistEntity> list1 = objectContext.performQuery(select);
126+
145127
assertEquals(4, list1.size());
146128

147129
List<DistEntity> list2 = ObjectSelect.query(DistEntity.class)
@@ -150,6 +132,27 @@ public void testAddingDistinctToQuery() throws Exception{
150132
.select(objectContext);
151133

152134
assertEquals(1,list2.size());
135+
136+
EJBQLQuery query1 = new EJBQLQuery("select d FROM DistEntity d JOIN d.distRel r where d.name='dist_entity1' and r.num>0");
137+
List<DistEntity> list3 = context.performQuery(query1);
138+
139+
assertEquals(4,list3.size());
140+
141+
List<String> list4 = ObjectSelect
142+
.columnQuery(DistEntity.class, DistEntity.NAME)
143+
.where(DistEntity.DIST_REL.dot(DistEntityRel.NUM).gt(0))
144+
.and(DistEntity.NAME.eq("dist_entity1"))
145+
.select(context);
146+
147+
assertEquals(1,list4.size());
148+
149+
List<Object[]> list5 = ObjectSelect
150+
.columnQuery(DistEntity.class, DistEntity.NAME, DistEntity.FIELD)
151+
.where(DistEntity.DIST_REL.dot(DistEntityRel.NUM).gt(0))
152+
.and(DistEntity.NAME.eq("dist_entity1"))
153+
.select(context);
154+
155+
assertEquals(1,list5.size());
153156
}
154157
}
155158

0 commit comments

Comments
 (0)