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/09/03 15:02:10 UTC
[cayenne] branch master updated: Support for NOT EXISTS subqueries
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 901b10c Support for NOT EXISTS subqueries
901b10c is described below
commit 901b10c37961cabb93a669b566a7c003c2d517b1
Author: Nikita Timofeev <st...@gmail.com>
AuthorDate: Tue Sep 3 18:02:01 2019 +0300
Support for NOT EXISTS subqueries
---
.../translator/select/QualifierTranslator.java | 4 +-
.../java/org/apache/cayenne/exp/Expression.java | 9 +++-
.../org/apache/cayenne/exp/ExpressionFactory.java | 9 ++++
.../apache/cayenne/exp/parser/ASTNotExists.java | 62 ++++++++++++++++++++++
.../cayenne/query/ObjectSelect_SubqueryIT.java | 12 ++++-
5 files changed, 92 insertions(+), 4 deletions(-)
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
index 8112ce1..1308091 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
@@ -212,6 +212,8 @@ class QualifierTranslator implements TraversalHandler {
case EXISTS:
return new FunctionNode("EXISTS", null, false);
+ case NOT_EXISTS:
+ return new FunctionNode("NOT EXISTS", null, false);
case SUBQUERY:
ASTSubquery subquery = (ASTSubquery)node;
@@ -369,7 +371,7 @@ class QualifierTranslator implements TraversalHandler {
case FUNCTION_CALL: case ADD: case SUBTRACT: case MULTIPLY: case DIVIDE: case NEGATIVE:
case BITWISE_AND: case BITWISE_LEFT_SHIFT: case BITWISE_OR: case BITWISE_RIGHT_SHIFT: case BITWISE_XOR:
case OR: case AND: case LESS_THAN: case LESS_THAN_EQUAL_TO: case GREATER_THAN: case GREATER_THAN_EQUAL_TO:
- case TRUE: case FALSE: case ASTERISK: case EXISTS: case SUBQUERY: case ENCLOSING_OBJECT: case FULL_OBJECT:
+ case TRUE: case FALSE: case ASTERISK: case EXISTS: case NOT_EXISTS: case SUBQUERY: case ENCLOSING_OBJECT: case FULL_OBJECT:
return true;
}
return false;
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java
index 689745f..415659f 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java
@@ -177,12 +177,17 @@ public abstract class Expression implements Serializable, XMLSerializable {
/**
* @since 4.2
*/
- public static final int SUBQUERY = 50;
+ public static final int NOT_EXISTS = 50;
/**
* @since 4.2
*/
- public static final int DBID_PATH = 51;
+ public static final int SUBQUERY = 51;
+
+ /**
+ * @since 4.2
+ */
+ public static final int DBID_PATH = 52;
protected int type;
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 3eaf00b..7d3b207 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
@@ -50,6 +50,7 @@ import org.apache.cayenne.exp.parser.ASTNegate;
import org.apache.cayenne.exp.parser.ASTNot;
import org.apache.cayenne.exp.parser.ASTNotBetween;
import org.apache.cayenne.exp.parser.ASTNotEqual;
+import org.apache.cayenne.exp.parser.ASTNotExists;
import org.apache.cayenne.exp.parser.ASTNotIn;
import org.apache.cayenne.exp.parser.ASTNotLike;
import org.apache.cayenne.exp.parser.ASTNotLikeIgnoreCase;
@@ -1441,6 +1442,14 @@ public class ExpressionFactory {
}
/**
+ * @param subQuery {@link org.apache.cayenne.query.ObjectSelect} or {@link ColumnSelect}
+ * @since 4.2
+ */
+ public static Expression notExists(FluentSelect<?> subQuery) {
+ return new ASTNotExists(new ASTSubquery(subQuery));
+ }
+
+ /**
* @since 4.2
*/
public static Expression inExp(Expression exp, ColumnSelect<?> subQuery) {
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTNotExists.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTNotExists.java
new file mode 100644
index 0000000..61e78ef
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTNotExists.java
@@ -0,0 +1,62 @@
+/*****************************************************************
+ * 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.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * @since 4.2
+ */
+public class ASTNotExists extends ConditionNode {
+
+ public ASTNotExists(ASTSubquery subquery) {
+ super(0);
+ jjtAddChild(subquery, 0);
+ }
+
+ ASTNotExists(int id) {
+ super(id);
+ }
+
+ @Override
+ protected int getRequiredChildrenCount() {
+ return 1;
+ }
+
+ @Override
+ protected Boolean evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception {
+ return null;
+ }
+
+ @Override
+ protected String getExpressionOperator(int index) {
+ return null;
+ }
+
+ @Override
+ public Expression shallowCopy() {
+ return new ASTNotExists(id);
+ }
+
+ @Override
+ public int getType() {
+ return Expression.NOT_EXISTS;
+ }
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_SubqueryIT.java b/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_SubqueryIT.java
index 0a02d7d..64904d5 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_SubqueryIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_SubqueryIT.java
@@ -82,7 +82,7 @@ public class ObjectSelect_SubqueryIT extends ServerCase {
@Test
public void selectQuery_existsWithExpressionFromParentQuery() {
- Expression exp = Painting.TO_ARTIST.eq(PropertyFactory.createSelf(Artist.class).enclosing())
+ Expression exp = Painting.TO_ARTIST.eq(Artist.ARTIST_ID_PK_PROPERTY.enclosing())
.andExp(Painting.PAINTING_TITLE.like("painting%"))
.andExp(Artist.ARTIST_NAME.enclosing().like("art%"));
@@ -94,6 +94,16 @@ public class ObjectSelect_SubqueryIT extends ServerCase {
}
@Test
+ public void selectQuery_notExistsWithExpressionFromParentQuery() {
+ ObjectSelect<Painting> subQuery = ObjectSelect.query(Painting.class)
+ .where(Painting.TO_ARTIST.eq(Artist.ARTIST_ID_PK_PROPERTY.enclosing()));
+ long count = ObjectSelect.query(Artist.class)
+ .where(ExpressionFactory.notExists(subQuery))
+ .selectCount(context);
+ assertEquals(15L, count);
+ }
+
+ @Test
public void selectQuery_twoLevelExists() {
Expression exp = Painting.PAINTING_TITLE.like("painting%")
.andExp(ExpressionFactory.exists(ObjectSelect.query(Gallery.class)));