You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by an...@apache.org on 2010/03/10 20:12:06 UTC

svn commit: r921518 [1/2] - in /cayenne/sandbox/cayenne-gwt/src: main/java/org/apache/cayenne/gwt/client/ main/java/org/apache/cayenne/gwt/server/ main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/ main/resources/org/apache/cayenne/query/...

Author: andrey
Date: Wed Mar 10 19:12:05 2010
New Revision: 921518

URL: http://svn.apache.org/viewvc?rev=921518&view=rev
Log:
GenericResponse & sqltemplate support

Added:
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/QueryResponse.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/SerializationSupport.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/map/
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/map/SQLResult.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/AbstractQuery.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/BaseQueryMetadata.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/CapsStrategy.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/Ordering.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/ParameterizedQuery.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/PrefetchTreeNode.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QualifiedQuery.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/Query.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QueryCacheStrategy.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QueryMetadata.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/SQLTemplate.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/SQLTemplateMetadata.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/SelectQuery.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/SelectQueryMetadata.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/SortOrder.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/util/
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/util/GenericResponse.java
    cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/util/ListResponse.java
Modified:
    cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/CayenneService.java
    cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/CayenneServiceAsync.java
    cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/GWTDataContext.java
    cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/server/CayenneServiceImpl.java
    cayenne/sandbox/cayenne-gwt/src/test/java/org/apache/cayenne/gwt/test/client/GwtTestQuery.java

Modified: cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/CayenneService.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/CayenneService.java?rev=921518&r1=921517&r2=921518&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/CayenneService.java (original)
+++ cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/CayenneService.java Wed Mar 10 19:12:05 2010
@@ -20,6 +20,7 @@ package org.apache.cayenne.gwt.client;
 
 import java.util.List;
 
+import org.apache.cayenne.QueryResponse;
 import org.apache.cayenne.query.Query;
 
 import com.google.gwt.user.client.rpc.RemoteService;
@@ -36,4 +37,9 @@ public interface CayenneService extends 
      */
     @SuppressWarnings("unchecked")
     public List performQuery(Query query);
+    
+    /**
+     * Executes any kind of query providing the result in a form of QueryResponse.
+     */
+    QueryResponse performGenericQuery(Query query);
 }

Modified: cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/CayenneServiceAsync.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/CayenneServiceAsync.java?rev=921518&r1=921517&r2=921518&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/CayenneServiceAsync.java (original)
+++ cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/CayenneServiceAsync.java Wed Mar 10 19:12:05 2010
@@ -20,6 +20,7 @@ package org.apache.cayenne.gwt.client;
 
 import java.util.List;
 
+import org.apache.cayenne.QueryResponse;
 import org.apache.cayenne.query.Query;
 
 import com.google.gwt.user.client.rpc.AsyncCallback;
@@ -36,4 +37,9 @@ public interface CayenneServiceAsync {
     @SuppressWarnings("unchecked")
 	<T> void performQuery(Query query, AsyncCallback<List<T>> callback);
 
+    /**
+     * Executes any kind of query providing the result in a form of QueryResponse.
+     */
+	void performGenericQuery(Query query, AsyncCallback<QueryResponse> callback);
+
 }

Modified: cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/GWTDataContext.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/GWTDataContext.java?rev=921518&r1=921517&r2=921518&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/GWTDataContext.java (original)
+++ cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/client/GWTDataContext.java Wed Mar 10 19:12:05 2010
@@ -20,6 +20,7 @@ package org.apache.cayenne.gwt.client;
 
 import java.util.List;
 
+import org.apache.cayenne.QueryResponse;
 import org.apache.cayenne.query.Query;
 
 import com.google.gwt.core.client.GWT;
@@ -62,4 +63,11 @@ public class GWTDataContext {
 	public <T> void performQuery(Query query, AsyncCallback<List<T>> callback) {
 		getService().performQuery(query, callback);
 	}
+	
+	/**
+     * Executes any kind of query providing the result in a form of QueryResponse.
+     */
+	public void performGenericQuery(Query query, AsyncCallback<QueryResponse> callback) {
+		getService().performGenericQuery(query, callback);
+	}
 }

Modified: cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/server/CayenneServiceImpl.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/server/CayenneServiceImpl.java?rev=921518&r1=921517&r2=921518&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/server/CayenneServiceImpl.java (original)
+++ cayenne/sandbox/cayenne-gwt/src/main/java/org/apache/cayenne/gwt/server/CayenneServiceImpl.java Wed Mar 10 19:12:05 2010
@@ -22,6 +22,7 @@ import java.util.List;
 
 import org.apache.cayenne.BaseContext;
 import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.QueryResponse;
 import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.conf.WebApplicationContextFilter;
 import org.apache.cayenne.gwt.client.CayenneService;
@@ -55,4 +56,10 @@ public class CayenneServiceImpl extends 
 		ObjectContext context = getObjectContext();
 		return context.performQuery(query);
 	}
