package com.googlecode.objectify.cmd; import com.google.appengine.api.datastore.Cursor; /** * A restricted set of query operations that apply to both kindless queries and typed queries. * * @author Jeff Schnitzer <jeff@infohazard.org> */ public interface SimpleQuery<T> extends QueryExecute<T> { /** * <p>Create a filter on the key of an entity. Examples:</p> * * <ul> * <li>{@code filterKey(">=", key)} (standard inequalities)</li> * <li>{@code filterKey("=", key)} (wouldn't you rather do a load-by-key?)</li> * <li>{@code filterKey("", key)} (if no operator, = is assumed)</li> * <li>{@code filterKey("!=", key)}</li> * <li>{@code filterKey("in", keyList)} (wouldn't you rather do a batch load-by-key?)</li> * </ul> * * <p>The key parameter can be anything key-ish; a Key<?>, a native datastore key, a Ref, a pojo entity, etc.</p> * * <p>See the Google documentation for * <a href="http://code.google.com/appengine/docs/java/datastore/queries.html#Introduction_to_Indexes">indexes</a> * for an explanation of what you can and cannot filter for.</p> * * <p><b>All command objects are immutable; this method returns a new object instead of modifying the * current command object.</b></p> * * @return a new immutable query object that applies the filter */ public SimpleQuery<T> filterKey(String condition, Object value); /** * An alias for {@code filterKey("=", value)} * * <p><b>All command objects are immutable; this method returns a new object instead of modifying the * current command object.</b></p> * * @return a new immutable query object that applies the filter */ public SimpleQuery<T> filterKey(Object value); /** * Orders results by the key. * @param descending if true, specifies a descending (aka reverse) sort * * <p><b>All command objects are immutable; this method returns a new object instead of modifying the * current command object.</b></p> * * @return a new immutable query object that applies the sort order */ public SimpleQuery<T> orderKey(boolean descending); /** * Restricts result set only to objects which have the given ancestor * somewhere in the chain. Doesn't need to be the immediate parent. The * specified ancestor itself will be included in the result set (if it * exists). * * <p><b>All command objects are immutable; this method returns a new object instead of modifying the * current command object.</b></p> * * @param keyOrEntity can be a Key, a Key<T>, or an Objectify entity object. * @return a new immutable query object that applies the ancestor filter */ public SimpleQuery<T> ancestor(Object keyOrEntity); /** * Limit the fetched result set to a certain number of values. * * <p><b>All command objects are immutable; this method returns a new object instead of modifying the * current command object.</b></p> * * @param value must be >= 0. A value of 0 indicates no limit. * @return a new immutable query object that applies the limit */ public SimpleQuery<T> limit(int value); /** * Starts the query results at a particular zero-based offset. This can be extraordinarily * expensive because each skipped entity is billed as a "minor datastore operation". If you * can, you probably want to use cursors instead. * * <p><b>All command objects are immutable; this method returns a new object instead of modifying the * current command object.</b></p> * * @param value must be >= 0 * @return a new immutable query object that applies the offset */ public SimpleQuery<T> offset(int value); /** * Starts query results at the specified Cursor. You can obtain a Cursor from * a QueryResultIterator by calling the getCursor() method. * * <p><b>All command objects are immutable; this method returns a new object instead of modifying the * current command object.</b></p> * * Note that limit() and offset() are NOT encoded within a cursor; they operate * on the results of the query after a cursor is established. * * @return a new immutable query object that applies the cursor */ public SimpleQuery<T> startAt(Cursor value); /** * Ends query results at the specified Cursor. You can obtain a Cursor from * a QueryResultIterator by calling the getCursor() method. * * <p><b>All command objects are immutable; this method returns a new object instead of modifying the * current command object.</b></p> * * Note that limit() and offset() are NOT encoded within a cursor; they operate * on the results of the query after a cursor is established. * * @return a new immutable query object that applies the cursor */ public SimpleQuery<T> endAt(Cursor value); /** * Sets the internal chunking and prefetching strategy within the low-level API. Affects * performance only; the result set will be the same. * * <p><b>All command objects are immutable; this method returns a new object instead of modifying the * current command object.</b></p> * * @param value must be >= 0 * @return a new immutable query object that applies the chunk size */ public SimpleQuery<T> chunk(int value); /** * <p>Sets the internal chunking and prefetching strategy within the low-level API to attempt to get all * results at once. Affects performance only; the result set will be the same.</p> * * <p><b>All command objects are immutable; this method returns a new object instead of modifying the * current command object.</b></p> * * <p>Same as chunk(Integer.MAX_VALUE).</p> * * @return a new immutable query object that applies the chunk size */ public SimpleQuery<T> chunkAll(); /** * <p>Converts this query into a <a href="https://developers.google.com/appengine/docs/java/datastore/projectionqueries">projection query</a>. * Projection queries allow values to be selected directly out of an index rather than loading the whole entity. While this allows * data to be fetched quickly and cheaply, it is limited to selecting data that exists in an index.</p> * * <p>Entities returned from projection queries are NOT kept in the session cache. However, @Load annotations are * processed normally.</p> * * <p>This method can be called more than once; it will have the same effect as passing all the fields * in to a single call.</p> * * @param fields is one or more field names * @return a new immutable query object that projects the specified fields */ public SimpleQuery<T> project(String... fields); /** * Determines whether this is a SELECT DISTINCT query. * * <p><b>All command objects are immutable; this method returns a new object instead of modifying the * current command object.</b></p> * * @return a new immutable query object that applies the distinct operator */ public SimpleQuery<T> distinct(boolean value); /** * Reverse the query, as described in the <a href="https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/datastore/Query#reverse()">GAE docs</a>. * * <p><b>All command objects are immutable; this method returns a new object instead of modifying the * current command object.</b></p> * * @return a new immutable query object that reverses the order of results */ public SimpleQuery<T> reverse(); /** * <p>This method forces Objectify to (or not to) hybridize the query into a keys-only fetch plus batch get.</p> * * <p>If Objectify knows you are fetching an entity type that can be cached, it automatically converts * queries into a "hybrid" of keys-only query followed by a batch fetch of the keys. This is cheaper (keys-only * results are 1/7th the price of a full fetch) and, if the cache hits, significantly faster. However, * there are some circumstances in which you may wish to force behavior one way or another:</p> * * <ul> * <li>Issuing a kindless query (which Objectify will not auto-hybridize) when you know a significant portion * of the result set is cacheable.</li> * <li>Some exotic queries cannot be made keys-only, and produce an exception from the Low-Level API when you * try to execute the query. Objectify tries to detect these cases but since the underlying implementation * may change, you may need to force hybridization off in some cases.</li> * <li>Hybrid queries have a slightly different consistency model than normal queries. You may wish to * force hybridization off to ensure a weakly consistent query (see below).</li> * </ul> * * <p>For the most part, hybridization only affects the performance and cost of queries. However, it is possible * for hybridization to alter the content of the result set. In the HRD, queries * always have EVENTUAL consistency but get operations may have either STRONG or EVENTUAL consistency depending * on the read policy (see {@code Objectify.consistency()}. The keys-only query results will always be EVENTUAL and may * return data that has been deleted, but Objectify will exclude these results when the more-current batch get fails to return * data. So the count of the returned data may actually be less than the limit(), even if there are plenty of * actual results. {@code hybrid(false)} will prevent this behavior.</p> * * <p>Note that in hybrid queries, the chunk size defines the batch size.</p> * * <p><b>All command objects are immutable; this method returns a new object instead of modifying the * current command object.</b></p> * * @return a new immutable query object that forces hybridization on or off */ public SimpleQuery<T> hybrid(boolean force); /** * Switches to a keys-only query. Keys-only responses are billed as "minor datastore operations" * which are faster and free compared to fetching whole entities. * * <p><b>All command objects are immutable; this method returns a new object instead of modifying the * current command object.</b></p> * * @return a new immutable query object that returns keys rather than whole entities */ public QueryKeys<T> keys(); /** * <p>Count the total number of values in the result. <em>limit</em> and <em>offset</em> are obeyed. * This is somewhat faster than fetching, but the time still grows with the number of results. * The datastore actually walks through the result set and counts for you.</p> * * <p>Immediately executes the query; there is no async version of this method.</p> * * <p>WARNING: Each counted entity is billed as a "datastore minor operation". Even though these * are free, they may take significant time because they require an index walk.</p> */ public int count(); /** * <p>Generates a string that consistently and uniquely specifies this query. There * is no way to convert this string back into a query and there is no guarantee that * the string will be consistent across versions of Objectify.</p> * * <p>In particular, this value is useful as a key for a simple memcache query cache.</p> */ public String toString(); }