cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aadamc...@apache.org
Subject svn commit: r609393 - in /cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne: access/jdbc/ ejbql/ ejbql/parser/
Date Sun, 06 Jan 2008 20:27:10 GMT
Author: aadamchik
Date: Sun Jan  6 12:27:08 2008
New Revision: 609393

URL: http://svn.apache.org/viewvc?rev=609393&view=rev
Log:
CAY-954 EJBQL Query: Support for single table inheritance
(raw translator for dbpath)

Added:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLDbPathTranslator.java
Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLDbPath.java

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java?rev=609393&r1=609392&r2=609393&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java
(original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java
Sun Jan  6 12:27:08 2008
@@ -481,6 +481,17 @@
         return false;
     }
 
+    @Override
+    public boolean visitDbPath(EJBQLExpression expression, int finishedChildIndex) {
+        expression.visit(new EJBQLDbPathTranslator(context) {
+
+            protected void appendMultiColumnPath(EJBQLMultiColumnOperand operand) {
+                EJBQLConditionTranslator.this.addMultiColumnOperand(operand);
+            }
+        });
+        return false;
+    }
+
     public boolean visitPath(EJBQLExpression expression, int finishedChildIndex) {
 
         expression.visit(new EJBQLPathTranslator(context) {

Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLDbPathTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLDbPathTranslator.java?rev=609393&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLDbPathTranslator.java
(added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLDbPathTranslator.java
Sun Jan  6 12:27:08 2008
@@ -0,0 +1,266 @@
+/*****************************************************************
+ *   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.access.jdbc;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cayenne.ejbql.EJBQLBaseVisitor;
+import org.apache.cayenne.ejbql.EJBQLException;
+import org.apache.cayenne.ejbql.EJBQLExpression;
+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.Relationship;
+import org.apache.cayenne.reflect.ClassDescriptor;
+
+public abstract class EJBQLDbPathTranslator extends EJBQLBaseVisitor {
+
+    private EJBQLTranslationContext context;
+    protected DbEntity currentEntity;
+    private String lastPathComponent;
+    protected String lastAlias;
+    protected String idPath;
+    protected String joinMarker;
+    private String fullPath;
+    private boolean usingAliases;
+
+    public EJBQLDbPathTranslator(EJBQLTranslationContext context) {
+        super(true);
+        this.context = context;
+        this.usingAliases = true;
+    }
+
+    protected abstract void appendMultiColumnPath(EJBQLMultiColumnOperand operand);
+
+    @Override
+    public boolean visitDbPath(EJBQLExpression expression, int finishedChildIndex) {
+        if (finishedChildIndex > 0) {
+
+            if (finishedChildIndex + 1 < expression.getChildrenCount()) {
+                processIntermediatePathComponent();
+            }
+            else {
+                processLastPathComponent();
+            }
+        }
+
+        return true;
+    }
+
+    public boolean visitIdentifier(EJBQLExpression expression) {
+
+        // expression id is always rooted in an ObjEntity, even for DbPath...
+        ClassDescriptor descriptor = context.getEntityDescriptor(expression.getText());
+        if (descriptor == null) {
+            throw new EJBQLException("Invalid identification variable: "
+                    + expression.getText());
+        }
+
+        this.currentEntity = descriptor.getEntity().getDbEntity();
+        this.idPath = expression.getText();
+        this.joinMarker = EJBQLJoinAppender.makeJoinTailMarker(idPath);
+        this.fullPath = idPath;
+        return true;
+    }
+
+    public boolean visitIdentificationVariable(EJBQLExpression expression) {
+
+        // TODO: andrus 6/11/2007 - if the path ends with relationship, the last join will
+        // get lost...
+        if (lastPathComponent != null) {
+            resolveJoin(true);
+        }
+
+        this.lastPathComponent = expression.getText();
+        return true;
+    }
+
+    private void resolveJoin(boolean inner) {
+
+        EJBQLJoinAppender joinAppender = context.getTranslatorFactory().getJoinAppender(
+                context);
+
+        // TODO: andrus 1/6/2007 - conflict with object path naming... maybe
+        // 'registerReusableJoin' should normalize everything to a db path?
+        String newPath = idPath + '.' + lastPathComponent;
+        String oldPath = joinAppender.registerReusableJoin(
+                idPath,
+                lastPathComponent,
+                newPath);
+
+        this.fullPath = fullPath + '.' + lastPathComponent;
+
+        if (oldPath != null) {
+            this.idPath = oldPath;
+            this.lastAlias = context.getTableAlias(oldPath, currentEntity.getName());
+        }
+        else {
+
+            // register join
+            if (inner) {
+                joinAppender.appendInnerJoin(
+                        joinMarker,
+                        new EJBQLTableId(idPath),
+                        new EJBQLTableId(fullPath));
+                this.lastAlias = context.getTableAlias(fullPath, currentEntity.getName());
+            }
+            else {
+                joinAppender.appendOuterJoin(
+                        joinMarker,
+                        new EJBQLTableId(idPath),
+                        new EJBQLTableId(fullPath));
+
+                Relationship lastRelationship = currentEntity
+                        .getRelationship(lastPathComponent);
+                DbEntity targetEntity = (DbEntity) lastRelationship.getTargetEntity();
+
+                this.lastAlias = context.getTableAlias(fullPath, targetEntity.getName());
+            }
+
+            this.idPath = newPath;
+        }
+    }
+
+    private void processIntermediatePathComponent() {
+        DbRelationship relationship = (DbRelationship) currentEntity
+                .getRelationship(lastPathComponent);
+        if (relationship == null) {
+            throw new EJBQLException("Unknown relationship '"
+                    + lastPathComponent
+                    + "' for entity '"
+                    + currentEntity.getName()
+                    + "'");
+        }
+
+        this.currentEntity = (DbEntity) relationship.getTargetEntity();
+    }
+
+    private void processLastPathComponent() {
+
+        DbAttribute attribute = (DbAttribute) currentEntity
+                .getAttribute(lastPathComponent);
+
+        if (attribute != null) {
+            processTerminatingAttribute(attribute);
+            return;
+        }
+
+        DbRelationship relationship = (DbRelationship) currentEntity
+                .getRelationship(lastPathComponent);
+        if (relationship != null) {
+            processTerminatingRelationship(relationship);
+            return;
+        }
+
+        throw new IllegalStateException("Invalid path component: " + lastPathComponent);
+    }
+
+    protected void processTerminatingAttribute(DbAttribute attribute) {
+
+        DbEntity table = (DbEntity) attribute.getEntity();
+
+        if (isUsingAliases()) {
+            String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(
+                    idPath,
+                    table.getFullyQualifiedName());
+            context.append(' ').append(alias).append('.').append(attribute.getName());
+        }
+        else {
+            context.append(' ').append(attribute.getName());
+        }
+    }
+
+    private void processTerminatingRelationship(DbRelationship relationship) {
+
+        if (relationship.isToMany()) {
+
+            // use an outer join for to-many matches
+            resolveJoin(false);
+
+            DbEntity table = (DbEntity) relationship.getTargetEntity();
+
+            String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(
+                    idPath,
+                    table.getFullyQualifiedName());
+
+            Collection<DbAttribute> pks = table.getPrimaryKeys();
+
+            if (pks.size() == 1) {
+                DbAttribute pk = pks.iterator().next();
+                context.append(' ');
+                if (isUsingAliases()) {
+                    context.append(alias).append('.');
+                }
+                context.append(pk.getName());
+            }
+            else {
+                throw new EJBQLException(
+                        "Multi-column PK to-many matches are not yet supported.");
+            }
+        }
+        else {
+            // match FK against the target object
+
+            DbEntity table = (DbEntity) relationship.getSourceEntity();
+
+            String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(
+                    idPath,
+                    table.getFullyQualifiedName());
+
+            List<DbJoin> joins = relationship.getJoins();
+
+            if (joins.size() == 1) {
+                DbJoin join = joins.get(0);
+                context.append(' ');
+                if (isUsingAliases()) {
+                    context.append(alias).append('.');
+                }
+                context.append(join.getSourceName());
+            }
+            else {
+                Map<String, String> multiColumnMatch = new HashMap<String, String>(joins
+                        .size() + 2);
+
+                for (DbJoin join : joins) {
+                    String column = isUsingAliases()
+                            ? alias + "." + join.getSourceName()
+                            : join.getSourceName();
+
+                    multiColumnMatch.put(join.getTargetName(), column);
+                }
+
+                appendMultiColumnPath(EJBQLMultiColumnOperand.getPathOperand(
+                        context,
+                        multiColumnMatch));
+            }
+        }
+    }
+
+    public boolean isUsingAliases() {
+        return usingAliases;
+    }
+
+    public void setUsingAliases(boolean usingAliases) {
+        this.usingAliases = usingAliases;
+    }
+}

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java?rev=609393&r1=609392&r2=609393&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java
(original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java
Sun Jan  6 12:27:08 2008
@@ -134,7 +134,7 @@
         return continueFlag;
     }
     
-    public boolean visitDbPath(EJBQLExpression expression) {
+    public boolean visitDbPath(EJBQLExpression expression, int finishedChildIndex) {
         return continueFlag;
     }
 

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java?rev=609393&r1=609392&r2=609393&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java
(original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java
Sun Jan  6 12:27:08 2008
@@ -275,7 +275,7 @@
      */
     boolean visitPath(EJBQLExpression expression, int finishedChildIndex);
     
-    boolean visitDbPath(EJBQLExpression expression);
+    boolean visitDbPath(EJBQLExpression expression, int finishedChildIndex);
 
     boolean visitPatternValue(EJBQLExpression expression);
 

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLDbPath.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLDbPath.java?rev=609393&r1=609392&r2=609393&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLDbPath.java
(original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLDbPath.java
Sun Jan  6 12:27:08 2008
@@ -26,7 +26,14 @@
         super(id);
     }
 
-    public void visit(EJBQLExpressionVisitor visitor) {
-        visitor.visitDbPath(this);
+    @Override
+    protected boolean visitChild(EJBQLExpressionVisitor visitor, int childIndex) {
+        return super.visitChild(visitor, childIndex)
+                && visitor.visitDbPath(this, childIndex);
+    }
+
+    @Override
+    protected boolean visitNode(EJBQLExpressionVisitor visitor) {
+        return visitor.visitDbPath(this, -1);
     }
 }



Mime
View raw message