You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by ab...@apache.org on 2019/06/11 12:31:01 UTC
[cayenne] branch STABLE-4.1 updated: CAY-2553 Wrong disjoint
prefetch query qualifier
This is an automated email from the ASF dual-hosted git repository.
abulatski pushed a commit to branch STABLE-4.1
in repository https://gitbox.apache.org/repos/asf/cayenne.git
The following commit(s) were added to refs/heads/STABLE-4.1 by this push:
new d3940e9 CAY-2553 Wrong disjoint prefetch query qualifier
d3940e9 is described below
commit d3940e9df874507dccf8f9862a505e0337e934a6
Author: Arseni Bulatski <an...@gmail.com>
AuthorDate: Tue Jun 11 15:30:05 2019 +0300
CAY-2553 Wrong disjoint prefetch query qualifier
---
RELEASE-NOTES.txt | 1 +
.../main/java/org/apache/cayenne/map/DbEntity.java | 130 +++--------------
.../apache/cayenne/exp/TranslateExpressionIT.java | 159 +++++++++++++++++++++
.../java/org/apache/cayenne/map/DbEntityIT.java | 8 +-
4 files changed, 181 insertions(+), 117 deletions(-)
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 144aa21..2f397d4 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -14,6 +14,7 @@ Date:
Bug Fixes:
+CAY-2553 Wrong disjoint prefetch query qualifier
CAY-2573 DI field injection is triggered when creating sql Driver
CAY-2582 Double insert of manyToMany relationship mapped to Set
CAY-2584 Crypto: can't use ColumnSelect with encrypted columns
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java b/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java
index 0626655..c341aa6 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java
@@ -19,6 +19,16 @@
package org.apache.cayenne.map;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.function.Function;
+
import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.ObjectId;
import org.apache.cayenne.configuration.ConfigurationNode;
@@ -37,18 +47,6 @@ import org.apache.cayenne.util.CayenneMapEntry;
import org.apache.cayenne.util.Util;
import org.apache.cayenne.util.XMLEncoder;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.function.Function;
-
/**
* A DbEntity is a mapping descriptor that defines a structure of a database
* table.
@@ -676,113 +674,17 @@ public class DbEntity extends Entity implements ConfigurationNode, DbEntityListe
String translatePath(String path) {
- // algorithm to determine the translated path:
- // 0. If relationship has at least one to-many component, travel all
- // the way
- // back, and then all the way forward
- // 1. If relationship path equals to input, travel one step back,
- // and then one
- // step forward.
- // 2. If input completely includes relationship path, use input's
- // remaining
- // tail.
- // 3. If relationship path and input have none or some leading
- // components in
- // common,
- // (a) strip common leading part;
- // (b) reverse the remaining relationship part;
- // (c) append remaining input to the reversed remaining
- // relationship.
-
- // case (0)
- if (toMany) {
- PathComponentIterator pathIt = createPathIterator(path);
- Iterator<CayenneMapEntry> relationshipIt = resolvePathComponents(relationshipPath);
-
- // for inserts from the both ends use LinkedList
- LinkedList<String> finalPath = new LinkedList<>();
-
- // append remainder of the relationship, reversing it
- while (relationshipIt.hasNext()) {
- DbRelationship nextDBR = (DbRelationship) relationshipIt.next();
- prependReversedPath(finalPath, nextDBR);
- }
-
- while (pathIt.hasNext()) {
- // components may be attributes or relationships
- PathComponent<Attribute, Relationship> component = pathIt.next();
- appendPath(finalPath, component);
- }
-
- return Util.join(finalPath, Entity.PATH_SEPARATOR);
- }
- // case (1)
- if (path.equals(relationshipPath)) {
-
- LinkedList<String> finalPath = new LinkedList<>();
- PathComponentIterator pathIt = createPathIterator(path);
-
- // just do one step back and one step forward to create correct
- // joins...
- // find last rel...
- DbRelationship lastDBR = null;
-
- while (pathIt.hasNext()) {
- // relationship path components must be DbRelationships
- lastDBR = (DbRelationship) pathIt.next().getRelationship();
- }
-
- if (lastDBR != null) {
- prependReversedPath(finalPath, lastDBR);
- appendPath(finalPath, lastDBR);
- }
-
- return Util.join(finalPath, Entity.PATH_SEPARATOR);
- }
-
- // case (2)
- String relationshipPathWithDot = relationshipPath + Entity.PATH_SEPARATOR;
- if (path.startsWith(relationshipPathWithDot)) {
- return path.substring(relationshipPathWithDot.length());
- }
-
- // case (3)
- PathComponentIterator pathIt = createPathIterator(path);
- Iterator<CayenneMapEntry> relationshipIt = resolvePathComponents(relationshipPath);
-
- // for inserts from the both ends use LinkedList
LinkedList<String> finalPath = new LinkedList<>();
- while (relationshipIt.hasNext() && pathIt.hasNext()) {
+ PathComponentIterator pathIt = createPathIterator(relationshipPath);
+ while (pathIt.hasNext()) {
// relationship path components must be DbRelationships
- DbRelationship nextDBR = (DbRelationship) relationshipIt.next();
-
- // expression components may be attributes or relationships
- PathComponent<Attribute, Relationship> component = pathIt.next();
-
- if (nextDBR != component.getRelationship()) {
- // found split point
- // consume the last iteration components,
- // then break out to finish the iterators independently
- prependReversedPath(finalPath, nextDBR);
- appendPath(finalPath, component);
- break;
+ DbRelationship lastDBR = (DbRelationship) pathIt.next().getRelationship();
+ if(lastDBR != null) {
+ prependReversedPath(finalPath, lastDBR);
}
-
- break;
- }
-
- // append remainder of the relationship, reversing it
- while (relationshipIt.hasNext()) {
- DbRelationship nextDBR = (DbRelationship) relationshipIt.next();
- prependReversedPath(finalPath, nextDBR);
- }
-
- while (pathIt.hasNext()) {
- // components may be attributes or relationships
- PathComponent<Attribute, Relationship> component = pathIt.next();
- appendPath(finalPath, component);
}
+ finalPath.add(path);
return Util.join(finalPath, Entity.PATH_SEPARATOR);
}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/TranslateExpressionIT.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/TranslateExpressionIT.java
new file mode 100644
index 0000000..41bb991
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/TranslateExpressionIT.java
@@ -0,0 +1,159 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.exp;
+
+import java.util.List;
+
+import org.apache.cayenne.access.DataContext;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.query.ObjectSelect;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.testmap.Artist;
+import org.apache.cayenne.testdo.testmap.Gallery;
+import org.apache.cayenne.testdo.testmap.Painting;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class TranslateExpressionIT extends ServerCase {
+
+ @Inject
+ private DataContext context;
+
+ @Inject
+ private DBHelper dbHelper;
+
+ @Before
+ public void createArtistsDataSet() throws Exception {
+ TableHelper tArtist = new TableHelper(dbHelper, "ARTIST");
+ tArtist.setColumns("ARTIST_ID", "ARTIST_NAME", "DATE_OF_BIRTH");
+
+ long dateBase = System.currentTimeMillis();
+ for (int i = 1; i <= 20; i++) {
+ tArtist.insert(i, "artist" + i, new java.sql.Date(dateBase + 10000 * i));
+ }
+
+ TableHelper tGallery = new TableHelper(dbHelper, "GALLERY");
+ tGallery.setColumns("GALLERY_ID", "GALLERY_NAME");
+ tGallery.insert(1, "tate modern");
+
+ TableHelper tPaintings = new TableHelper(dbHelper, "PAINTING");
+ tPaintings.setColumns("PAINTING_ID", "PAINTING_TITLE", "ARTIST_ID", "GALLERY_ID");
+ for (int i = 1; i <= 20; i++) {
+ tPaintings.insert(i, "painting" + i, i % 5 + 1, 1);
+ }
+ }
+
+ @Test
+ public void testPrefetchWithTranslatedExp() {
+ List<Painting> result = ObjectSelect.query(Painting.class)
+ .where(Painting.TO_ARTIST
+ .dot(Artist.PAINTING_ARRAY)
+ .dot(Painting.PAINTING_TITLE).like("painting7"))
+ .and(Painting.PAINTING_TITLE.like("painting2"))
+ .prefetch(Painting.TO_ARTIST.disjoint())
+ .select(context);
+ assertEquals(1, result.size());
+ assertEquals("artist3", result.get(0).getToArtist().getArtistName());
+ }
+
+ @Test
+ public void testPrefetchWithTheSamePrefetchAndQualifier() {
+ List<Painting> result = ObjectSelect.query(Painting.class)
+ .where(Painting.TO_GALLERY
+ .dot(Gallery.PAINTING_ARRAY)
+ .dot(Painting.PAINTING_TITLE)
+ .eq("painting1"))
+ .and(Painting.PAINTING_TITLE.like("painting2"))
+ .prefetch(Painting.TO_GALLERY.disjoint())
+ .prefetch(Painting.TO_GALLERY.dot(Gallery.PAINTING_ARRAY).disjoint())
+ .select(context);
+ assertEquals(1, result.size());
+ assertEquals("painting2", result.get(0).getPaintingTitle());
+ }
+
+ @Test
+ public void testTranslateExpression() {
+ ObjEntity entity = context.getEntityResolver().getObjEntity("Painting");
+ Expression expression = ExpressionFactory.pathExp("toArtist.paintingArray");
+ Expression translatedExpression = entity
+ .translateToRelatedEntity(expression, "toArtist");
+ assertEquals(ExpressionFactory
+ .dbPathExp("paintingArray.toArtist.paintingArray"),
+ translatedExpression);
+ }
+
+ @Test
+ public void testRelationshipPathEqualsToInput() {
+ ObjEntity entity = context.getEntityResolver().getObjEntity("Painting");
+ Expression expression = ExpressionFactory.pathExp("toArtist");
+ Expression translatedExpression = entity
+ .translateToRelatedEntity(expression, "toArtist");
+ assertEquals(ExpressionFactory.dbPathExp("paintingArray.toArtist"),
+ translatedExpression);
+ }
+
+ @Test
+ public void testRelationshipNoneLeadingParts() {
+ ObjEntity entity = context.getEntityResolver().getObjEntity("Painting");
+ Expression expression = ExpressionFactory.pathExp("toGallery");
+ Expression translatedExpression = entity
+ .translateToRelatedEntity(expression, "toArtist");
+ assertEquals(ExpressionFactory.dbPathExp("paintingArray.toGallery"),
+ translatedExpression);
+ }
+
+ @Test
+ public void testRelationshipSomeLeadingParts() {
+ ObjEntity entity = context.getEntityResolver().getObjEntity("Painting");
+ Expression expression = ExpressionFactory.pathExp("toGallery");
+ Expression translatedExpression = entity
+ .translateToRelatedEntity(expression, "toArtist.paintingArray.toGallery");
+ assertEquals(ExpressionFactory.dbPathExp("paintingArray.toArtist.paintingArray.toGallery"),
+ translatedExpression);
+ }
+
+ @Test
+ public void testCompQualifier() {
+ ObjEntity entity = context.getEntityResolver().getObjEntity("Painting");
+ Expression expression = ExpressionFactory.pathExp("toArtist.artistExhibitArray.toExhibit");
+ Expression translatedExpression = entity
+ .translateToRelatedEntity(expression, "toGallery");
+ assertEquals(ExpressionFactory.dbPathExp("paintingArray.toArtist.artistExhibitArray.toExhibit"),
+ translatedExpression);
+ }
+
+ @Test
+ public void testCompQualifierAndPref() {
+ ObjEntity entity = context.getEntityResolver().getObjEntity("Artist");
+ Expression expression = ExpressionFactory.pathExp("paintingArray.toGallery");
+ Expression translatedExpression = entity
+ .translateToRelatedEntity(expression, "artistExhibitArray.toExhibit");
+ assertEquals(ExpressionFactory.dbPathExp("artistExhibitArray.toArtist.paintingArray.toGallery"),
+ translatedExpression);
+ }
+}
\ No newline at end of file
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/map/DbEntityIT.java b/cayenne-server/src/test/java/org/apache/cayenne/map/DbEntityIT.java
index c0a886f..5afd955 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/map/DbEntityIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/map/DbEntityIT.java
@@ -19,6 +19,8 @@
package org.apache.cayenne.map;
+import java.util.Collection;
+
import org.apache.cayenne.configuration.server.ServerRuntime;
import org.apache.cayenne.di.Inject;
import org.apache.cayenne.exp.Expression;
@@ -29,8 +31,6 @@ import org.apache.cayenne.unit.di.server.UseServerRuntime;
import org.apache.cayenne.util.Util;
import org.junit.Test;
-import java.util.Collection;
-
import static org.junit.Assert.*;
@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
@@ -270,6 +270,8 @@ public class DbEntityIT extends ServerCase {
Expression e1 = ExpressionFactory.exp("db:toArtist.ARTIST_NAME = 'aa'");
Expression translated = paintingE.translateToRelatedEntity(e1, "toArtist");
- assertEquals("failure: " + translated, ExpressionFactory.exp("db:ARTIST_NAME = 'aa'"), translated);
+ assertEquals("failure: " + translated,
+ ExpressionFactory.exp("db:paintingArray.toArtist.ARTIST_NAME = 'aa'"),
+ translated);
}
}