+
+	@Override
+	public QueryResponse performGenericQuery(Query query) {
+		ObjectContext context = getObjectContext();
+		return context.performGenericQuery(query);
+	}
 }

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/QueryResponse.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/QueryResponse.java?rev=921518&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/QueryResponse.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/QueryResponse.java Wed Mar 10 19:12:05 2010
@@ -0,0 +1,108 @@
+/*****************************************************************
+ *   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;
+
+import java.util.List;
+
+/**
+ * Represents a result of query execution. It potentially contain a mix of update counts
+ * and lists of selected values. Provides API somewhat similar to java.util.Iterator or
+ * java.sql.ResultSet for scanning through the individual results.
+ * <p>
+ * An example of iterating through a response:
+ * </p>
+ * 
+ * <pre>
+ * QueryResponse response = context.performGenericQuery(query);
+ * for (response.reset(); response.next();) {
+ *     if (response.isList()) {
+ *         List list = response.currentList();
+ *         // ...
+ *     }
+ *     else {
+ *         int[] updateCounts = response.currentUpdateCount();
+ *         // ...
+ *     }
+ * }
+ * </pre>
+ * 
+ * <p>
+ * In case the structure of the result is known, and only a single list or an update count
+ * is expected, there is a simpler API to access them:
+ * </p>
+ * 
+ * <pre>
+ * QueryResponse response = context.performGenericQuery(query);
+ * List list = response.firstList();
+ * int[] count = response.firstUpdateCount();
+ * </pre>
+ * 
+ * @since 1.2
+ */
+public interface QueryResponse {
+
+    /**
+     * Returns a number of results in the response.
+     */
+    int size();
+
+    /**
+     * Returns whether current iteration result is a list or an update count.
+     */
+    boolean isList();
+
+    /**
+     * Returns a List under the current iterator position. Use {@link #isList()} to check
+     * the result type before calling this method.
+     */
+    List<?> currentList();
+
+    /**
+     * Returns an update count under the current iterator position. Returned value is an
+     * int[] to accommodate batch queries. For a regular update result, the value will be
+     * an int[1]. Use {@link #isList()} to check the result type before calling this
+     * method.
+     */
+    int[] currentUpdateCount();
+
+    /**
+     * Rewinds response iterator to the next result, returning true if it is available.
+     */
+    boolean next();
+
+    /**
+     * Restarts response iterator.
+     */
+    void reset();
+
+    /**
+     * A utility method for quickly retrieving the first list in the response. Returns
+     * null if the query has no lists. Note that this method resets current iterator to an
+     * undefined state.
+     */
+    @SuppressWarnings("unchecked")
+    List firstList();
+
+    /**
+     * A utility method for quickly retrieving the first update count from the response.
+     * Note that this method resets current iterator to an undefined state.
+     */
+    int[] firstUpdateCount();
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/SerializationSupport.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/SerializationSupport.java?rev=921518&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/SerializationSupport.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/SerializationSupport.java Wed Mar 10 19:12:05 2010
@@ -0,0 +1,33 @@
+/*****************************************************************
+ *   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;
+
+import java.io.Serializable;
+
+import org.apache.cayenne.util.GenericResponse;
+
+/**
+ * This class is an evil hack for GWT serialization.
+ * Turns out if some type is not defined explicitly somewhere, it is not included to SerializationPolicy.
+ * Then it cannot serialize e.g. as part of collection. Currently we see this when serializing
+ * {@link GenericResponse} class
+ */
+class SerializationSupport implements Serializable {
+	int[] array;
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/map/SQLResult.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/map/SQLResult.java?rev=921518&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/map/SQLResult.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/map/SQLResult.java Wed Mar 10 19:12:05 2010
@@ -0,0 +1,79 @@
+/*****************************************************************
+ *   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.map;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A metadata object that defines how a row in a result set can be converted to result
+ * objects. SQLResult can be mapped to a single scalar, a single entity or a mix of
+ * scalars and entities that is represented as an Object[].
+ * 
+ * @since 3.0
+ */
+public class SQLResult implements Serializable {
+
+    protected String name;
+    protected List<Object> resultDescriptors;
+
+    /**
+     * Creates an unnamed SQLResultSet.
+     */
+    public SQLResult() {
+
+    }
+
+    /**
+     * Creates a named SQLResultSet.
+     */
+    public SQLResult(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Returns a list of "uncompiled" result descriptors. Column descriptors are returned
+     * as Strings, entity descriptors - as {@link EntityResult}. To get fully resolved
+     * descriptors, use {@link #getResolvedComponents(EntityResolver)}.
+     */
+    public List<Object> getComponents() {
+        return resultDescriptors != null ? resultDescriptors : Collections.EMPTY_LIST;
+    }
+
+    /**
+     * Adds a result set column name to the mapping.
+     */
+    public void addColumnResult(String column) {
+        if (resultDescriptors == null) {
+            resultDescriptors = new ArrayList<Object>(3);
+        }
+
+        resultDescriptors.add(column);
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/AbstractQuery.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/AbstractQuery.java?rev=921518&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/AbstractQuery.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/AbstractQuery.java Wed Mar 10 19:12:05 2010
@@ -0,0 +1,90 @@
+/*****************************************************************
+ *   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.query;
+
+import java.io.Serializable;
+
+
+/**
+ * A common superclass of Cayenne queries.
+ * 
+ */
+public abstract class AbstractQuery<T> implements Query, Serializable {
+
+    /**
+     * The root object this query. May be an entity name, Java class, ObjEntity or
+     * DbEntity, depending on the specific query and how it was constructed.
+     */
+    protected T root;
+    protected String name;
+
+    /**
+     * Returns a symbolic name of the query.
+     * 
+     * @since 1.1
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets a symbolic name of the query.
+     * 
+     * @since 1.1
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Returns the root of this query.
+     */
+    public Object getRoot() {
+        return root;
+    }
+
+    /**
+     * Sets the root of the query
+     * 
+     * @param value The new root
+     * @throws IllegalArgumentException if value is not a String, ObjEntity, DbEntity,
+     *             Procedure, DataMap, Class or null.
+     */
+    public void setRoot(Object value) {
+        if (value == null) {
+            this.root = null;
+        }
+
+        // sanity check
+        if (!((value instanceof String) || (value instanceof Class))) {
+
+            String rootClass = (value != null) ? value.getClass().getName() : "null";
+
+            throw new IllegalArgumentException(
+                    getClass().getName()
+                            + ": \"setRoot(..)\" takes a String "
+                            + "or Class. It was passed a "
+                            + rootClass);
+        }
+
+        this.root = (T) value;
+    }
+
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/BaseQueryMetadata.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/BaseQueryMetadata.java?rev=921518&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/BaseQueryMetadata.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/BaseQueryMetadata.java Wed Mar 10 19:12:05 2010
@@ -0,0 +1,367 @@
+/*****************************************************************
+ *   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.query;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ * Default mutable implementation of {@link QueryMetadata}.
+ * 
+ * @since 1.1
+ */
+class BaseQueryMetadata implements QueryMetadata, Serializable {
+
+    int fetchLimit = QueryMetadata.FETCH_LIMIT_DEFAULT;
+    int fetchOffset = QueryMetadata.FETCH_OFFSET_DEFAULT;
+    
+    int statementFetchSize = QueryMetadata.FETCH_OFFSET_DEFAULT;
+
+    int pageSize = QueryMetadata.PAGE_SIZE_DEFAULT;
+    boolean fetchingDataRows = QueryMetadata.FETCHING_DATA_ROWS_DEFAULT;
+    QueryCacheStrategy cacheStrategy = QueryCacheStrategy.getDefaultStrategy();
+
+    PrefetchTreeNode prefetchTree;
+    String cacheKey;
+    String[] cacheGroups;
+    
+    transient List<Object> resultSetMapping;
+    transient Object lastRoot;
+
+    /**
+     * Copies values of another QueryMetadata object to this object.
+     */
+    void copyFromInfo(QueryMetadata info) {
+        this.lastRoot = null;
+
+        this.fetchingDataRows = info.isFetchingDataRows();
+        this.fetchLimit = info.getFetchLimit();
+        this.pageSize = info.getPageSize();
+        this.cacheStrategy = info.getCacheStrategy();
+        this.cacheKey = info.getCacheKey();
+        this.resultSetMapping = info.getResultSetMapping();
+
+        setPrefetchTree(info.getPrefetchTree());
+    }
+
+    void initWithProperties(Map<String, ?> properties) {
+        // must init defaults even if properties are empty
+        if (properties == null) {
+            properties = Collections.EMPTY_MAP;
+        }
+
+        Object fetchOffset = properties.get(QueryMetadata.FETCH_OFFSET_PROPERTY);
+        Object fetchLimit = properties.get(QueryMetadata.FETCH_LIMIT_PROPERTY);
+        Object pageSize = properties.get(QueryMetadata.PAGE_SIZE_PROPERTY);
+        Object statementFetchSize = properties.get(QueryMetadata.STATEMENT_FETCH_SIZE_PROPERTY);
+        Object fetchingDataRows = properties
+                .get(QueryMetadata.FETCHING_DATA_ROWS_PROPERTY);
+
+        // deprecated cache policy... handle it for backwards compatibility.
+        Object cachePolicy = properties.get(QueryMetadata.CACHE_POLICY_PROPERTY);
+        Object cacheStrategy = properties.get(QueryMetadata.CACHE_STRATEGY_PROPERTY);
+
+        Object cacheGroups = properties.get(QueryMetadata.CACHE_GROUPS_PROPERTY);
+
+        // init ivars from properties
+        this.fetchOffset = (fetchOffset != null) ? Integer.parseInt(fetchOffset
+                .toString()) : QueryMetadata.FETCH_OFFSET_DEFAULT;
+
+        this.fetchLimit = (fetchLimit != null)
+                ? Integer.parseInt(fetchLimit.toString())
+                : QueryMetadata.FETCH_LIMIT_DEFAULT;
+
+        this.pageSize = (pageSize != null)
+                ? Integer.parseInt(pageSize.toString())
+                : QueryMetadata.PAGE_SIZE_DEFAULT;
+                
+        this.statementFetchSize = (statementFetchSize != null)
+                ? Integer.parseInt(statementFetchSize.toString())
+                : QueryMetadata.STATEMENT_FETCH_SIZE_DEFAULT;
+
+        this.fetchingDataRows = (fetchingDataRows != null)
+                ? "true".equalsIgnoreCase(fetchingDataRows.toString())
+                : QueryMetadata.FETCHING_DATA_ROWS_DEFAULT;
+
+        this.cacheStrategy = (cacheStrategy != null) ? QueryCacheStrategy
+                .safeValueOf(cacheStrategy.toString()) : QueryCacheStrategy
+                .getDefaultStrategy();
+
+        // use legacy cachePolicy if it is provided and no strategy is set...
+        if (cacheStrategy == null && cachePolicy != null) {
+            setCachePolicy(cachePolicy.toString());
+        }
+
+        this.cacheGroups = null;
+        if (cacheGroups instanceof String[]) {
+            this.cacheGroups = (String[]) cacheGroups;
+        }
+        else if (cacheGroups instanceof String) {
+            StringTokenizer toks = new StringTokenizer(cacheGroups.toString(), ",");
+            this.cacheGroups = new String[toks.countTokens()];
+            for (int i = 0; i < this.cacheGroups.length; i++) {
+                this.cacheGroups[i] = toks.nextToken();
+            }
+        }
+    }
+
+    /**
+     * @since 1.2
+     */
+    public String getCacheKey() {
+        return cacheKey;
+    }
+
+    /**
+     * @since 3.0
+     */
+    public Map<String, String> getPathSplitAliases() {
+        return Collections.emptyMap();
+    }
+
+    /**
+     * @since 3.0
+     */
+    public List<Object> getResultSetMapping() {
+        return resultSetMapping;
+    }
+
+    /**
+     * @since 1.2
+     */
+    public PrefetchTreeNode getPrefetchTree() {
+        return prefetchTree;
+    }
+
+    void setPrefetchTree(PrefetchTreeNode prefetchTree) {
+        this.prefetchTree = prefetchTree;
+    }
+
+    /**
+     * @deprecated since 3.0 {@link #getCacheStrategy()} replaces this method.
+     */
+    @Deprecated
+    public String getCachePolicy() {
+        if (cacheStrategy == null) {
+            return QueryMetadata.CACHE_POLICY_DEFAULT;
+        }
+
+        switch (cacheStrategy) {
+            case NO_CACHE:
+                return QueryMetadata.NO_CACHE;
+            case LOCAL_CACHE:
+                return QueryMetadata.LOCAL_CACHE;
+            case LOCAL_CACHE_REFRESH:
+                return QueryMetadata.LOCAL_CACHE_REFRESH;
+            case SHARED_CACHE:
+                return QueryMetadata.SHARED_CACHE;
+            case SHARED_CACHE_REFRESH:
+                return QueryMetadata.SHARED_CACHE_REFRESH;
+
+            default:
+                return QueryMetadata.CACHE_POLICY_DEFAULT;
+        }
+    }
+
+    /**
+     * @deprecated since 3.0 {@link #setCacheStrategy(QueryCacheStrategy)} replaces this
+     *             method.
+     */
+    @Deprecated
+    void setCachePolicy(String policy) {
+        if (policy == null) {
+            cacheStrategy = null;
+        }
+        else if (QueryMetadata.NO_CACHE.equals(policy)) {
+            cacheStrategy = QueryCacheStrategy.NO_CACHE;
+        }
+        else if (QueryMetadata.LOCAL_CACHE.equals(policy)) {
+            cacheStrategy = QueryCacheStrategy.LOCAL_CACHE;
+        }
+        else if (QueryMetadata.LOCAL_CACHE_REFRESH.equals(policy)) {
+            cacheStrategy = QueryCacheStrategy.LOCAL_CACHE_REFRESH;
+        }
+        else if (QueryMetadata.SHARED_CACHE.equals(policy)) {
+            cacheStrategy = QueryCacheStrategy.SHARED_CACHE;
+        }
+        else if (QueryMetadata.SHARED_CACHE_REFRESH.equals(policy)) {
+            cacheStrategy = QueryCacheStrategy.SHARED_CACHE_REFRESH;
+        }
+        else {
+            cacheStrategy = QueryCacheStrategy.NO_CACHE;
+        }
+    }
+
+    /**
+     * @since 3.0
+     */
+    public QueryCacheStrategy getCacheStrategy() {
+        return cacheStrategy;
+    }
+
+    /**
+     * @since 3.0
+     */
+    void setCacheStrategy(QueryCacheStrategy cacheStrategy) {
+        this.cacheStrategy = cacheStrategy;
+    }
+
+    /**
+     * @since 3.0
+     */
+    public String[] getCacheGroups() {
+        return cacheGroups;
+    }
+
+    /**
+     * @since 3.0
+     */
+    void setCacheGroups(String... groups) {
+        this.cacheGroups = groups;
+    }
+
+    public boolean isFetchingDataRows() {
+        return fetchingDataRows;
+    }
+
+    public int getFetchLimit() {
+        return fetchLimit;
+    }
+
+    public int getPageSize() {
+        return pageSize;
+    }
+
+    public Query getOrginatingQuery() {
+        return null;
+    }
+
+    /**
+     * @since 3.0
+     */
+    public int getFetchOffset() {
+        return fetchOffset;
+    }
+
+    /**
+     * @deprecated since 3.0
+     */
+    @Deprecated
+    public int getFetchStartIndex() {
+        return getFetchOffset();
+    }
+
+    public boolean isRefreshingObjects() {
+        return true;
+    }
+
+    /**
+     * @deprecated since 3.0. Inheritance resolving is not optional anymore.
+     */
+    @Deprecated
+    public boolean isResolvingInherited() {
+        return true;
+    }
+
+    void setFetchingDataRows(boolean b) {
+        fetchingDataRows = b;
+    }
+
+    void setFetchLimit(int i) {
+        fetchLimit = i;
+    }
+
+    void setFetchOffset(int i) {
+        fetchOffset = i;
+    }
+
+    void setPageSize(int i) {
+        pageSize = i;
+    }
+    
+    /**
+     * Sets statement's fetch size (0 for no default size)
+     * @since 3.0 
+     */
+    void setStatementFetchSize(int size) {
+        this.statementFetchSize = size;
+    }
+    
+    /**
+     * @return statement's fetch size
+     * @since 3.0
+     */
+    public int getStatementFetchSize() {
+        return statementFetchSize;
+    }
+
+    /**
+     * Adds a joint prefetch.
+     * 
+     * @since 1.2
+     */
+    PrefetchTreeNode addPrefetch(String path, int semantics) {
+        if (prefetchTree == null) {
+            prefetchTree = new PrefetchTreeNode();
+        }
+
+        PrefetchTreeNode node = prefetchTree.addPath(path);
+        node.setSemantics(semantics);
+        node.setPhantom(false);
+        return node;
+    }
+
+    /**
+     * Adds all prefetches from a provided collection.
+     * 
+     * @since 1.2
+     */
+    void addPrefetches(Collection<String> prefetches, int semantics) {
+        if (prefetches != null) {
+            for (String prefetch : prefetches) {
+                addPrefetch(prefetch, semantics);
+            }
+        }
+    }
+
+    /**
+     * Clears all joint prefetches.
+     * 
+     * @since 1.2
+     */
+    void clearPrefetches() {
+        prefetchTree = null;
+    }
+
+    /**
+     * Removes joint prefetch.
+     * 
+     * @since 1.2
+     */
+    void removePrefetch(String prefetch) {
+        if (prefetchTree != null) {
+            prefetchTree.removePath(prefetch);
+        }
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/CapsStrategy.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/CapsStrategy.java?rev=921518&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/CapsStrategy.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/CapsStrategy.java Wed Mar 10 19:12:05 2010
@@ -0,0 +1,28 @@
+/*****************************************************************
+ *   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.query;
+
+/**
+ * Defines forced capitalization of the result column names in the DataRow.
+ * 
+ * @since 3.0
+ */
+public enum CapsStrategy {
+    DEFAULT, UPPER, LOWER
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/Ordering.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/Ordering.java?rev=921518&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/Ordering.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/Ordering.java Wed Mar 10 19:12:05 2010
@@ -0,0 +1,258 @@
+/*****************************************************************
+ *   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.query;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cayenne.util.Util;
+
+/**
+ * Defines object sorting criteria, used either for in-memory sorting of object lists or
+ * as a specification for building <em>ORDER BY</em> clause of a SelectQuery query. Note
+ * that in case of in-memory sorting, Ordering can be used with any JavaBeans, not just
+ * DataObjects.
+ */
+public class Ordering implements Serializable {
+    /**
+     * Symbolic representation of ascending ordering criterion.
+     * 
+     * @deprecated Use SortOrder.ASCENDING instead.
+     */
+    @Deprecated
+    public static final boolean ASC = true;
+
+    /**
+     * Symbolic representation of descending ordering criterion.
+     * 
+     * @deprecated Use SortOrder.DESCENDING instead.
+     */
+    @Deprecated
+    public static final boolean DESC = false;
+
+    protected String sortSpecString;
+    protected SortOrder sortOrder;
+//    protected boolean ascending;
+//    protected boolean caseInsensitive;
+    protected boolean pathExceptionSuppressed = false;
+    protected boolean nullSortedFirst = true;
+
+    public Ordering() {
+    }
+
+    @Deprecated
+    public Ordering(String sortPathSpec, boolean ascending) {
+        this(sortPathSpec, ascending, false);
+    }
+
+    /**
+     * @since 3.0
+     */
+    public Ordering(String sortPathSpec, SortOrder sortOrder) {
+        setSortSpecString(sortPathSpec);
+        setSortOrder(sortOrder);
+    }
+
+    @Deprecated
+    public Ordering(String sortPathSpec, boolean ascending, boolean caseInsensitive) {
+        setSortSpecString(sortPathSpec);
+        setAscending(ascending);
+        setCaseInsensitive(caseInsensitive);
+//        this.ascending = ascending;
+//        this.caseInsensitive = caseInsensitive;
+    }
+
+    /**
+     * Sets sortSpec to be an expression represented by string argument.
+     * 
+     * @since 1.1
+     */
+    public void setSortSpecString(String sortSpecString) {
+        if (!Util.nullSafeEquals(this.sortSpecString, sortSpecString)) {
+            this.sortSpecString = sortSpecString;
+        }
+    }
+     
+    /**
+     * Sets sort order for whether nulls are at the top or bottom of the resulting list. Default is true.
+     * 
+     * @param nullSortedFirst true sorts nulls to the top of the list, false sorts nulls to the bottom
+     */
+    public void setNullSortedFirst(boolean nullSortedFirst) {
+        this.nullSortedFirst = nullSortedFirst;
+    }
+    
+    /** 
+     * Get sort order for nulls.
+     * 
+     *  @return true if nulls are sorted to the top of the list, false if sorted to the bottom
+     */
+    public boolean isNullSortedFirst() {
+        return nullSortedFirst;
+    }
+    
+    /**
+     * Sets whether a path with a null in the middle is ignored. For example, a sort from <code>painting</code>
+     * on <code>artist.name</code> would by default throw an exception if the artist was null.
+     * If set to true, then this is treated just like a null value.
+     * Default is false.
+     * 
+     * @param pathExceptionSuppressed true to suppress exceptions and sort as null
+     */
+    public void setPathExceptionSupressed(boolean pathExceptionSuppressed) {
+        this.pathExceptionSuppressed = pathExceptionSuppressed;
+    }
+    
+    /** 
+     * Is a path with a null in the middle is ignored.
+     * 
+     * @return true is exception is suppressed and sorted as null
+     */
+    public boolean isPathExceptionSuppressed() {
+        return pathExceptionSuppressed;
+    }
+    
+    
+    /**
+     * Returns sortSpec string representation.
+     * 
+     * @since 1.1
+     */
+    public String getSortSpecString() {
+        return sortSpecString;
+    }
+
+    /**
+     * Sets the sort order for this ordering.
+     * 
+     * @since 3.0
+     */
+    public void setSortOrder(SortOrder order) {
+        this.sortOrder = order;
+    }
+
+    /** Returns true if sorting is done in ascending order. */
+    public boolean isAscending() {
+        return sortOrder == null || sortOrder == SortOrder.ASCENDING || sortOrder == SortOrder.ASCENDING_INSENSITIVE;
+    }
+
+    /**
+     * Returns true if the sorting is done in descending order.
+     * 
+     * @since 3.0
+     */
+    public boolean isDescending() {
+        return !isAscending();
+    }
+
+    /**
+     * Sets <code>ascending</code> property of this Ordering.
+     * 
+     * @deprecated Use setSortOrder() or setAscending() or setDescending().
+     */
+    @Deprecated
+    public void setAscending(boolean ascending) {
+        if (ascending)
+            setAscending();
+        else
+            setDescending();
+    }
+
+    /**
+     * If the sort order is DESCENDING or DESCENDING_INSENSITIVE, sets
+     * the sort order to ASCENDING or ASCENDING_INSENSITIVE, respectively.
+     * 
+     * @since 3.0
+     */
+    public void setAscending() {
+        if (sortOrder == null || sortOrder == SortOrder.DESCENDING)
+            setSortOrder(SortOrder.ASCENDING);
+        else if (sortOrder == SortOrder.DESCENDING_INSENSITIVE)
+            setSortOrder(SortOrder.ASCENDING_INSENSITIVE);
+    }
+
+    /**
+     * If the sort order is ASCENDING or ASCENDING_INSENSITIVE, sets
+     * the sort order to DESCENDING or DESCENDING_INSENSITIVE, respectively.
+     * 
+     * @since 3.0
+     */
+    public void setDescending() {
+        if (sortOrder == null || sortOrder == SortOrder.ASCENDING)
+            setSortOrder(SortOrder.DESCENDING);
+        else if (sortOrder == SortOrder.ASCENDING_INSENSITIVE)
+            setSortOrder(SortOrder.DESCENDING_INSENSITIVE);
+    }
+
+    /** Returns true if the sorting is case insensitive */
+    public boolean isCaseInsensitive() {
+        return !isCaseSensitive();
+    }
+
+    /**
+     * Returns true if the sorting is case sensitive.
+     * 
+     * @since 3.0
+     */
+    public boolean isCaseSensitive() {
+        return sortOrder == null || sortOrder == SortOrder.ASCENDING || sortOrder == SortOrder.DESCENDING;
+    }
+
+    /**
+     * Sets <code>caseInsensitive</code> property of this Ordering.
+     * 
+     * @deprecated Use setSortOrder() or setCaseInsensitive() or setCaseSensitive().
+     */
+    @Deprecated
+    public void setCaseInsensitive(boolean caseInsensitive) {
+        if (caseInsensitive)
+            setCaseInsensitive();
+        else
+            setCaseSensitive();
+    }
+
+    /**
+     * If the sort order is ASCENDING or DESCENDING, sets the sort order to
+     * ASCENDING_INSENSITIVE or DESCENDING_INSENSITIVE, respectively.
+     * 
+     * @since 3.0
+     */
+    public void setCaseInsensitive() {
+        if (sortOrder == null || sortOrder == SortOrder.ASCENDING)
+            setSortOrder(SortOrder.ASCENDING_INSENSITIVE);
+        else if (sortOrder == SortOrder.DESCENDING)
+            setSortOrder(SortOrder.DESCENDING_INSENSITIVE);
+    }
+
+    /**
+     * If the sort order is ASCENDING_INSENSITIVE or DESCENDING_INSENSITIVE,
+     * sets the sort order to ASCENDING or DESCENDING, respectively.
+     * 
+     * @since 3.0
+     */
+    public void setCaseSensitive() {
+        if (sortOrder == null || sortOrder == SortOrder.ASCENDING_INSENSITIVE)
+            setSortOrder(SortOrder.ASCENDING);
+        else if (sortOrder == SortOrder.DESCENDING_INSENSITIVE)
+            setSortOrder(SortOrder.DESCENDING);
+    }
+
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/ParameterizedQuery.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/ParameterizedQuery.java?rev=921518&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/ParameterizedQuery.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/ParameterizedQuery.java Wed Mar 10 19:12:05 2010
@@ -0,0 +1,39 @@
+/*****************************************************************
+ *   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.query;
+
+import java.util.Map;
+
+/**
+ * Defines a query that can serve as a template for other queries. ParameterizedQuery
+ * interface is used mainly in DataContext convenience methods, simplifying execution of
+ * the mapped queries.
+ * 
+ * @since 1.1
+ */
+public interface ParameterizedQuery extends Query {
+
+    /**
+     * Creates a new query based on current query as a template, and using a Map of named
+     * parameters. In case of select queries, it is up to the implementing query to name
+     * the new query to avoid cache key conflicts.
+     */
+    Query createQuery(Map<String, ?> parameters);
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/PrefetchTreeNode.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/PrefetchTreeNode.java?rev=921518&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/PrefetchTreeNode.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/PrefetchTreeNode.java Wed Mar 10 19:12:05 2010
@@ -0,0 +1,287 @@
+/*****************************************************************
+ *   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.query;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.StringTokenizer;
+
+import org.apache.cayenne.util.Util;
+
+/**
+ * Defines a node in a prefetch tree.
+ * 
+ * @since 1.2
+ */
+public class PrefetchTreeNode implements Serializable {
+
+    public static final int UNDEFINED_SEMANTICS = 0;
+    public static final int JOINT_PREFETCH_SEMANTICS = 1;
+    public static final int DISJOINT_PREFETCH_SEMANTICS = 2;
+
+    protected String name;
+    protected boolean phantom;
+    protected int semantics;
+    protected String ejbqlPathEntityId;
+    protected String entityName;
+
+    // transient parent allows cloning parts of the tree via serialization
+    protected transient PrefetchTreeNode parent;
+
+    // Using Collection instead of Map for children storage (even though there cases of
+    // lookup by segment) is a reasonable tradeoff considering that
+    // each node has no more than a few children and lookup by name doesn't happen on
+    // traversal, only during creation.
+    protected Collection<PrefetchTreeNode> children;
+
+    /**
+     * Creates a root node of the prefetch tree. Children can be added to the parent by
+     * calling "addPath".
+     */
+    public PrefetchTreeNode() {
+        this(null, null);
+    }
+
+    /**
+     * Creates a phantom PrefetchTreeNode, initializing it with parent node and a name of
+     * a relationship segment connecting this node with the parent.
+     */
+    protected PrefetchTreeNode(PrefetchTreeNode parent, String segmentPath) {
+        this.parent = parent;
+        this.name = segmentPath;
+        this.phantom = true;
+        this.semantics = UNDEFINED_SEMANTICS;
+    }
+
+    /**
+     * Returns the root of the node tree. Root is the topmost parent node that itself has
+     * no parent set.
+     */
+    public PrefetchTreeNode getRoot() {
+        return (parent != null) ? parent.getRoot() : this;
+    }
+
+    /**
+     * Returns full prefetch path, that is a dot separated String of node names starting
+     * from root and up to and including this node. Note that root "name" is considered to
+     * be an empty string.
+     */
+    public String getPath() {
+        return getPath(null);
+    }
+
+    public String getPath(PrefetchTreeNode upTillParent) {
+        if (parent == null || upTillParent == this) {
+            return "";
+        }
+
+        StringBuilder path = new StringBuilder(getName());
+        PrefetchTreeNode node = this.getParent();
+
+        // root node has no path
+        while (node.getParent() != null && node != upTillParent) {
+            path.insert(0, node.getName() + ".");
+            node = node.getParent();
+        }
+
+        return path.toString();
+    }
+    
+    /**
+     * Looks up an existing node in the tree desribed by the dot-separated path. Will
+     * return null if no matching child exists.
+     */
+    public PrefetchTreeNode getNode(String path) {
+        if (Util.isEmptyString(path)) {
+            throw new IllegalArgumentException("Empty path: " + path);
+        }
+
+        PrefetchTreeNode node = this;
+        StringTokenizer toks = new StringTokenizer(path, ".");
+        while (toks.hasMoreTokens() && node != null) {
+            String segment = toks.nextToken();
+            node = node.getChild(segment);
+        }
+
+        return node;
+    }
+
+    /**
+     * Adds a "path" with specified semantics to this prefetch node. All yet non-existent
+     * nodes in the created path will be marked as phantom.
+     * 
+     * @return the last segment in the created path.
+     */
+    public PrefetchTreeNode addPath(String path) {
+        if (Util.isEmptyString(path)) {
+            throw new IllegalArgumentException("Empty path: " + path);
+        }
+
+        PrefetchTreeNode node = this;
+        StringTokenizer toks = new StringTokenizer(path, ".");
+        while (toks.hasMoreTokens()) {
+            String segment = toks.nextToken();
+
+            PrefetchTreeNode child = node.getChild(segment);
+            if (child == null) {
+                child = new PrefetchTreeNode(node, segment);
+                node.addChild(child);
+            }
+
+            node = child;
+        }
+
+        return node;
+    }
+
+    /**
+     * Removes or makes phantom a node defined by this path. If the node for this path
+     * doesn't have any children, it is removed, otherwise it is made phantom.
+     */
+    public void removePath(String path) {
+
+        PrefetchTreeNode node = getNode(path);
+        while (node != null) {
+
+            if (node.children != null) {
+                node.setPhantom(true);
+                break;
+            }
+
+            String segment = node.getName();
+
+            node = node.getParent();
+
+            if (node != null) {
+                node.removeChild(segment);
+            }
+        }
+    }
+
+    public void addChild(PrefetchTreeNode child) {
+
+        if (Util.isEmptyString(child.getName())) {
+            throw new IllegalArgumentException("Child has no segmentPath: " + child);
+        }
+
+        if (child.getParent() != this) {
+            child.getParent().removeChild(child.getName());
+            child.parent = this;
+        }
+
+        if (children == null) {
+            children = new ArrayList<PrefetchTreeNode>(4);
+        }
+
+        children.add(child);
+    }
+
+    public void removeChild(PrefetchTreeNode child) {
+        if (children != null && child != null) {
+            children.remove(child);
+            child.parent = null;
+        }
+    }
+
+    protected void removeChild(String segment) {
+        if (children != null) {
+            PrefetchTreeNode child = getChild(segment);
+            if (child != null) {
+                children.remove(child);
+                child.parent = null;
+            }
+        }
+    }
+
+    protected PrefetchTreeNode getChild(String segment) {
+        if (children != null) {
+            for (PrefetchTreeNode child : children) {
+                if (segment.equals(child.getName())) {
+                    return child;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public PrefetchTreeNode getParent() {
+        return parent;
+    }
+
+    /**
+     * Returns an unmodifiable collection of children.
+     */
+    public Collection<PrefetchTreeNode> getChildren() {
+        return children == null ? Collections.EMPTY_SET : Collections
+                .unmodifiableCollection(children);
+    }
+
+    public boolean hasChildren() {
+        return children != null && !children.isEmpty();
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public boolean isPhantom() {
+        return phantom;
+    }
+
+    public void setPhantom(boolean phantom) {
+        this.phantom = phantom;
+    }
+
+    public int getSemantics() {
+        return semantics;
+    }
+
+    public void setSemantics(int semantics) {
+        this.semantics = semantics;
+    }
+
+    public boolean isJointPrefetch() {
+        return semantics == JOINT_PREFETCH_SEMANTICS;
+    }
+
+    public boolean isDisjointPrefetch() {
+        return semantics == DISJOINT_PREFETCH_SEMANTICS;
+    }
+    
+    public String getEjbqlPathEntityId() {
+        return ejbqlPathEntityId;
+    }
+
+    public void setEjbqlPathEntityId(String ejbqlPathEntityId) {
+        this.ejbqlPathEntityId = ejbqlPathEntityId;
+    }
+
+    public String getEntityName() {
+        return entityName;
+    }
+    
+    public void setEntityName(String entityName) {
+        this.entityName = entityName;
+    }
+
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QualifiedQuery.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QualifiedQuery.java?rev=921518&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QualifiedQuery.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QualifiedQuery.java Wed Mar 10 19:12:05 2010
@@ -0,0 +1,59 @@
+/*****************************************************************
+ *   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.query;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * An abstract superclass of queries with Expression qualifiers.
+ * 
+ */
+public abstract class QualifiedQuery extends AbstractQuery {
+
+    protected Expression qualifier;
+
+    /**
+     * Sets new query qualifier.
+     */
+    public void setQualifier(Expression qualifier) {
+        this.qualifier = qualifier;
+    }
+
+    /**
+     * Returns query qualifier.
+     */
+    public Expression getQualifier() {
+        return qualifier;
+    }
+
+    /**
+     * Adds specified qualifier to the existing qualifier joining it using "AND".
+     */
+    public void andQualifier(Expression e) {
+        qualifier = (qualifier != null) ? qualifier.andExp(e) : e;
+    }
+
+    /**
+     * Adds specified qualifier to the existing qualifier joining it using "OR".
+     */
+    public void orQualifier(Expression e) {
+        qualifier = (qualifier != null) ? qualifier.orExp(e) : e;
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/Query.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/Query.java?rev=921518&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/Query.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/Query.java Wed Mar 10 19:12:05 2010
@@ -0,0 +1,38 @@
+/*****************************************************************
+ *   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.query;
+
+import java.io.Serializable;
+
+/**
+ * Defines minimal API of a query descriptor that is executable via Cayenne.
+ * 
+ */
+public interface Query extends Serializable {
+
+    /**
+     * Returns a symbolic name of the query. The name may be used as a key to find queries
+     * stored in the DataMap. Some query implementors reuse the name as a QueryMetadata
+     * cache key. Generally the name can be null.
+     * 
+     * @since 1.1
+     */
+    String getName();
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QueryCacheStrategy.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QueryCacheStrategy.java?rev=921518&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QueryCacheStrategy.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QueryCacheStrategy.java Wed Mar 10 19:12:05 2010
@@ -0,0 +1,79 @@
+/*****************************************************************
+ *   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.query;
+
+/**
+ * Defines query result caching policy.
+ * 
+ * @since 3.0
+ */
+public enum QueryCacheStrategy {
+
+    /**
+     * A default cache policy stating that the query results should not be cached.
+     */
+    NO_CACHE,
+
+    /**
+     * A cache policy stating that query results shall be cached by the ObjectContext that
+     * originated the query, independent from any other ObjectContexts.
+     */
+    LOCAL_CACHE,
+
+    /**
+     * A cache policy stating that query results shall be cached by the ObjectContext that
+     * originated the query, independent from any other ObjectContexts, however the query
+     * that uses this policy should treat current cache state as expired, and force the
+     * database fetch.
+     */
+    LOCAL_CACHE_REFRESH,
+
+    /**
+     * A cache policy ruling that query results shall be cached in a shared location
+     * accessible by all ObjectContexts.
+     */
+    SHARED_CACHE,
+
+    /**
+     * A cache policy ruling that query results shall be cached in a shared location
+     * accessible by all ObjectContexts, however the query that uses this policy should
+     * treat current cache state as expired, and force the database fetch.
+     */
+    SHARED_CACHE_REFRESH;
+
+    /**
+     * Returns QueryCacheStrategy for the specified string name or default strategy for
+     * invalid names.
+     */
+    public static QueryCacheStrategy safeValueOf(String string) {
+        try {
+            return QueryCacheStrategy.valueOf(string);
+        }
+        catch (IllegalArgumentException e) {
+            return getDefaultStrategy();
+        }
+    }
+
+    /**
+     * Returns the default strategy - {@link #NO_CACHE}.
+     */
+    public static QueryCacheStrategy getDefaultStrategy() {
+        return NO_CACHE;
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QueryMetadata.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QueryMetadata.java?rev=921518&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QueryMetadata.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/query/QueryMetadata.java Wed Mar 10 19:12:05 2010
@@ -0,0 +1,305 @@
+/*****************************************************************
+ *   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.query;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provides a common interface for accessing query metadata.
+ * 
+ * @since 1.2
+ */
+public interface QueryMetadata {
+
+    /**
+     * A cache policy that disables caching of query results.
+     * 
+     * @deprecated since 3.0 use {@link QueryCacheStrategy} enum.
+     */
+    @Deprecated
+    public static final String NO_CACHE = "nocache";
+
+    /**
+     * A cache policy ruling that query results shall be cached separately for each
+     * DataContext.
+     * 
+     * @deprecated since 3.0 use {@link QueryCacheStrategy} enum.
+     */
+    @Deprecated
+    public static final String LOCAL_CACHE = "localcache";
+
+    /**
+     * Same as {@link #LOCAL_CACHE}, only forcing any current cache expiration.
+     * 
+     * @deprecated since 3.0 use {@link QueryCacheStrategy} enum.
+     */
+    @Deprecated
+    public static final String LOCAL_CACHE_REFRESH = "localcache_refresh";
+
+    /**
+     * A cache policy ruling that query results shall be stored in a shared cache
+     * accessible by all DataContexts.
+     * 
+     * @deprecated since 3.0 use {@link QueryCacheStrategy} enum.
+     */
+    @Deprecated
+    public static final String SHARED_CACHE = "sharedcache";
+
+    /**
+     * Same as {@link #SHARED_CACHE}, only forcing any current cache expiration.
+     * 
+     * @deprecated since 3.0 use {@link QueryCacheStrategy} enum.
+     */
+    @Deprecated
+    public static final String SHARED_CACHE_REFRESH = "sharedcache_refresh";
+
+    /**
+     * Defines the name of the property for the query {@link #getFetchLimit() fetch limit}
+     * .
+     */
+    public static final String FETCH_LIMIT_PROPERTY = "cayenne.GenericSelectQuery.fetchLimit";
+
+    /**
+     * Defines default query fetch limit, which is zero, meaning that all matching rows
+     * should be fetched.
+     */
+    public static final int FETCH_LIMIT_DEFAULT = 0;
+
+    /**
+     * Defines the name of the property for the query {@link #getFetchOffset() fetch
+     * offset}.
+     * 
+     * @since 3.0
+     */
+    public static final String FETCH_OFFSET_PROPERTY = "cayenne.GenericSelectQuery.fetchOffset";
+
+    /**
+     * Defines default query fetch start index, which is 0, meaning that matching rows
+     * selected starting from the first.
+     * 
+     * @since 3.0
+     */
+    public static final int FETCH_OFFSET_DEFAULT = 0;
+
+    /**
+     * Defines the name of the property for the query {@link #getPageSize() page size}.
+     */
+    public static final String PAGE_SIZE_PROPERTY = "cayenne.GenericSelectQuery.pageSize";
+
+    /**
+     * Defines default query page size, which is zero for no pagination.
+     */
+    public static final int PAGE_SIZE_DEFAULT = 0;
+
+    public static final String FETCHING_DATA_ROWS_PROPERTY = "cayenne.GenericSelectQuery.fetchingDataRows";
+
+    public static final boolean FETCHING_DATA_ROWS_DEFAULT = false;
+
+    /**
+     * @deprecated since 3.0
+     */
+    @Deprecated
+    public static final String REFRESHING_OBJECTS_PROPERTY = "cayenne.GenericSelectQuery.refreshingObjects";
+
+    /**
+     * @deprecated since 3.0
+     */
+    @Deprecated
+    public static final boolean REFRESHING_OBJECTS_DEFAULT = true;
+
+    /**
+     * @deprecated since 3.0. Inheritance resolving is not optional anymore.
+     */
+    @Deprecated
+    public static final String RESOLVING_INHERITED_PROPERTY = "cayenne.GenericSelectQuery.resolvingInherited";
+
+    /**
+     * @deprecated since 3.0. Inheritance resolving is not optional anymore.
+     */
+    @Deprecated
+    public static final boolean RESOLVING_INHERITED_DEFAULT = true;
+
+    /**
+     * @deprecated since 3.0 use {@value #CACHE_STRATEGY_PROPERTY}
+     */
+    @Deprecated
+    public static final String CACHE_POLICY_PROPERTY = "cayenne.GenericSelectQuery.cachePolicy";
+
+    /**
+     * @since 3.0
+     */
+    public static final String CACHE_STRATEGY_PROPERTY = "cayenne.GenericSelectQuery.cacheStrategy";
+
+    /**
+     * @since 3.0
+     */
+    public static final String CACHE_GROUPS_PROPERTY = "cayenne.GenericSelectQuery.cacheGroups";
+
+    /**
+     * @deprecated since 3.0 use {@link QueryCacheStrategy} enum.
+     */
+    @Deprecated
+    public static final String CACHE_POLICY_DEFAULT = NO_CACHE;
+    
+    /**
+     * Defines the name of the property for the query {@link #getStatementFetchSize() fetch
+     * size}.
+     * 
+     * @since 3.0
+     */
+    public static final String STATEMENT_FETCH_SIZE_PROPERTY = "cayenne.GenericSelectQuery.statementFetchSize";
+
+    /**
+     * Defines default query fetch start index, which is 0, meaning that matching rows
+     * selected starting from the first.
+     * 
+     * @since 3.0
+     */
+    public static final int STATEMENT_FETCH_SIZE_DEFAULT = 0;
+
+    /**
+     * Returns query cache policy, which can be one of {@link #NO_CACHE},
+     * {@link #LOCAL_CACHE}, or {@link #SHARED_CACHE}. NO_CACHE is generally a default
+     * policy.
+     * 
+     * @deprecated since 3.0 {@link #getCacheStrategy()} replaces this method.
+     */
+    @Deprecated
+    String getCachePolicy();
+
+    /**
+     * Returns a caching strategy for this query.
+     * 
+     * @since 3.0
+     */
+    QueryCacheStrategy getCacheStrategy();
+
+    /**
+     * Returns a String that uniquely identifies this query for the purposes of result
+     * caching. If null is returned, no caching is performed.
+     */
+    String getCacheKey();
+
+    /**
+     * Returns an optional array of cache "groups". Cache groups allow to invalidate query
+     * caches in bulk on different events. Usually the first group in the array is
+     * considered to be the "main" group that is used for declarative cache invalidation
+     * with some cache providers.
+     * 
+     * @since 3.0
+     */
+    String[] getCacheGroups();
+
+    /**
+     * Returns <code>true</code> if this query should produce a list of data rows as
+     * opposed to DataObjects, <code>false</code> for DataObjects. This is a hint to
+     * QueryEngine executing this query.
+     */
+    boolean isFetchingDataRows();
+
+    /**
+     * Returns <code>true</code> if the query results should replace any currently cached
+     * values, returns <code>false</code> otherwise. If {@link #isFetchingDataRows()}
+     * returns <code>true</code>, this setting is not applicable and has no effect.
+     */
+    boolean isRefreshingObjects();
+
+    /**
+     * Returns true if objects fetched via this query should be fully resolved according
+     * to the inheritance hierarchy.
+     * 
+     * @deprecated since 3.0. Inheritance resolving is not optional anymore.
+     */
+    @Deprecated
+    boolean isResolvingInherited();
+
+    /**
+     * Returns query page size. Page size is a hint to Cayenne that query should be
+     * performed page by page, instead of retrieving all results at once. If the value
+     * returned is less than or equal to zero, no paging should occur.
+     */
+    int getPageSize();
+
+    /**
+     * Specifies a start of a range when fetching a subset of records.
+     * 
+     * @since 3.0
+     */
+    int getFetchOffset();
+
+    /**
+     * @deprecated since 3.0, renamed to {@link #getFetchOffset()}.
+     */
+    @Deprecated
+    int getFetchStartIndex();
+
+    /**
+     * Returns the limit on the maximum number of records that can be returned by this
+     * query. If the actual number of rows in the result exceeds the fetch limit, they
+     * will be discarded. One possible use of fetch limit is using it as a safeguard
+     * against large result sets that may lead to the application running out of memory,
+     * etc. If a fetch limit is greater or equal to zero, all rows will be returned.
+     * 
+     * @return the limit on the maximum number of records that can be returned by this
+     *         query
+     */
+    int getFetchLimit();
+
+    /**
+     * Returns a query that originated this query. Originating query is a query whose
+     * result is needed to obtain the result of the query owning this metadata. Most often
+     * than not the returned value is null. One example of non-null originating query is a
+     * query for a range of objects in a previously fetched paginated list. The query that
+     * fetched the original paginated list is an "originated" query. It may be used to
+     * restore a list that got lost due to a cache overflow, etc.
+     * 
+     * @since 3.0
+     */
+    Query getOrginatingQuery();
+
+    /**
+     * Returns a root node of prefetch tree used by this query, or null of no prefetches
+     * are configured.
+     */
+    PrefetchTreeNode getPrefetchTree();
+
+    /**
+     * Returns a map of aliases vs. expression subpaths that is used to build split joins.
+     * 
+     * @since 3.0
+     */
+    Map<String, String> getPathSplitAliases();
+
+    /**
+     * Returns an optional list of result set mapping hints. Elements in the list can be
+     * either {@link EntityResultSegment} or {@link ScalarResultSegment}. The returned
+     * list can be null.
+     * 
+     * @since 3.0
+     */
+    List<Object> getResultSetMapping();
+    
+    /**
+     * @return statement's fetch size
+     * @since 3.0
+     */
+    public int getStatementFetchSize();
+}