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);
+ }
}