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
commit 932037f80adade89f49df5e58f3f482a48b32bc4 Author: Nikita Timofeev <[email protected]> AuthorDate: Sat May 4 17:15:00 2019 +0300 Add DbEntity qualifiers to main query qualifier instead of join clause --- .../translator/select/DefaultSelectTranslator.java | 1 + .../select/QualifierTranslationStage.java | 21 +------ .../access/translator/select/TableTree.java | 14 ++++- .../translator/select/TableTreeQualifierStage.java | 67 ++++++++++++++++++++++ .../access/translator/select/TableTreeStage.java | 25 -------- .../translator/select/TranslatorContext.java | 10 ++++ .../select/QualifierTranslationStageTest.java | 10 +--- 7 files changed, 94 insertions(+), 54 deletions(-) diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java index 1213c38..fee28d8 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java @@ -48,6 +48,7 @@ public class DefaultSelectTranslator implements SelectTranslator { new DistinctStage(), new LimitOffsetStage(), new ColumnDescriptorStage(), + new TableTreeQualifierStage(), new TableTreeStage(), new SQLResultStage(), new SQLGenerationStage() diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslationStage.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslationStage.java index c4d2ba1..386c0e3 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslationStage.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslationStage.java @@ -49,26 +49,7 @@ class QualifierTranslationStage implements TranslationStage { } } - // Attaching root Db entity's qualifier - DbEntity dbEntity = context.getMetadata().getDbEntity(); - if (dbEntity != null) { - Expression dbQualifier = dbEntity.getQualifier(); - if (dbQualifier != null) { - dbQualifier = dbQualifier.transform(node -> { - if (node instanceof ASTObjPath) { - return new ASTDbPath(((SimpleNode) node).getOperand(0)); - } - return node; - }); - - expression = expression == null ? dbQualifier : expression.andExp(dbQualifier); - } - } - Node qualifierNode = translator.translate(expression); - - if(qualifierNode != null) { - context.getSelectBuilder().where(qualifierNode); - } + context.setQualifierNode(qualifierNode); } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TableTree.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TableTree.java index 5082c4e..6eb7a8d 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TableTree.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TableTree.java @@ -21,6 +21,7 @@ package org.apache.cayenne.access.translator.select; import java.util.LinkedHashMap; import java.util.Map; +import java.util.stream.Collectors; import org.apache.cayenne.CayenneRuntimeException; import org.apache.cayenne.map.DbEntity; @@ -97,8 +98,17 @@ class TableTree { public void visit(TableNodeVisitor visitor) { visitor.visit(rootNode); - for(TableTreeNode node : tableNodes.values()) { - visitor.visit(node); + + // as we can spawn new nodes while processing existing, + // we need multiple iterations until all rows are processed + int initialSize = 0; + int currentSize = tableNodes.size(); + while(initialSize != currentSize) { + tableNodes.values().stream().skip(initialSize) + .collect(Collectors.toList()) // copy collection in case of concurrent modification in visitor + .forEach(visitor::visit); + initialSize = currentSize; + currentSize = tableNodes.size(); } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TableTreeQualifierStage.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TableTreeQualifierStage.java new file mode 100644 index 0000000..1d00543 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TableTreeQualifierStage.java @@ -0,0 +1,67 @@ +/***************************************************************** + * 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.translator.select; + +import org.apache.cayenne.access.sqlbuilder.NodeBuilder; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; +import org.apache.cayenne.exp.Expression; +import org.apache.cayenne.exp.parser.ASTDbPath; +import org.apache.cayenne.exp.parser.ASTPath; + +import static org.apache.cayenne.access.sqlbuilder.SQLBuilder.exp; +import static org.apache.cayenne.access.sqlbuilder.SQLBuilder.node; + +/** + * @since 4.2 + */ +class TableTreeQualifierStage implements TranslationStage { + + @Override + public void perform(TranslatorContext context) { + context.getTableTree().visit(node -> { + Expression dbQualifier = node.getEntity().getQualifier(); + if (dbQualifier != null) { + String pathToRoot = node.getAttributePath().getPath(); + dbQualifier = dbQualifier.transform(input -> { + if (input instanceof ASTPath) { + String path = ((ASTPath) input).getPath(); + if(!pathToRoot.isEmpty()) { + path = pathToRoot + '.' + path; + } + return new ASTDbPath(path); + } + return input; + }); + Node rootQualifier = context.getQualifierNode(); + Node translatedQualifier = context.getQualifierTranslator().translate(dbQualifier); + if (rootQualifier != null) { + NodeBuilder expressionNodeBuilder = exp(node(rootQualifier)).and(node(translatedQualifier)); + context.setQualifierNode(expressionNodeBuilder.build()); + } else { + context.setQualifierNode(translatedQualifier); + } + } + }); + + if(context.getQualifierNode() != null) { + context.getSelectBuilder().where(context.getQualifierNode()); + } + } +} diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TableTreeStage.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TableTreeStage.java index 9ad1588..c4ee949 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TableTreeStage.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TableTreeStage.java @@ -24,10 +24,6 @@ import java.util.List; import org.apache.cayenne.access.sqlbuilder.ExpressionNodeBuilder; import org.apache.cayenne.access.sqlbuilder.JoinNodeBuilder; import org.apache.cayenne.access.sqlbuilder.NodeBuilder; -import org.apache.cayenne.access.sqlbuilder.sqltree.Node; -import org.apache.cayenne.exp.Expression; -import org.apache.cayenne.exp.parser.ASTDbPath; -import org.apache.cayenne.exp.parser.ASTPath; import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.map.DbJoin; @@ -45,7 +41,6 @@ class TableTreeStage implements TranslationStage { if(node.getRelationship() != null) { tableNode = getJoin(node, tableNode).on(getJoinExpression(context, node)); } - context.getSelectBuilder().from(tableNode); }); } @@ -79,26 +74,6 @@ class TableTreeStage implements TranslationStage { } } - expressionNodeBuilder = attachTargetQualifier(context, node, expressionNodeBuilder); - - return expressionNodeBuilder; - } - - private ExpressionNodeBuilder attachTargetQualifier(TranslatorContext context, TableTreeNode node, ExpressionNodeBuilder expressionNodeBuilder) { - Expression dbQualifier = node.getRelationship().getTargetEntity().getQualifier(); - if (dbQualifier != null) { - String pathToRoot = node.getAttributePath().getPath(); - dbQualifier = dbQualifier.transform(input -> input instanceof ASTPath - ? new ASTDbPath(pathToRoot + '.' + ((ASTPath) input).getPath()) - : input - ); - Node translatedQualifier = context.getQualifierTranslator().translate(dbQualifier); - if (expressionNodeBuilder != null) { - expressionNodeBuilder = expressionNodeBuilder.and(node(translatedQualifier)); - } else { - expressionNodeBuilder = exp(node(translatedQualifier)); - } - } return expressionNodeBuilder; } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TranslatorContext.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TranslatorContext.java index bf89ceb..25c1687 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TranslatorContext.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TranslatorContext.java @@ -87,6 +87,8 @@ public class TranslatorContext implements SQLGenerationContext { // List of SQL tree nodes that describe resulting rows of this query private final List<ResultNodeDescriptor> resultNodeList; + // resulting qualifier for this query ('where' qualifier and qualifiers from entities) + private Node qualifierNode; // if true SQL generation stage will be skipped, needed for nested queries translation private boolean skipSQLGeneration; // translated SQL string @@ -256,6 +258,14 @@ public class TranslatorContext implements SQLGenerationContext { return rootEntityResult; } + void setQualifierNode(Node qualifierNode) { + this.qualifierNode = qualifierNode; + } + + Node getQualifierNode() { + return qualifierNode; + } + enum DescriptorType { ROOT, PREFETCH, diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslationStageTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslationStageTest.java index 9b56c81..cc628f8 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslationStageTest.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslationStageTest.java @@ -62,19 +62,15 @@ public class QualifierTranslationStageTest { QualifierTranslationStage stage = new QualifierTranslationStage(); stage.perform(context); - Node select = context.getSelectBuilder().build(); + assertNotNull(context.getQualifierNode()); - // Content of "select" node: + // Content of "Qualifier" node: // - // Where - // | // OpExpression // / \ // Column Value - assertEquals(1, select.getChildrenCount()); - assertThat(select.getChild(0), instanceOf(WhereNode.class)); - Node op = select.getChild(0).getChild(0); + Node op = context.getQualifierNode(); assertThat(op, instanceOf(OpExpressionNode.class)); assertEquals(">=", ((OpExpressionNode)op).getOp()); assertEquals(2, op.getChildrenCount());
