You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2026/08/30 16:04:42 UTC
(cayenne) 02/02: removing dead code - EOQuery
This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git
commit debcdc94dab0812372b6fbb04d7be9b1db17d079
Author: Andrus Adamchik <an...@objectstyle.com>
AuthorDate: Sun Aug 30 12:03:35 2026 -0400
removing dead code - EOQuery
---
.../wocompat/EOFetchSpecificationParser.java | 302 +++++++++++++
.../apache/cayenne/wocompat/EOModelProcessor.java | 2 +-
.../org/apache/cayenne/wocompat/EOObjEntity.java | 4 +-
.../java/org/apache/cayenne/wocompat/EOQuery.java | 495 ---------------------
...st.java => EOFetchSpecificationParserTest.java} | 45 +-
5 files changed, 331 insertions(+), 517 deletions(-)
diff --git a/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOFetchSpecificationParser.java b/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOFetchSpecificationParser.java
new file mode 100644
index 000000000..a52d0866f
--- /dev/null
+++ b/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOFetchSpecificationParser.java
@@ -0,0 +1,302 @@
+/*****************************************************************
+ * 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
+ *
+ * https://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.wocompat;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionException;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.exp.ExpressionParameter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * EOFetchSpecificationParser parses EOFetchSpecifications from a
+ * WebObjects-style EOModel. It recursively builds Cayenne Expression
+ * objects and assembles them into the final aggregate Expression.
+ */
+@SuppressWarnings("unchecked")
+class EOFetchSpecificationParser {
+
+ // Xcode/EOModeler expressions have a colon at the end of the selector
+ // name
+ // (just like standard Objective-C syntax). WOLips does not. Add both
+ // sets to the hash map to handle both types of models.
+
+ // Selector strings (Java-base).
+ static final String IS_EQUAL_TO = "isEqualTo";
+ static final String IS_NOT_EQUAL_TO = "isNotEqualTo";
+ static final String IS_LIKE = "isLike";
+ static final String CASE_INSENSITIVE_LIKE = "isCaseInsensitiveLike";
+ static final String IS_LESS_THAN = "isLessThan";
+ static final String IS_LESS_THAN_OR_EQUAL_TO = "isLessThanOrEqualTo";
+ static final String IS_GREATER_THAN = "isGreaterThan";
+ static final String IS_GREATER_THAN_OR_EQUAL_TO = "isGreaterThanOrEqualTo";
+
+ private static final String OBJ_C = ":"; // Objective-C syntax addition.
+
+ private static Map<String, Integer> selectorToExpressionBridge;
+ private static final Logger LOGGER = LoggerFactory.getLogger(EOFetchSpecificationParser.class);
+
+ /**
+ * selectorToExpressionBridge is just a mapping of EOModeler's selector
+ * types to Cayenne Expression types.
+ *
+ * @return HashMap of Expression types, keyed by the corresponding
+ * selector name
+ */
+ static synchronized Map<String, Integer> selectorToExpressionBridge() {
+ // Initialize selectorToExpressionBridge if needed.
+ if (null == selectorToExpressionBridge) {
+ selectorToExpressionBridge = new HashMap<>();
+
+ selectorToExpressionBridge.put(IS_EQUAL_TO, Expression.EQUAL_TO);
+ selectorToExpressionBridge.put(IS_EQUAL_TO + OBJ_C, Expression.EQUAL_TO);
+
+ selectorToExpressionBridge.put(IS_NOT_EQUAL_TO, Expression.NOT_EQUAL_TO);
+ selectorToExpressionBridge.put(IS_NOT_EQUAL_TO + OBJ_C, Expression.NOT_EQUAL_TO);
+
+ selectorToExpressionBridge.put(IS_LIKE, Expression.LIKE);
+ selectorToExpressionBridge.put(IS_LIKE + OBJ_C, Expression.LIKE);
+
+ selectorToExpressionBridge.put(CASE_INSENSITIVE_LIKE, Expression.LIKE_IGNORE_CASE);
+ selectorToExpressionBridge.put(CASE_INSENSITIVE_LIKE + OBJ_C, Expression.LIKE_IGNORE_CASE);
+
+ selectorToExpressionBridge.put(IS_LESS_THAN, Expression.LESS_THAN);
+ selectorToExpressionBridge.put(IS_LESS_THAN + OBJ_C, Expression.LESS_THAN);
+
+ selectorToExpressionBridge.put(IS_LESS_THAN_OR_EQUAL_TO, Expression.LESS_THAN_EQUAL_TO);
+ selectorToExpressionBridge.put(IS_LESS_THAN_OR_EQUAL_TO + OBJ_C, Expression.LESS_THAN_EQUAL_TO);
+
+ selectorToExpressionBridge.put(IS_GREATER_THAN, Expression.GREATER_THAN);
+ selectorToExpressionBridge.put(IS_GREATER_THAN + OBJ_C, Expression.GREATER_THAN);
+
+ selectorToExpressionBridge.put(IS_GREATER_THAN_OR_EQUAL_TO, Expression.GREATER_THAN_EQUAL_TO);
+ selectorToExpressionBridge.put(IS_GREATER_THAN_OR_EQUAL_TO + OBJ_C, Expression.GREATER_THAN_EQUAL_TO);
+ }
+
+ return selectorToExpressionBridge;
+ }
+
+ /**
+ * isAggregate determines whether a qualifier is "aggregate" -- has
+ * children -- or "simple".
+ *
+ * @param qualifier
+ * - a Map containing the qualifier settings
+ * @return boolean indicating whether the qualifier is "aggregate"
+ * qualifier
+ */
+ static boolean isAggregate(Map<String, ?> qualifier) {
+ boolean result = true;
+
+ String theClass = (String) qualifier.get("class");
+ if (theClass == null) {
+ return false; // should maybe throw an exception?
+ }
+ if (theClass.equalsIgnoreCase("EOKeyValueQualifier")
+ || theClass.equalsIgnoreCase("EOKeyComparisonQualifier")) {
+ result = false;
+ }
+
+ return result;
+ }
+
+ /**
+ * expressionTypeForQualifier looks at a qualifier containing the
+ * EOModeler FetchSpecification and returns the equivalent Cayenne
+ * Expression type for its selector.
+ *
+ * @param qualifierMap
+ * - a Map containing the qualifier settings to examine.
+ * @return int Expression type
+ */
+ static int expressionTypeForQualifier(Map<String, ?> qualifierMap) {
+ // get selector
+ String selector = (String) qualifierMap.get("selectorName");
+ return expressionTypeForSelector(selector);
+ }
+
+ /**
+ * expressionTypeForSelector looks at a selector from an EOModeler
+ * FetchSpecification and returns the equivalent Cayenne Expression
+ * type.
+ *
+ * @param selector
+ * - a String containing the selector name.
+ * @return int Expression type
+ */
+ static int expressionTypeForSelector(String selector) {
+ Integer expType = selectorToExpressionBridge().get(selector);
+ return (expType != null ? expType : -1);
+ }
+
+ /**
+ * aggregateExpressionClassForQualifier looks at a qualifer and returns
+ * the aggregate type: one of Expression.AND, Expression.OR, or
+ * Expression.NOT
+ *
+ * @param qualifierMap
+ * - containing the qualifier to examine
+ * @return int aggregate Expression type
+ */
+ static int aggregateExpressionClassForQualifier(Map<String, ?> qualifierMap) {
+ String qualifierClass = (String) qualifierMap.get("class");
+ if (qualifierClass != null) {
+ if (qualifierClass.equalsIgnoreCase("EOAndQualifier")) {
+ return Expression.AND;
+ } else if (qualifierClass.equalsIgnoreCase("EOOrQualifier")) {
+ return Expression.OR;
+ } else if (qualifierClass.equalsIgnoreCase("EONotQualifier")) {
+ return Expression.NOT;
+ }
+ }
+
+ return -1; // error
+ }
+
+ /**
+ * makeQualifier recursively builds an Expression for each condition in
+ * the qualifierMap and assembles from them the complex Expression to
+ * represent the entire EOFetchSpecification.
+ *
+ * @param qualifierMap
+ * - Map representation of EOFetchSpecification
+ * @return Expression translation of the EOFetchSpecification
+ */
+ static Expression makeQualifier(EOObjEntity entity, Map<String, ?> qualifierMap) {
+ if (isAggregate(qualifierMap)) {
+ // the fetch specification has more than one qualifier
+ int aggregateClass = aggregateExpressionClassForQualifier(qualifierMap); // AND,
+ // OR,
+ // NOT
+
+ if (aggregateClass == Expression.NOT) {
+ // NOT qualifiers only have one child, keyed with
+ // "qualifier"
+ Map<String, ?> child = (Map<String, ?>) qualifierMap.get("qualifier");
+ // build the child expression
+ Expression childExp = makeQualifier(entity, child);
+
+ return childExp.notExp(); // add the "not" clause and return
+ // the
+ // result
+ } else {
+ // AND, OR qualifiers can have multiple children, keyed with
+ // "qualifiers"
+ // get the list of children
+ List<Map<String, ?>> children = (List<Map<String, ?>>) qualifierMap.get("qualifiers");
+ if (children != null) {
+ ArrayList<Expression> childExpressions = new ArrayList<>();
+ // build an Expression for each child
+ for (Map<String, ?> child : children) {
+ Expression childExp = makeQualifier(entity, child);
+ childExpressions.add(childExp);
+ }
+ // join the child expressions and return the result
+ return ExpressionFactory.joinExp(aggregateClass, childExpressions);
+ }
+ }
+
+ } // end if isAggregate(qualifierMap)...
+
+ // the query has a single qualifier
+ // get expression selector type
+ String qualifierClass = (String) qualifierMap.get("class");
+
+ // the key or key path we're comparing
+ String key = null;
+ // the key, keyPath, value, or parameterized value against which
+ // we're
+ // comparing the key
+ Object comparisonValue = null;
+
+ if ("EOKeyComparisonQualifier".equals(qualifierClass)) {
+ // Comparing two keys or key paths
+ key = (String) qualifierMap.get("leftValue");
+ comparisonValue = qualifierMap.get("rightValue");
+ // FIXME: I think EOKeyComparisonQualifier style Expressions are not supported...
+ return null;
+ } else if ("EOKeyValueQualifier".equals(qualifierClass)) {
+ // Comparing key with a value or parameterized value
+ key = (String) qualifierMap.get("key");
+ Object value = qualifierMap.get("value");
+
+ if (value instanceof Map) {
+ Map<String, String> valueMap = (Map<String, String>) value;
+ String objClass = valueMap.get("class"); // can be a
+ // qualifier class or java type
+ if ("EOQualifierVariable".equals(objClass) && valueMap.containsKey("_key")) {
+ // make a parameterized expression
+ String paramName = valueMap.get("_key");
+ comparisonValue = new ExpressionParameter(paramName);
+ } else {
+ Object queryVal = valueMap.get("value");
+ if ("NSNumber".equals(objClass)) {
+ // comparison to NSNumber -- cast
+ comparisonValue = queryVal;
+ } else if ("EONull".equals(objClass)) {
+ // comparison to null
+ comparisonValue = null;
+ } else { // Could there be other types? boolean, date,
+ // etc.???
+ // no cast
+ comparisonValue = queryVal;
+ }
+ }
+
+ } else if (value instanceof String) {
+ // value expression
+ comparisonValue = value;
+ } // end if (value instanceof Map) else...
+ }
+
+ // check whether the key is an object path; if at least one
+ // component is not,
+ // switch to db path..
+
+ Expression keyExp = ExpressionFactory.exp(key);
+ try {
+ entity.lastPathComponent(keyExp, Collections.emptyMap());
+ } catch (ExpressionException e) {
+ try {
+ keyExp = entity.translateToDbPath(keyExp);
+ } catch (Exception dbpathEx) {
+ LOGGER.warn("Couldn't find {} in {} in EOModel", keyExp, entity.getName());
+ }
+ }
+
+ try {
+ Expression exp = ExpressionFactory.expressionOfType(expressionTypeForQualifier(qualifierMap));
+
+ exp.setOperand(0, keyExp);
+ exp.setOperand(1, comparisonValue);
+ return exp;
+ } catch (ExpressionException e) {
+ LOGGER.warn(e.getUnlabeledMessage());
+ return null;
+ }
+ }
+}
diff --git a/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java b/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java
index eb1eb79e1..079ccf07b 100644
--- a/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java
+++ b/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java
@@ -263,7 +263,7 @@ public class EOModelProcessor {
// qualifiers
Map<String, ?> qualifierMap = (Map<String, ?>) plistMap.get("qualifier");
if (qualifierMap != null && !qualifierMap.isEmpty()) {
- descriptor.setQualifier(EOQuery.EOFetchSpecificationParser.makeQualifier((EOObjEntity) root, qualifierMap));
+ descriptor.setQualifier(EOFetchSpecificationParser.makeQualifier((EOObjEntity) root, qualifierMap));
}
// prefetches
diff --git a/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOObjEntity.java b/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOObjEntity.java
index 53cba8228..515e47bdf 100644
--- a/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOObjEntity.java
+++ b/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOObjEntity.java
@@ -83,7 +83,7 @@ public class EOObjEntity extends ObjEntity {
* @since 1.2
*/
// TODO: andrus, 5/27/2006 - make public after 1.2. Also maybe move entity
- // initialization code from EOModelProcessor to this class, kind of like EOQuery does.
+ // initialization code from EOModelProcessor to this class.
Map getEoMap() {
return eoMap;
}
@@ -92,7 +92,7 @@ public class EOObjEntity extends ObjEntity {
* @since 1.2
*/
// TODO: andrus, 5/27/2006 - make public after 1.2. Also maybe move entity
- // initialization code from EOModelProcessor to this class, kind of like EOQuery does.
+ // initialization code from EOModelProcessor to this class.
void setEoMap(Map eoMap) {
this.eoMap = eoMap;
}
diff --git a/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOQuery.java b/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOQuery.java
deleted file mode 100644
index 5fecd4bc6..000000000
--- a/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOQuery.java
+++ /dev/null
@@ -1,495 +0,0 @@
-/*****************************************************************
- * 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
- *
- * https://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.wocompat;
-
-import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.exp.ExpressionException;
-import org.apache.cayenne.exp.ExpressionFactory;
-import org.apache.cayenne.exp.ExpressionParameter;
-import org.apache.cayenne.exp.parser.ASTObjPath;
-import org.apache.cayenne.map.Entity;
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.ObjRelationship;
-import org.apache.cayenne.query.ObjectSelect;
-import org.apache.cayenne.query.PrefetchTreeNode;
-import org.apache.cayenne.query.SortOrder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A descriptor of SelectQuery loaded from EOModel. It is an informal
- * "decorator" of Cayenne SelectQuery to provide access to the extra information
- * of WebObjects EOFetchSpecification.
- *
- * @since 1.1
- * @since 5.0 this query extends {@link ObjectSelect}
- */
-@SuppressWarnings("unchecked")
-public class EOQuery<T> extends ObjectSelect<T> {
-
- protected Map<String, ?> plistMap;
- protected Map<String, String> bindings;
-
- public EOQuery(ObjEntity root, Map<String, ?> plistMap) {
- super();
- entityName(root.getName());
- setRoot(root);
- this.plistMap = plistMap;
- initFromPlist(plistMap);
- }
-
- protected void initFromPlist(Map<String, ?> plistMap) {
-
- if("YES".equalsIgnoreCase((String) plistMap.get("usesDistinct"))) {
- distinct();
- }
-
- Object fetchLimit = plistMap.get("fetchLimit");
- if (fetchLimit != null) {
- try {
- if (fetchLimit instanceof Number) {
- limit(((Number) fetchLimit).intValue());
- } else {
- limit(Integer.parseInt(fetchLimit.toString()));
- }
- } catch (NumberFormatException nfex) {
- // ignoring...
- }
- }
-
- // sort orderings
- List<Map<String, String>> orderings = (List<Map<String, String>>) plistMap.get("sortOrderings");
- if (orderings != null && !orderings.isEmpty()) {
- for (Map<String, String> ordering : orderings) {
- boolean asc = !"compareDescending:".equals(ordering.get("selectorName"));
- String key = ordering.get("key");
- if (key != null) {
- orderBy(key, asc ? SortOrder.ASCENDING : SortOrder.DESCENDING);
- }
- }
- }
-
- // qualifiers
- Map<String, ?> qualifierMap = (Map<String, ?>) plistMap.get("qualifier");
- if (qualifierMap != null && !qualifierMap.isEmpty()) {
- where(makeQualifier(qualifierMap));
- }
-
- // prefetches
- List<?> prefetches = (List<?>) plistMap.get("prefetchingRelationshipKeyPaths");
- if (prefetches != null && !prefetches.isEmpty()) {
- for (Object prefetch : prefetches) {
- prefetch((String) prefetch, PrefetchTreeNode.UNDEFINED_SEMANTICS);
- }
- }
-
- // data rows - note that we do not support fetching individual columns
- // in the
- // modeler...
- if (plistMap.containsKey("rawRowKeyPaths")) {
- fetchDataRows();
- }
- }
-
- public Collection<String> getBindingNames() {
- if (bindings == null) {
- initBindings();
- }
-
- return bindings.keySet();
- }
-
- public String bindingClass(String name) {
- if (bindings == null) {
- initBindings();
- }
-
- return bindings.get(name);
- }
-
- private synchronized void initBindings() {
- if (bindings != null) {
- return;
- }
-
- bindings = new HashMap<>();
-
- if (!(root instanceof Entity)) {
- return;
- }
-
- Map<String, ?> qualifier = (Map<String, ?>) plistMap.get("qualifier");
- initBindings(bindings, (Entity<?,?,?>) root, qualifier);
- }
-
- private void initBindings(Map<String,String> bindings, Entity<?,?,?> entity, Map<String, ?> qualifier) {
- if (qualifier == null) {
- return;
- }
-
- if ("EOKeyValueQualifier".equals(qualifier.get("class"))) {
- String key = (String) qualifier.get("key");
- if (key == null) {
- return;
- }
-
- Object value = qualifier.get("value");
- if (!(value instanceof Map)) {
- return;
- }
-
- Map<String, ?> valueMap = (Map<String, ?>) value;
- if (!"EOQualifierVariable".equals(valueMap.get("class")) || !valueMap.containsKey("_key")) {
- return;
- }
-
- String name = (String) valueMap.get("_key");
- String className = null;
-
- // we don't know whether its obj path or db path, so the expression
- // can blow
- // ... in fact we can't support DB Path as the key is different from
- // external
- // name,
- // so we will use Object type for all DB path...
- try {
- Object lastObject = new ASTObjPath(key).evaluate(entity);
-
- if (lastObject instanceof ObjAttribute) {
- className = ((ObjAttribute) lastObject).getType();
- } else if (lastObject instanceof ObjRelationship) {
- ObjEntity target = ((ObjRelationship) lastObject).getTargetEntity();
- if (target != null) {
- className = target.getClassName();
- }
- }
- } catch (ExpressionException ex) {
- className = "java.lang.Object";
- }
-
- if (className == null) {
- className = "java.lang.Object";
- }
-
- bindings.put(name, className);
-
- return;
- }
-
- List<Map<String, ?>> children = (List<Map<String, ?>>) qualifier.get("qualifiers");
- if (children != null) {
- for (Map<String, ?> child : children) {
- initBindings(bindings, entity, child);
- }
- }
- }
-
- /**
- * Creates the Expression equivalent of the EOFetchSpecification represented
- * by the Map.
- *
- * @param qualifierMap
- * - FetchSpecification to translate
- * @return Expression equivalent to FetchSpecification
- */
- public synchronized Expression makeQualifier(Map<String, ?> qualifierMap) {
- if (qualifierMap == null) {
- return null;
- }
-
- return EOFetchSpecificationParser.makeQualifier((EOObjEntity) getRoot(), qualifierMap);
- }
-
- /**
- * EOFetchSpecificationParser parses EOFetchSpecifications from a
- * WebObjects-style EOModel. It recursively builds Cayenne Expression
- * objects and assembles them into the final aggregate Expression.
- */
- static class EOFetchSpecificationParser {
-
- // Xcode/EOModeler expressions have a colon at the end of the selector
- // name
- // (just like standard Objective-C syntax). WOLips does not. Add both
- // sets to the hash map to handle both types of models.
-
- // Selector strings (Java-base).
- static final String IS_EQUAL_TO = "isEqualTo";
- static final String IS_NOT_EQUAL_TO = "isNotEqualTo";
- static final String IS_LIKE = "isLike";
- static final String CASE_INSENSITIVE_LIKE = "isCaseInsensitiveLike";
- static final String IS_LESS_THAN = "isLessThan";
- static final String IS_LESS_THAN_OR_EQUAL_TO = "isLessThanOrEqualTo";
- static final String IS_GREATER_THAN = "isGreaterThan";
- static final String IS_GREATER_THAN_OR_EQUAL_TO = "isGreaterThanOrEqualTo";
-
- private static final String OBJ_C = ":"; // Objective-C syntax addition.
-
- private static Map<String, Integer> selectorToExpressionBridge;
- private static final Logger LOGGER = LoggerFactory.getLogger(EOFetchSpecificationParser.class);
-
- /**
- * selectorToExpressionBridge is just a mapping of EOModeler's selector
- * types to Cayenne Expression types.
- *
- * @return HashMap of Expression types, keyed by the corresponding
- * selector name
- */
- static synchronized Map<String, Integer> selectorToExpressionBridge() {
- // Initialize selectorToExpressionBridge if needed.
- if (null == selectorToExpressionBridge) {
- selectorToExpressionBridge = new HashMap<>();
-
- selectorToExpressionBridge.put(IS_EQUAL_TO, Expression.EQUAL_TO);
- selectorToExpressionBridge.put(IS_EQUAL_TO + OBJ_C, Expression.EQUAL_TO);
-
- selectorToExpressionBridge.put(IS_NOT_EQUAL_TO, Expression.NOT_EQUAL_TO);
- selectorToExpressionBridge.put(IS_NOT_EQUAL_TO + OBJ_C, Expression.NOT_EQUAL_TO);
-
- selectorToExpressionBridge.put(IS_LIKE, Expression.LIKE);
- selectorToExpressionBridge.put(IS_LIKE + OBJ_C, Expression.LIKE);
-
- selectorToExpressionBridge.put(CASE_INSENSITIVE_LIKE, Expression.LIKE_IGNORE_CASE);
- selectorToExpressionBridge.put(CASE_INSENSITIVE_LIKE + OBJ_C, Expression.LIKE_IGNORE_CASE);
-
- selectorToExpressionBridge.put(IS_LESS_THAN, Expression.LESS_THAN);
- selectorToExpressionBridge.put(IS_LESS_THAN + OBJ_C, Expression.LESS_THAN);
-
- selectorToExpressionBridge.put(IS_LESS_THAN_OR_EQUAL_TO, Expression.LESS_THAN_EQUAL_TO);
- selectorToExpressionBridge.put(IS_LESS_THAN_OR_EQUAL_TO + OBJ_C, Expression.LESS_THAN_EQUAL_TO);
-
- selectorToExpressionBridge.put(IS_GREATER_THAN, Expression.GREATER_THAN);
- selectorToExpressionBridge.put(IS_GREATER_THAN + OBJ_C, Expression.GREATER_THAN);
-
- selectorToExpressionBridge.put(IS_GREATER_THAN_OR_EQUAL_TO, Expression.GREATER_THAN_EQUAL_TO);
- selectorToExpressionBridge.put(IS_GREATER_THAN_OR_EQUAL_TO + OBJ_C, Expression.GREATER_THAN_EQUAL_TO);
- }
-
- return selectorToExpressionBridge;
- }
-
- /**
- * isAggregate determines whether a qualifier is "aggregate" -- has
- * children -- or "simple".
- *
- * @param qualifier
- * - a Map containing the qualifier settings
- * @return boolean indicating whether the qualifier is "aggregate"
- * qualifier
- */
- static boolean isAggregate(Map<String, ?> qualifier) {
- boolean result = true;
-
- String theClass = (String) qualifier.get("class");
- if (theClass == null) {
- return false; // should maybe throw an exception?
- }
- if (theClass.equalsIgnoreCase("EOKeyValueQualifier")
- || theClass.equalsIgnoreCase("EOKeyComparisonQualifier")) {
- result = false;
- }
-
- return result;
- }
-
- /**
- * expressionTypeForQualifier looks at a qualifier containing the
- * EOModeler FetchSpecification and returns the equivalent Cayenne
- * Expression type for its selector.
- *
- * @param qualifierMap
- * - a Map containing the qualifier settings to examine.
- * @return int Expression type
- */
- static int expressionTypeForQualifier(Map<String, ?> qualifierMap) {
- // get selector
- String selector = (String) qualifierMap.get("selectorName");
- return expressionTypeForSelector(selector);
- }
-
- /**
- * expressionTypeForSelector looks at a selector from an EOModeler
- * FetchSpecification and returns the equivalent Cayenne Expression
- * type.
- *
- * @param selector
- * - a String containing the selector name.
- * @return int Expression type
- */
- static int expressionTypeForSelector(String selector) {
- Integer expType = selectorToExpressionBridge().get(selector);
- return (expType != null ? expType : -1);
- }
-
- /**
- * aggregateExpressionClassForQualifier looks at a qualifer and returns
- * the aggregate type: one of Expression.AND, Expression.OR, or
- * Expression.NOT
- *
- * @param qualifierMap
- * - containing the qualifier to examine
- * @return int aggregate Expression type
- */
- static int aggregateExpressionClassForQualifier(Map<String, ?> qualifierMap) {
- String qualifierClass = (String) qualifierMap.get("class");
- if (qualifierClass != null) {
- if (qualifierClass.equalsIgnoreCase("EOAndQualifier")) {
- return Expression.AND;
- } else if (qualifierClass.equalsIgnoreCase("EOOrQualifier")) {
- return Expression.OR;
- } else if (qualifierClass.equalsIgnoreCase("EONotQualifier")) {
- return Expression.NOT;
- }
- }
-
- return -1; // error
- }
-
- /**
- * makeQualifier recursively builds an Expression for each condition in
- * the qualifierMap and assembles from them the complex Expression to
- * represent the entire EOFetchSpecification.
- *
- * @param qualifierMap
- * - Map representation of EOFetchSpecification
- * @return Expression translation of the EOFetchSpecification
- */
- static Expression makeQualifier(EOObjEntity entity, Map<String, ?> qualifierMap) {
- if (isAggregate(qualifierMap)) {
- // the fetch specification has more than one qualifier
- int aggregateClass = aggregateExpressionClassForQualifier(qualifierMap); // AND,
- // OR,
- // NOT
-
- if (aggregateClass == Expression.NOT) {
- // NOT qualifiers only have one child, keyed with
- // "qualifier"
- Map<String, ?> child = (Map<String, ?>) qualifierMap.get("qualifier");
- // build the child expression
- Expression childExp = makeQualifier(entity, child);
-
- return childExp.notExp(); // add the "not" clause and return
- // the
- // result
- } else {
- // AND, OR qualifiers can have multiple children, keyed with
- // "qualifiers"
- // get the list of children
- List<Map<String, ?>> children = (List<Map<String, ?>>) qualifierMap.get("qualifiers");
- if (children != null) {
- ArrayList<Expression> childExpressions = new ArrayList<>();
- // build an Expression for each child
- for (Map<String, ?> child : children) {
- Expression childExp = makeQualifier(entity, child);
- childExpressions.add(childExp);
- }
- // join the child expressions and return the result
- return ExpressionFactory.joinExp(aggregateClass, childExpressions);
- }
- }
-
- } // end if isAggregate(qualifierMap)...
-
- // the query has a single qualifier
- // get expression selector type
- String qualifierClass = (String) qualifierMap.get("class");
-
- // the key or key path we're comparing
- String key = null;
- // the key, keyPath, value, or parameterized value against which
- // we're
- // comparing the key
- Object comparisonValue = null;
-
- if ("EOKeyComparisonQualifier".equals(qualifierClass)) {
- // Comparing two keys or key paths
- key = (String) qualifierMap.get("leftValue");
- comparisonValue = qualifierMap.get("rightValue");
- // FIXME: I think EOKeyComparisonQualifier style Expressions are not supported...
- return null;
- } else if ("EOKeyValueQualifier".equals(qualifierClass)) {
- // Comparing key with a value or parameterized value
- key = (String) qualifierMap.get("key");
- Object value = qualifierMap.get("value");
-
- if (value instanceof Map) {
- Map<String, String> valueMap = (Map<String, String>) value;
- String objClass = valueMap.get("class"); // can be a
- // qualifier class or java type
- if ("EOQualifierVariable".equals(objClass) && valueMap.containsKey("_key")) {
- // make a parameterized expression
- String paramName = valueMap.get("_key");
- comparisonValue = new ExpressionParameter(paramName);
- } else {
- Object queryVal = valueMap.get("value");
- if ("NSNumber".equals(objClass)) {
- // comparison to NSNumber -- cast
- comparisonValue = queryVal;
- } else if ("EONull".equals(objClass)) {
- // comparison to null
- comparisonValue = null;
- } else { // Could there be other types? boolean, date,
- // etc.???
- // no cast
- comparisonValue = queryVal;
- }
- }
-
- } else if (value instanceof String) {
- // value expression
- comparisonValue = value;
- } // end if (value instanceof Map) else...
- }
-
- // check whether the key is an object path; if at least one
- // component is not,
- // switch to db path..
-
- Expression keyExp = ExpressionFactory.exp(key);
- try {
- entity.lastPathComponent(keyExp, Collections.emptyMap());
- } catch (ExpressionException e) {
- try {
- keyExp = entity.translateToDbPath(keyExp);
- } catch (Exception dbpathEx) {
- LOGGER.warn("Couldn't find {} in {} in EOModel", keyExp, entity.getName());
- }
- }
-
- try {
- Expression exp = ExpressionFactory.expressionOfType(expressionTypeForQualifier(qualifierMap));
-
- exp.setOperand(0, keyExp);
- exp.setOperand(1, comparisonValue);
- return exp;
- } catch (ExpressionException e) {
- LOGGER.warn(e.getUnlabeledMessage());
- return null;
- }
- }
- }
-}
diff --git a/cayenne-wocompat/src/test/java/org/apache/cayenne/wocompat/EOQueryTest.java b/cayenne-wocompat/src/test/java/org/apache/cayenne/wocompat/EOFetchSpecificationParserTest.java
similarity index 55%
rename from cayenne-wocompat/src/test/java/org/apache/cayenne/wocompat/EOQueryTest.java
rename to cayenne-wocompat/src/test/java/org/apache/cayenne/wocompat/EOFetchSpecificationParserTest.java
index ab423976c..8761dd4cc 100644
--- a/cayenne-wocompat/src/test/java/org/apache/cayenne/wocompat/EOQueryTest.java
+++ b/cayenne-wocompat/src/test/java/org/apache/cayenne/wocompat/EOFetchSpecificationParserTest.java
@@ -20,48 +20,55 @@
package org.apache.cayenne.wocompat;
import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.QueryDescriptor;
+import org.apache.cayenne.map.SelectQueryDescriptor;
+import org.apache.cayenne.query.ObjectSelect;
+import org.apache.cayenne.query.Ordering;
import org.apache.cayenne.query.PrefetchTreeNode;
import org.junit.jupiter.api.Test;
import java.net.URL;
import java.util.Collection;
-import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
-public class EOQueryTest {
+public class EOFetchSpecificationParserTest {
@Test
- public void constructor() throws Exception {
+ public void loadedFetchSpecification() throws Exception {
URL url = getClass().getClassLoader().getResource("wotests/fetchspec.eomodeld/");
assertNotNull(url);
- EOModelProcessor processor = new EOModelProcessor();
- DataMap map = processor.loadEOModel(url);
+ DataMap map = new EOModelProcessor().loadEOModel(url);
- @SuppressWarnings("unchecked")
- Map<String, ?> fspecMap = (Map<String, ?>) PropertyListSerialization.propertyListFromStream(getClass()
- .getClassLoader()
- .getResourceAsStream("wotests/fetchspec.eomodeld/Entity1.fspec"));
- assertNotNull(fspecMap);
- assertNotNull(fspecMap.get("E1FS1"));
+ QueryDescriptor descriptor = map.getQueryDescriptor("Entity1_E1FS1");
+ assertNotNull(descriptor);
+ SelectQueryDescriptor selectDescriptor = assertInstanceOf(SelectQueryDescriptor.class, descriptor);
+ assertSame(map.getObjEntity("Entity1"), selectDescriptor.getRoot());
- @SuppressWarnings("unchecked")
- EOQuery query = new EOQuery(map.getObjEntity("Entity1"), (Map<String, ?>) fspecMap.get("E1FS1"));
-
- assertNotNull(query.getWhere());
+ assertNotNull(selectDescriptor.getQualifier());
assertEquals(
"(name = \"aa\") and (db:ID >= 7) and ((e2.name = \"bb\") or (db:e2.ID != 5))",
- query.getWhere().toString());
+ selectDescriptor.getQualifier().toString());
+
+ ObjectSelect<?> query = selectDescriptor.buildQuery();
assertNotNull(query.getPrefetches());
+ Collection<PrefetchTreeNode> prefetches = query.getPrefetches().getChildren();
+ assertEquals(1, prefetches.size());
+ assertEquals("e2", prefetches.iterator().next().getName());
- Collection children = query.getPrefetches().getChildren();
- assertEquals(1, children.size());
- assertEquals("e2", ((PrefetchTreeNode) children.iterator().next()).getName());
+ Collection<Ordering> orderings = query.getOrderings();
+ assertEquals(1, orderings.size());
+ Ordering ordering = orderings.iterator().next();
+ assertEquals("name", ordering.getSortSpecString());
+ assertFalse(ordering.isAscending());
assertTrue(query.isFetchingDataRows());
assertEquals(500, query.getLimit());