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 2019/05/04 15:01:04 UTC
[cayenne] 02/04: Add DbEntity qualifiers to main query qualifier
instead of join clause
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 <st...@gmail.com>
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());