Skip to content

Commit d90c467

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

File tree

5 files changed

+161
-39
lines changed

5 files changed

+161
-39
lines changed

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

+49-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919

2020
package org.apache.cayenne;
2121

22-
import java.util.HashMap;
23-
import java.util.Map;
22+
import java.util.*;
2423
import java.util.concurrent.atomic.AtomicLong;
2524

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

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

+36-10
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,7 @@
2424
import org.apache.cayenne.map.DbEntity;
2525
import org.apache.cayenne.util.ResultIteratorIterator;
2626

27-
import java.util.ArrayList;
28-
import java.util.HashMap;
29-
import java.util.HashSet;
30-
import java.util.Iterator;
31-
import java.util.List;
32-
import java.util.Map;
33-
import java.util.NoSuchElementException;
34-
import java.util.Set;
27+
import java.util.*;
3528

3629
/**
3730
* A ResultIterator that does in-memory filtering of rows to return only
@@ -144,13 +137,20 @@ private void checkNextUniqueRow() {
144137
while (delegate.hasNextRow()) {
145138
T next = delegate.nextRow();
146139

147-
if (fetchedIds.add(next)) {
140+
if (isUnique(next)) {
148141
this.nextDataRow = next;
149142
break;
150143
}
151144
}
152145
}
153146

147+
private boolean isUnique(T next) {
148+
if(next instanceof Object[]){
149+
return fetchedIds.add(new ObjectArrayWrapper((Object[]) next));
150+
}
151+
return fetchedIds.add(next);
152+
}
153+
154154
private void checkNextRowWithUniqueId() {
155155
nextDataRow = null;
156156
while (delegate.hasNextRow()) {
@@ -165,11 +165,37 @@ private void checkNextRowWithUniqueId() {
165165
id.put(pk.getName(), ((DataRow)next).get(pk.getName()));
166166
}
167167

168-
if (fetchedIds.add(id)) {
168+
if (isUnique((T) id)) {
169169
this.nextDataRow = next;
170170
break;
171171
}
172172
}
173173
}
174174

175+
class ObjectArrayWrapper{
176+
private Object[] objects;
177+
178+
ObjectArrayWrapper(Object[] objects){
179+
this.objects = objects;
180+
}
181+
182+
Object[] getObjects(){
183+
return objects;
184+
}
185+
186+
public int hashCode(){
187+
return Arrays.deepHashCode(objects);
188+
}
189+
190+
public boolean equals(Object o){
191+
if (o == this)
192+
return true;
193+
194+
if (!(o instanceof DistinctResultIterator.ObjectArrayWrapper))
195+
return false;
196+
197+
return Arrays.deepEquals(this.getObjects(),((ObjectArrayWrapper)o).getObjects());
198+
}
199+
}
200+
175201
}

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

+51-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
import org.junit.Test;
2323

24-
import static org.junit.Assert.assertFalse;
24+
import static org.junit.Assert.*;
2525

2626
public class DataRowTest {
2727

@@ -35,4 +35,54 @@ public void testVersion() throws Exception {
3535
assertFalse(s3.getVersion() == s1.getVersion());
3636
}
3737

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

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

+24-25
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@
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.ObjectSelect;
29-
import org.apache.cayenne.query.SQLTemplate;
30-
import org.apache.cayenne.query.SelectQuery;
28+
import org.apache.cayenne.query.*;
3129
import org.apache.cayenne.test.jdbc.DBHelper;
3230
import org.apache.cayenne.test.jdbc.TableHelper;
3331
import org.apache.cayenne.testdo.lob.ClobTestEntity;
@@ -96,28 +94,6 @@ public void testColumnSelect_DistinctResultIterator() throws Exception {
9694
@Test
9795
public void testAddingDistinctToQuery() throws Exception{
9896
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();
12197

12298
TableHelper tDistEntity = new TableHelper(dbHelper, "DIST_ENTITY");
12399
tDistEntity.setColumns("ID", "NAME", "FIELD");
@@ -141,7 +117,9 @@ public void testAddingDistinctToQuery() throws Exception{
141117
ObjectContext objectContext = serverRuntime.newContext();
142118

143119
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')");
120+
select.setColumnNamesCapitalization(CapsStrategy.UPPER);
144121
List<DistEntity> list1 = objectContext.performQuery(select);
122+
145123
assertEquals(4, list1.size());
146124

147125
List<DistEntity> list2 = ObjectSelect.query(DistEntity.class)
@@ -150,6 +128,27 @@ public void testAddingDistinctToQuery() throws Exception{
150128
.select(objectContext);
151129

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

0 commit comments

Comments
 (0)