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 <[email protected]>
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());

Reply via email to