Return-Path: X-Original-To: apmail-cayenne-commits-archive@www.apache.org Delivered-To: apmail-cayenne-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 4714018CEF for ; Sun, 13 Sep 2015 18:59:57 +0000 (UTC) Received: (qmail 21176 invoked by uid 500); 13 Sep 2015 18:59:57 -0000 Delivered-To: apmail-cayenne-commits-archive@cayenne.apache.org Received: (qmail 21154 invoked by uid 500); 13 Sep 2015 18:59:57 -0000 Mailing-List: contact commits-help@cayenne.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cayenne.apache.org Delivered-To: mailing list commits@cayenne.apache.org Received: (qmail 21143 invoked by uid 99); 13 Sep 2015 18:59:57 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 13 Sep 2015 18:59:57 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id EAF7CE02DB; Sun, 13 Sep 2015 18:59:56 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: aadamchik@apache.org To: commits@cayenne.apache.org Message-Id: <12685b12bf4846638351ae981d99ceb8@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: cayenne git commit: CAY-2027 Support for Expression outer join syntax in EJBQL Date: Sun, 13 Sep 2015 18:59:56 +0000 (UTC) Repository: cayenne Updated Branches: refs/heads/master 1799395a9 -> de8a52b2e CAY-2027 Support for Expression outer join syntax in EJBQL Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/de8a52b2 Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/de8a52b2 Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/de8a52b2 Branch: refs/heads/master Commit: de8a52b2eb9b44656433d11991bbb7cc6c5c2d6c Parents: 1799395 Author: aadamchik Authored: Sun Sep 13 14:13:14 2015 -0400 Committer: aadamchik Committed: Sun Sep 13 14:59:49 2015 -0400 ---------------------------------------------------------------------- .../ejbql/EJBQLAggregateColumnTranslator.java | 2 +- .../ejbql/EJBQLGroupByTranslator.java | 2 +- .../translator/ejbql/EJBQLPathTranslator.java | 27 ++++++++++++--- .../ejbql/EJBQLSelectColumnsTranslator.java | 2 +- .../apache/cayenne/ejbql/parser/Compiler.java | 5 +++ .../org/apache/cayenne/ejbql/EJBQLParser.jjt | 2 +- .../cayenne/access/DataContextEJBQLJoinsIT.java | 36 ++++++++++++++++++++ .../cayenne/ejbql/EJBQLParser_ParseTest.java | 8 ++++- docs/doc/src/main/resources/RELEASE-NOTES.txt | 1 + 9 files changed, 75 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/de8a52b2/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLAggregateColumnTranslator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLAggregateColumnTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLAggregateColumnTranslator.java index 902b63e..d3bc0e3 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLAggregateColumnTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLAggregateColumnTranslator.java @@ -127,7 +127,7 @@ class EJBQLAggregateColumnTranslator extends EJBQLBaseVisitor { Collection dbAttr = ((ObjEntity) relationship.getTargetEntity()).getDbEntity().getAttributes(); if (dbAttr.size() > 0) { - this.resolveJoin(true); + resolveJoin(); } context.append('*'); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/de8a52b2/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLGroupByTranslator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLGroupByTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLGroupByTranslator.java index ba32677..cf4b16f 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLGroupByTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLGroupByTranslator.java @@ -78,7 +78,7 @@ class EJBQLGroupByTranslator extends EJBQLBaseVisitor { .quotedFullyQualifiedName(descriptor.getEntity().getDbEntity())); } - this.lastPathComponent = expression.getText(); + resolveLastPathComponent(expression.getText()); this.fullPath = fullPath + '.' + lastPathComponent; return true; http://git-wip-us.apache.org/repos/asf/cayenne/blob/de8a52b2/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLPathTranslator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLPathTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLPathTranslator.java index c7342d9..75c0687 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLPathTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLPathTranslator.java @@ -31,6 +31,7 @@ import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.map.DbEntity; import org.apache.cayenne.map.DbJoin; import org.apache.cayenne.map.DbRelationship; +import org.apache.cayenne.map.Entity; import org.apache.cayenne.map.ObjAttribute; import org.apache.cayenne.map.ObjEntity; import org.apache.cayenne.map.ObjRelationship; @@ -48,6 +49,7 @@ public abstract class EJBQLPathTranslator extends EJBQLBaseVisitor { private EJBQLTranslationContext context; protected ObjEntity currentEntity; protected String lastPathComponent; + protected boolean innerJoin; protected String lastAlias; protected String idPath; protected String joinMarker; @@ -98,14 +100,28 @@ public abstract class EJBQLPathTranslator extends EJBQLBaseVisitor { // join will // get lost... if (lastPathComponent != null) { - resolveJoin(true); + resolveJoin(); } - this.lastPathComponent = expression.getText(); + resolveLastPathComponent(expression.getText()); return true; } + + /** + * @since 4.0 + */ + protected void resolveLastPathComponent(String pathComponent) { + + if (pathComponent.endsWith(Entity.OUTER_JOIN_INDICATOR)) { + this.lastPathComponent = pathComponent.substring(0, pathComponent.length() - 1); + this.innerJoin = false; + } else { + this.lastPathComponent = pathComponent; + this.innerJoin = true; + } + } - protected void resolveJoin(boolean inner) { + protected void resolveJoin() { EJBQLJoinAppender joinAppender = context.getTranslatorFactory().getJoinAppender(context); @@ -137,7 +153,7 @@ public abstract class EJBQLPathTranslator extends EJBQLBaseVisitor { } // register join - if (inner) { + if (innerJoin) { joinAppender.appendInnerJoin(joinMarker, new EJBQLTableId(idPath), new EJBQLTableId(fullPath)); } else { joinAppender.appendOuterJoin(joinMarker, new EJBQLTableId(idPath), new EJBQLTableId(fullPath)); @@ -213,7 +229,8 @@ public abstract class EJBQLPathTranslator extends EJBQLBaseVisitor { // MEMBER OF and IS EMPTY operators. Outer join is needed for IS // EMPTY... I // guess MEMBER OF could've been done with an inner join though.. - resolveJoin(false); + this.innerJoin = false; + resolveJoin(); DbRelationship dbRelationship = chooseDbRelationship(relationship); DbEntity table = (DbEntity) dbRelationship.getTargetEntity(); http://git-wip-us.apache.org/repos/asf/cayenne/blob/de8a52b2/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLSelectColumnsTranslator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLSelectColumnsTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLSelectColumnsTranslator.java index 3266337..41a4017 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLSelectColumnsTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLSelectColumnsTranslator.java @@ -91,7 +91,7 @@ public class EJBQLSelectColumnsTranslator extends EJBQLBaseVisitor { Iterator it = dbAttr.iterator(); if (dbAttr.size() > 0) { - this.resolveJoin(true); + resolveJoin(); } String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context http://git-wip-us.apache.org/repos/asf/cayenne/blob/de8a52b2/cayenne-server/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java b/cayenne-server/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java index 375547d..5955b3e 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java @@ -34,6 +34,7 @@ import org.apache.cayenne.ejbql.EJBQLExpressionVisitor; import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.map.DbJoin; import org.apache.cayenne.map.DbRelationship; +import org.apache.cayenne.map.Entity; import org.apache.cayenne.map.EntityResolver; import org.apache.cayenne.map.EntityResult; import org.apache.cayenne.map.ObjAttribute; @@ -147,6 +148,10 @@ class Compiler { for (int i = 1; i < path.getChildrenCount(); i++) { String pathChunk = path.getChild(i).getText(); + if(pathChunk.endsWith(Entity.OUTER_JOIN_INDICATOR)) { + pathChunk = pathChunk.substring(0, pathChunk.length() - 1); + } + buffer.append('.').append(pathChunk); PropertyDescriptor property = descriptor.getProperty(pathChunk); http://git-wip-us.apache.org/repos/asf/cayenne/blob/de8a52b2/cayenne-server/src/main/jjtree/org/apache/cayenne/ejbql/EJBQLParser.jjt ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/jjtree/org/apache/cayenne/ejbql/EJBQLParser.jjt b/cayenne-server/src/main/jjtree/org/apache/cayenne/ejbql/EJBQLParser.jjt index ed947fa..1a418bb 100644 --- a/cayenne-server/src/main/jjtree/org/apache/cayenne/ejbql/EJBQLParser.jjt +++ b/cayenne-server/src/main/jjtree/org/apache/cayenne/ejbql/EJBQLParser.jjt @@ -253,7 +253,7 @@ TOKEN : /* literals */ /* From the Java 1.0.2 specification */ TOKEN : /* IDENTIFIERS */ { - < IDENTIFIER: (|)* > + < IDENTIFIER: (|)* (["+"])? > | < #LETTER: [ http://git-wip-us.apache.org/repos/asf/cayenne/blob/de8a52b2/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextEJBQLJoinsIT.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextEJBQLJoinsIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextEJBQLJoinsIT.java index f91c351..1a5bd31 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextEJBQLJoinsIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextEJBQLJoinsIT.java @@ -179,6 +179,42 @@ public class DataContextEJBQLJoinsIT extends ServerCase { } @Test + public void testImplicitJoins_OUTER_LastComponent() throws Exception { + + tArtist.insert(33001, "AA1"); + tArtist.insert(33002, "AA2"); + tPainting.insert(33005, 33001, null, "CC1", 5000); + tPainting.insert(33006, 33001, null, "CC2", 5000); + + String ejbql = "SELECT a FROM Artist a WHERE a.paintingArray+ is null"; + + EJBQLQuery query = new EJBQLQuery(ejbql); + + List artists = context.performQuery(query); + assertEquals(1, artists.size()); + assertEquals(33002, Cayenne.intPKForObject((Artist) artists.get(0))); + } + + @Test + public void testImplicitJoins_OUTER_InTheMiddle() throws Exception { + + tGallery.insert(33001, "gallery1"); + tGallery.insert(33002, "gallery2"); + tArtist.insert(33001, "AA1"); + tArtist.insert(33002, "AA2"); + tPainting.insert(33005, 33001, 33001, "CC1", 5000); + tPainting.insert(33006, 33001, 33002, "CC2", 5000); + + String ejbql = "SELECT a FROM Artist a WHERE a.paintingArray+.toGallery is null"; + + EJBQLQuery query = new EJBQLQuery(ejbql); + + List artists = context.performQuery(query); + assertEquals(1, artists.size()); + assertEquals(33002, Cayenne.intPKForObject((Artist) artists.get(0))); + } + + @Test public void testPartialImplicitJoins1() throws Exception { createTwoArtistsTwoPaintingsTwoGalleries(); http://git-wip-us.apache.org/repos/asf/cayenne/blob/de8a52b2/cayenne-server/src/test/java/org/apache/cayenne/ejbql/EJBQLParser_ParseTest.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/ejbql/EJBQLParser_ParseTest.java b/cayenne-server/src/test/java/org/apache/cayenne/ejbql/EJBQLParser_ParseTest.java index f63ce7e..3f70977 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/ejbql/EJBQLParser_ParseTest.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/ejbql/EJBQLParser_ParseTest.java @@ -46,6 +46,13 @@ public class EJBQLParser_ParseTest { assertNotNull(select); } + @Test + public void testImplicitOuterJoin() { + EJBQLExpression select = parser + .parse("SELECT a FROM Artist a WHERE a.paintingArray+.toGallery.galleryName = 'gallery2'"); + assertNotNull(select); + } + /** * This should not parse because there are multiple non-bracketed * parameters. @@ -62,6 +69,5 @@ public class EJBQLParser_ParseTest { fail("expected an instance of " + EJBQLException.class.getSimpleName() + " to be thrown, but; " + th.getClass().getSimpleName() + " was thrown"); } - } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/de8a52b2/docs/doc/src/main/resources/RELEASE-NOTES.txt ---------------------------------------------------------------------- diff --git a/docs/doc/src/main/resources/RELEASE-NOTES.txt b/docs/doc/src/main/resources/RELEASE-NOTES.txt index 655f412..74daf95 100644 --- a/docs/doc/src/main/resources/RELEASE-NOTES.txt +++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt @@ -31,6 +31,7 @@ CAY-2013 In-memory evaluation of DB expressions - non-id attributes CAY-2023 Decouple the use of ResourceLocator CAY-2025 Support for DBCP2 CAY-2026 Java 7 +CAY-2027 Support for Expression outer join syntax in EJBQL Bug Fixes: