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 2022/11/24 14:25:49 UTC

[cayenne] branch master updated: Fix split expressions for db relationships

This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git


The following commit(s) were added to refs/heads/master by this push:
     new 69d754c24 Fix split expressions for db relationships
     new 598eb371e Merge pull request #540 from m-dzianishchyts/CAY-2764
69d754c24 is described below

commit 69d754c24be25506fcf8f0ccb64d179cecf5e005
Author: Mikhail Dzianishchyts <mi...@gmail.com>
AuthorDate: Mon Nov 21 02:58:17 2022 +0300

    Fix split expressions for db relationships
---
 .../access/translator/select/DbPathProcessor.java  |   1 +
 .../org/apache/cayenne/exp/ExpressionFactory.java  |  13 +-
 .../apache/cayenne/exp/ExpressionFactoryIT.java    | 308 ++++++++++++---------
 3 files changed, 186 insertions(+), 136 deletions(-)

diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DbPathProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DbPathProcessor.java
index 48fdcee2c..c1336b5ff 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DbPathProcessor.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DbPathProcessor.java
@@ -70,6 +70,7 @@ class DbPathProcessor extends PathProcessor<DbEntity> {
             throw new IllegalStateException("Non-relationship aliased path part: " + alias);
         }
 
+        entity = relationship.getTargetEntity();
         processRelationship(relationship);
     }
 
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java
index 8f50603f7..b17775411 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java
@@ -79,6 +79,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 
 /**
  * Helper class to build expressions.
@@ -330,6 +331,14 @@ public class ExpressionFactory {
 			return new ASTTrue();
 		}
 
+		Function<Object, ASTPath> pathProvider;
+		if (path.startsWith(ASTDbPath.DB_PREFIX)) {
+			pathProvider = ASTDbPath::new;
+			path = path.substring(ASTDbPath.DB_PREFIX.length());
+		} else {
+			pathProvider = ASTObjPath::new;
+		}
+
 		int split = path.indexOf(SPLIT_SEPARATOR);
 
 		List<Expression> matches = new ArrayList<>(values.length);
@@ -355,13 +364,13 @@ public class ExpressionFactory {
 				String aliasedPath = beforeSplit + alias + afterSplit;
 				i++;
 
-				ASTPath pathExp = new ASTObjPath(aliasedPath);
+				ASTPath pathExp = pathProvider.apply(aliasedPath);
 				pathExp.setPathAliases(Collections.singletonMap(alias, splitChunk));
 				matches.add(new ASTEqual(pathExp, value));
 			}
 		} else {
 			for (Object value : values) {
-				matches.add(new ASTEqual(new ASTObjPath(path), value));
+				matches.add(new ASTEqual(pathProvider.apply(path), value));
 			}
 		}
 
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryIT.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryIT.java
index c22b71d46..22408c316 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryIT.java
@@ -19,21 +19,11 @@
 
 package org.apache.cayenne.exp;
 
-import static org.apache.cayenne.exp.ExpressionFactory.exp;
-import static org.apache.cayenne.exp.ExpressionFactory.greaterExp;
-import static org.apache.cayenne.exp.FunctionExpressionFactory.lengthExp;
-import static org.apache.cayenne.exp.FunctionExpressionFactory.substringExp;
-import static org.apache.cayenne.exp.FunctionExpressionFactory.trimExp;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import java.util.List;
-
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.query.ObjectSelect;
 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.UnitDbAdapter;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
@@ -41,130 +31,180 @@ import org.apache.cayenne.unit.di.server.ServerCase;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
 import org.junit.Test;
 
+import java.util.List;
+
+import static org.apache.cayenne.exp.ExpressionFactory.exp;
+import static org.apache.cayenne.exp.ExpressionFactory.greaterExp;
+import static org.apache.cayenne.exp.FunctionExpressionFactory.lengthExp;
+import static org.apache.cayenne.exp.FunctionExpressionFactory.substringExp;
+import static org.apache.cayenne.exp.FunctionExpressionFactory.trimExp;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 @UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
 public class ExpressionFactoryIT extends ServerCase {
 
-	@Inject
-	private ObjectContext context;
-
-	@Inject
-	private UnitDbAdapter accessStackAdapter;
-
-	// CAY-416
-	@Test
-	public void testCollectionMatch() {
-		Artist artist = context.newObject(Artist.class);
-		artist.setArtistName("artist");
-		Painting p1 = context.newObject(Painting.class),
-				p2 = context.newObject(Painting.class),
-				p3 = context.newObject(Painting.class);
-		p1.setPaintingTitle("p1");
-		p2.setPaintingTitle("p2");
-		p3.setPaintingTitle("p3");
-		artist.addToPaintingArray(p1);
-		artist.addToPaintingArray(p2);
-
-		context.commitChanges();
-
-		assertTrue(ExpressionFactory.matchExp("paintingArray", p1).match(artist));
-		assertFalse(ExpressionFactory.matchExp("paintingArray", p3).match(artist));
-		assertTrue(ExpressionFactory.noMatchExp("paintingArray", p1).match(artist)); // changed to align with SQL
-		assertTrue(ExpressionFactory.noMatchExp("paintingArray", p3).match(artist));
-
-		assertTrue(ExpressionFactory.matchExp("paintingArray.paintingTitle", "p1").match(artist));
-		assertFalse(ExpressionFactory.matchExp("paintingArray.paintingTitle", "p3").match(artist));
-		assertTrue(ExpressionFactory.noMatchExp("paintingArray.paintingTitle", "p1").match(artist)); // changed to align with SQL
-		assertTrue(ExpressionFactory.noMatchExp("paintingArray.paintingTitle", "p3").match(artist));
-
-		assertTrue(ExpressionFactory.inExp("paintingTitle", "p1").match(p1));
-		assertFalse(ExpressionFactory.notInExp("paintingTitle", "p3").match(p3));
-	}
-
-	@Test
-	public void testIn() {
-		Artist a1 = context.newObject(Artist.class);
-		a1.setArtistName("a1");
-		Painting p1 = context.newObject(Painting.class);
-		p1.setPaintingTitle("p1");
-		Painting p2 = context.newObject(Painting.class);
-		p2.setPaintingTitle("p2");
-		a1.addToPaintingArray(p1);
-		a1.addToPaintingArray(p2);
-
-		Expression in = ExpressionFactory.inExp("paintingArray", p1);
-		assertTrue(in.match(a1));
-	}
-
-	@Test
-	public void testEscapeCharacter() {
-		if(!accessStackAdapter.supportsEscapeInLike()) {
-			return;
-		}
-
-		Artist a1 = context.newObject(Artist.class);
-		a1.setArtistName("A_1");
-		Artist a2 = context.newObject(Artist.class);
-		a2.setArtistName("A_2");
-		context.commitChanges();
-
-		Expression ex1 = ExpressionFactory.likeIgnoreCaseDbExp("ARTIST_NAME", "A*_1", '*');
-		List<Artist> artists = ObjectSelect.query(Artist.class, ex1).select(context);
-		assertEquals(1, artists.size());
-
-		Expression ex2 = ExpressionFactory.likeExp("artistName", "A*_2", '*');
-		artists = ObjectSelect.query(Artist.class, ex2).select(context);
-		assertEquals(1, artists.size());
-	}
-	
-	@Test
-	public void testContains_Escape() {
-
-		if(!accessStackAdapter.supportsEscapeInLike()) {
-			return;
-		}
-
-		Artist a1 = context.newObject(Artist.class);
-		a1.setArtistName("MA_1X");
-		Artist a2 = context.newObject(Artist.class);
-		a2.setArtistName("CA%2Y");
-		context.commitChanges();
-
-		Expression ex1 = ExpressionFactory.containsExp(Artist.ARTIST_NAME.getName(), "A_1");
-		List<Artist> artists = ObjectSelect.query(Artist.class, ex1).select(context);
-		assertEquals(1, artists.size());
-
-		Expression ex2 = ExpressionFactory.containsExp(Artist.ARTIST_NAME.getName(), "A%2");
-		artists = ObjectSelect.query(Artist.class, ex2).select(context);
-		assertEquals(1, artists.size());
-	}
-
-	@Test
-	public void testDifferentExpressionAPI() {
-		List<Artist> res;
-
-		// First version via expression string
-		Expression exp1 = exp(
-				"length(substring(artistName, 1, 3)) > length(trim(artistName))"
-		);
-		res = ObjectSelect.query(Artist.class, exp1).select(context);
-		assertEquals(0, res.size());
-
-		// Second version via FunctionExpressionFactory API
-		Expression exp2 = greaterExp(
-				lengthExp(substringExp(Artist.ARTIST_NAME.getExpression(), 1, 3)),
-				lengthExp(trimExp(Artist.ARTIST_NAME.getExpression()))
-		);
-		res = ObjectSelect.query(Artist.class, exp2).select(context);
-		assertEquals(0, res.size());
-
-		// Third version via Property API
-		Expression exp3 = Artist.ARTIST_NAME.substring(1, 3).length()
-				.gt(Artist.ARTIST_NAME.trim().length());
-		res = ObjectSelect.query(Artist.class, exp3).select(context);
-		assertEquals(0, res.size());
-
-		// Check that all expressions are equal
-		assertEquals(exp1, exp2);
-		assertEquals(exp3, exp3);
-	}
+    @Inject
+    private ObjectContext context;
+
+    @Inject
+    private UnitDbAdapter accessStackAdapter;
+
+    // CAY-416
+    @Test
+    public void testCollectionMatch() {
+        Artist artist = context.newObject(Artist.class);
+        artist.setArtistName("artist");
+        Painting p1 = context.newObject(Painting.class),
+                p2 = context.newObject(Painting.class),
+                p3 = context.newObject(Painting.class);
+        p1.setPaintingTitle("p1");
+        p2.setPaintingTitle("p2");
+        p3.setPaintingTitle("p3");
+        artist.addToPaintingArray(p1);
+        artist.addToPaintingArray(p2);
+
+        context.commitChanges();
+
+        assertTrue(ExpressionFactory.matchExp("paintingArray", p1).match(artist));
+        assertFalse(ExpressionFactory.matchExp("paintingArray", p3).match(artist));
+        assertTrue(ExpressionFactory.noMatchExp("paintingArray", p1).match(artist)); // changed to align with SQL
+        assertTrue(ExpressionFactory.noMatchExp("paintingArray", p3).match(artist));
+
+        assertTrue(ExpressionFactory.matchExp("paintingArray.paintingTitle", "p1").match(artist));
+        assertFalse(ExpressionFactory.matchExp("paintingArray.paintingTitle", "p3").match(artist));
+        assertTrue(ExpressionFactory.noMatchExp("paintingArray.paintingTitle", "p1")
+                           .match(artist)); // changed to align with SQL
+        assertTrue(ExpressionFactory.noMatchExp("paintingArray.paintingTitle", "p3").match(artist));
+
+        assertTrue(ExpressionFactory.inExp("paintingTitle", "p1").match(p1));
+        assertFalse(ExpressionFactory.notInExp("paintingTitle", "p3").match(p3));
+    }
+
+    @Test
+    public void testIn() {
+        Artist a1 = context.newObject(Artist.class);
+        a1.setArtistName("a1");
+        Painting p1 = context.newObject(Painting.class);
+        p1.setPaintingTitle("p1");
+        Painting p2 = context.newObject(Painting.class);
+        p2.setPaintingTitle("p2");
+        a1.addToPaintingArray(p1);
+        a1.addToPaintingArray(p2);
+
+        Expression in = ExpressionFactory.inExp("paintingArray", p1);
+        assertTrue(in.match(a1));
+    }
+
+    @Test
+    public void testEscapeCharacter() {
+        if (!accessStackAdapter.supportsEscapeInLike()) {
+            return;
+        }
+
+        Artist a1 = context.newObject(Artist.class);
+        a1.setArtistName("A_1");
+        Artist a2 = context.newObject(Artist.class);
+        a2.setArtistName("A_2");
+        context.commitChanges();
+
+        Expression ex1 = ExpressionFactory.likeIgnoreCaseDbExp("ARTIST_NAME", "A*_1", '*');
+        List<Artist> artists = ObjectSelect.query(Artist.class, ex1).select(context);
+        assertEquals(1, artists.size());
+
+        Expression ex2 = ExpressionFactory.likeExp("artistName", "A*_2", '*');
+        artists = ObjectSelect.query(Artist.class, ex2).select(context);
+        assertEquals(1, artists.size());
+    }
+
+    @Test
+    public void testContains_Escape() {
+
+        if (!accessStackAdapter.supportsEscapeInLike()) {
+            return;
+        }
+
+        Artist a1 = context.newObject(Artist.class);
+        a1.setArtistName("MA_1X");
+        Artist a2 = context.newObject(Artist.class);
+        a2.setArtistName("CA%2Y");
+        context.commitChanges();
+
+        Expression ex1 = ExpressionFactory.containsExp(Artist.ARTIST_NAME.getName(), "A_1");
+        List<Artist> artists = ObjectSelect.query(Artist.class, ex1).select(context);
+        assertEquals(1, artists.size());
+
+        Expression ex2 = ExpressionFactory.containsExp(Artist.ARTIST_NAME.getName(), "A%2");
+        artists = ObjectSelect.query(Artist.class, ex2).select(context);
+        assertEquals(1, artists.size());
+    }
+
+    @Test
+    public void testSplitExpressions() {
+        Artist artist1 = context.newObject(Artist.class),
+                artist2 = context.newObject(Artist.class);
+        artist1.setArtistName("a1");
+        artist2.setArtistName("a2");
+
+        Painting p1 = context.newObject(Painting.class),
+                p2 = context.newObject(Painting.class),
+                p3 = context.newObject(Painting.class);
+        p1.setPaintingTitle("p1");
+        p2.setPaintingTitle("p2");
+        p3.setPaintingTitle("p3");
+
+        Gallery g1 = context.newObject(Gallery.class),
+                g2 = context.newObject(Gallery.class);
+        g1.setGalleryName("g1");
+        g2.setGalleryName("g2");
+
+        artist1.addToPaintingArray(p1);
+        artist1.addToPaintingArray(p2);
+        artist2.addToPaintingArray(p3);
+
+        g1.addToPaintingArray(p1);
+        g1.addToPaintingArray(p3);
+        g2.addToPaintingArray(p2);
+
+        context.commitChanges();
+
+        List<Artist> objArtists = ObjectSelect.query(Artist.class)
+                .where(ExpressionFactory.matchAllExp("|paintingArray.toGallery.galleryName", "g1", "g2"))
+                .select(context);
+        List<Artist> dbArtists = ObjectSelect.query(Artist.class)
+                .where(ExpressionFactory.matchAllExp("db:|paintingArray.toGallery.GALLERY_NAME", "g1", "g2"))
+                .select(context);
+        assertEquals(objArtists, dbArtists);
+    }
+
+    @Test
+    public void testDifferentExpressionAPI() {
+        List<Artist> res;
+
+        // First version via expression string
+        Expression exp1 = exp(
+                "length(substring(artistName, 1, 3)) > length(trim(artistName))"
+        );
+        res = ObjectSelect.query(Artist.class, exp1).select(context);
+        assertEquals(0, res.size());
+
+        // Second version via FunctionExpressionFactory API
+        Expression exp2 = greaterExp(
+                lengthExp(substringExp(Artist.ARTIST_NAME.getExpression(), 1, 3)),
+                lengthExp(trimExp(Artist.ARTIST_NAME.getExpression()))
+        );
+        res = ObjectSelect.query(Artist.class, exp2).select(context);
+        assertEquals(0, res.size());
+
+        // Third version via Property API
+        Expression exp3 = Artist.ARTIST_NAME.substring(1, 3).length()
+                .gt(Artist.ARTIST_NAME.trim().length());
+        res = ObjectSelect.query(Artist.class, exp3).select(context);
+        assertEquals(0, res.size());
+
+        // Check that all expressions are equal
+        assertEquals(exp1, exp2);
+        assertEquals(exp3, exp3);
+    }
 }