Package org.slim3.datastore

Source Code of org.slim3.datastore.AbstractQuery

/*
* Copyright 2004-2010 the Seasar Foundation and the Others.
*
* Licensed 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.slim3.datastore;

import java.util.ArrayList;
import java.util.List;

import org.slim3.util.AppEngineUtil;
import org.slim3.util.ByteUtil;
import org.slim3.util.ThrowableUtil;

import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.QueryResultIterable;
import com.google.appengine.api.datastore.QueryResultIterator;
import com.google.appengine.api.datastore.QueryResultList;
import com.google.appengine.api.datastore.Transaction;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.FilterPredicate;
import com.google.appengine.api.datastore.Query.SortDirection;
import com.google.appengine.api.datastore.Query.SortPredicate;
import com.google.appengine.repackaged.com.google.common.util.Base64;
import com.google.appengine.repackaged.com.google.common.util.Base64DecoderException;

/**
* An abstract query.
*
* @param <SUB>
*            the sub type
* @author higa
* @since 1.0.0
*
*/
public abstract class AbstractQuery<SUB> {

    /**
     * The datastore query.
     */
    protected Query query;

    /**
     * The transaction.
     */
    protected Transaction tx;

    /**
     * Whether the transaction was set.
     */
    protected boolean txSet = false;

    /**
     * The fetch options.
     */
    protected FetchOptions fetchOptions =
        FetchOptions.Builder.withOffset(0).limit(Integer.MAX_VALUE);

    /**
     * Constructor.
     *
     */
    public AbstractQuery() {
        setUpQuery();
    }

    /**
     * Constructor.
     *
     * @param kind
     *            the kind
     * @throws NullPointerException
     *             if the kind parameter is null
     *
     */
    public AbstractQuery(String kind) throws NullPointerException {
        setUpQuery(kind);
    }

    /**
     * Constructor.
     *
     * @param kind
     *            the kind
     * @param ancestorKey
     *            the ancestor key
     * @throws NullPointerException
     *             if the kind parameter is null or if the ancestorKey parameter
     *             is null
     *
     */
    public AbstractQuery(String kind, Key ancestorKey)
            throws NullPointerException {
        setUpQuery(kind, ancestorKey);
    }

    /**
     * Constructor.
     *
     * @param ancestorKey
     *            the ancestor key
     * @throws NullPointerException
     *             if the ancestorKey parameter is null
     */
    public AbstractQuery(Key ancestorKey) throws NullPointerException {
        setUpQuery(ancestorKey);
    }

    /**
     * Sets up an internal query.
     *
     */
    protected void setUpQuery() {
        query = new Query();
    }

    /**
     * Sets up an internal query.
     *
     * @param kind
     *            the kind
     * @throws NullPointerException
     *             if the kind parameter is null
     *
     */
    protected void setUpQuery(String kind) throws NullPointerException {
        if (kind == null) {
            throw new NullPointerException(
                "The kind parameter must not be null.");
        }
        query = new Query(kind);
    }

    /**
     * Sets up an internal query.
     *
     * @param kind
     *            the kind
     * @param ancestorKey
     *            the ancestor key
     * @throws NullPointerException
     *             if the kind parameter is null or if the ancestorKey parameter
     *             is null
     *
     */
    protected void setUpQuery(String kind, Key ancestorKey)
            throws NullPointerException {
        if (kind == null) {
            throw new NullPointerException(
                "The kind parameter must not be null.");
        }
        if (ancestorKey == null) {
            throw new NullPointerException(
                "The ancestorKey parameter must not be null.");
        }
        query = new Query(kind, ancestorKey);
    }

    /**
     * Sets up an internal query.
     *
     * @param ancestorKey
     *            the ancestor key
     * @throws NullPointerException
     *             if the ancestorKey parameter is null
     */
    protected void setUpQuery(Key ancestorKey) throws NullPointerException {
        if (ancestorKey == null) {
            throw new NullPointerException(
                "The ancestorKey parameter must not be null.");
        }
        query = new Query(ancestorKey);
    }

    /**
     * Specified the transaction.
     *
     * @param tx
     *            the transaction
     * @throws IllegalStateException
     *             if the transaction is not null and the transaction is not
     *             active
     */
    protected void setTx(Transaction tx) throws IllegalStateException {
        if (tx != null && !tx.isActive()) {
            throw new IllegalStateException("The transaction must be active.");
        }
        this.tx = tx;
        txSet = true;
    }

    /**
     * Specifies the offset.
     *
     * @param offset
     *            the offset
     * @return this instance
     */
    @SuppressWarnings("unchecked")
    public SUB offset(int offset) {
        fetchOptions.offset(offset);
        return (SUB) this;
    }

    /**
     * Specifies the limit.
     *
     * @param limit
     *            the limit
     * @return this instance
     */
    @SuppressWarnings("unchecked")
    public SUB limit(int limit) {
        fetchOptions.limit(limit);
        return (SUB) this;
    }

    /**
     * Specifies the size of prefetch.
     *
     * @param prefetchSize
     *            the size of prefetch
     * @return this instance
     */
    @SuppressWarnings("unchecked")
    public SUB prefetchSize(int prefetchSize) {
        fetchOptions.prefetchSize(prefetchSize);
        return (SUB) this;
    }

    /**
     * Specifies the size of chunk.
     *
     * @param chunkSize
     *            the size of chunk
     * @return this instance
     */
    @SuppressWarnings("unchecked")
    public SUB chunkSize(int chunkSize) {
        fetchOptions.chunkSize(chunkSize);
        return (SUB) this;
    }

    /**
     * Specifies the cursor.
     *
     * @param cursor
     *            the cursor
     * @return this instance
     * @throws NullPointerException
     *             if the cursor parameter is null
     */
    @SuppressWarnings("unchecked")
    public SUB cursor(Cursor cursor) throws NullPointerException {
        if (cursor == null) {
            throw new NullPointerException(
                "The cursor parameter must not be null.");
        }
        fetchOptions.cursor(cursor);
        return (SUB) this;
    }

    /**
     * Specifies the encoded cursor.
     *
     * @param encodedCursor
     *            the encoded cursor
     * @return this instance
     * @throws NullPointerException
     *             if the encodedCursor parameter is null
     */
    @SuppressWarnings("unchecked")
    public SUB encodedCursor(String encodedCursor) throws NullPointerException {
        if (encodedCursor == null) {
            throw new NullPointerException(
                "The encodedCursor parameter must not be null.");
        }
        fetchOptions.cursor(Cursor.fromWebSafeString(encodedCursor));
        return (SUB) this;
    }

    /**
     * Adds the filter.
     *
     * @param propertyName
     *            the property name
     * @param operator
     *            the {@link FilterOperator}
     * @param value
     *            the value
     *
     * @return this instance
     * @throws NullPointerException
     *             if the propertyName parameter is null or if the operator
     *             parameter is null
     */
    @SuppressWarnings("unchecked")
    public SUB filter(String propertyName, FilterOperator operator, Object value)
            throws NullPointerException {
        if (propertyName == null) {
            throw new NullPointerException(
                "The propertyName parameter must not be null.");
        }
        if (operator == null) {
            throw new NullPointerException(
                "The operator parameter must not be null.");
        }
        query.addFilter(propertyName, operator, value);
        return (SUB) this;
    }

    /**
     * Adds the filters.
     *
     * @param filters
     *            the filters
     * @return this instance
     * @throws NullPointerException
     *             if the element of the filters parameter is null
     */
    @SuppressWarnings("unchecked")
    public SUB filter(Filter... filters) throws NullPointerException {
        for (Filter f : filters) {
            if (f == null) {
                throw new NullPointerException(
                    "The element of the filters parameter must not be null.");
            }
            query.addFilter(f.getPropertyName(), f.getOperator(), f.getValue());
        }
        return (SUB) this;
    }

    /**
     * Specifies the encoded filters.
     *
     * @param encodedFilters
     *            the encoded filters
     * @return this instance
     * @throws NullPointerException
     *             if the encodedFilters parameter is null
     */
    public SUB encodedFilters(String encodedFilters)
            throws NullPointerException {
        if (encodedFilters == null) {
            throw new NullPointerException(
                "The encodedFilters parameter must not be null.");
        }
        try {
            Filter[] filters =
                (Filter[]) ByteUtil.toObject(Base64.decode(encodedFilters));
            return filter(filters);
        } catch (Base64DecoderException e) {
            throw ThrowableUtil.wrap(e);
        }
    }

    /**
     * Adds the sorts.
     *
     * @param sorts
     *            the array of sorts
     * @return this instance
     * @throws NullPointerException
     *             if the element of the sorts parameter is null
     */
    @SuppressWarnings("unchecked")
    public SUB sort(Sort... sorts) throws NullPointerException {
        for (Sort s : sorts) {
            if (s == null) {
                throw new NullPointerException(
                    "The element of the sorts parameter must not be null.");
            }
            query.addSort(s.getPropertyName(), s.getDirection());
        }
        return (SUB) this;
    }

    /**
     * Adds the sort.
     *
     * @param propertyName
     *            the property name
     * @return this instance
     * @throws NullPointerException
     *             if the propertyName parameter is null
     */
    public SUB sort(String propertyName) throws NullPointerException {
        return sort(propertyName, SortDirection.ASCENDING);
    }

    /**
     * Adds the sort.
     *
     * @param propertyName
     *            the property name
     * @param direction
     *            the sort direction
     * @return this instance
     * @throws NullPointerException
     *             if the propertyName parameter is null or if the direction
     *             parameter is null
     */
    @SuppressWarnings("unchecked")
    public SUB sort(String propertyName, SortDirection direction)
            throws NullPointerException {
        if (propertyName == null) {
            throw new NullPointerException(
                "The propertyName parameter must not be null.");
        }
        if (direction == null) {
            throw new NullPointerException(
                "The direction parameter must not be null.");
        }
        query.addSort(propertyName, direction);
        return (SUB) this;
    }

    /**
     * Specifies the encoded sorts.
     *
     * @param encodedSorts
     *            the encoded sorts
     * @return this instance
     * @throws NullPointerException
     *             if the encodedSorts parameter is null
     */
    public SUB encodedSorts(String encodedSorts) throws NullPointerException {
        if (encodedSorts == null) {
            throw new NullPointerException(
                "The encodedSorts parameter must not be null.");
        }
        try {
            Sort[] sorts =
                (Sort[]) ByteUtil.toObject(Base64.decode(encodedSorts));
            return sort(sorts);
        } catch (Base64DecoderException e) {
            throw ThrowableUtil.wrap(e);
        }
    }

    /**
     * Returns the filters.
     *
     * @return the filters
     */
    public Filter[] getFilters() {
        List<FilterPredicate> list = query.getFilterPredicates();
        Filter[] filters = new Filter[list.size()];
        for (int i = 0; i < list.size(); i++) {
            FilterPredicate f = list.get(i);
            filters[i] =
                new Filter(f.getPropertyName(), f.getOperator(), f.getValue());
        }
        return filters;
    }

    /**
     * Returns the encoded filters.
     *
     * @return the encoded filters
     */
    public String getEncodedFilters() {
        return Base64.encode(ByteUtil.toByteArray(getFilters()));
    }

    /**
     * Returns the sorts.
     *
     * @return the sorts
     */
    public Sort[] getSorts() {
        List<SortPredicate> list = query.getSortPredicates();
        Sort[] sorts = new Sort[list.size()];
        for (int i = 0; i < list.size(); i++) {
            SortPredicate s = list.get(i);
            sorts[i] = new Sort(s.getPropertyName(), s.getDirection());
        }
        return sorts;
    }

    /**
     * Returns the encoded sorts.
     *
     * @return the encoded sorts
     */
    public String getEncodedSorts() {
        return Base64.encode(ByteUtil.toByteArray(getSorts()));
    }

    /**
     * Returns entities as list.
     *
     * @return entities as list
     */
    protected List<Entity> asEntityList() {
        DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
        if (!AppEngineUtil.isProduction() && query.getKind() == null) {
            List<Entity> list = new ArrayList<Entity>();
            List<String> kinds = DatastoreUtil.getKinds();
            Key ancestor = query.getAncestor();
            if (ancestor != null) {
                for (String kind : kinds) {
                    Query q = new Query(kind, ancestor);
                    list.addAll(asEntityList(ds, q));
                }
            } else {
                for (String kind : kinds) {
                    Query q = new Query(kind);
                    list.addAll(asEntityList(ds, q));
                }
            }
            return list;
        }
        return asEntityList(ds, query);
    }

    /**
     * Returns entities as list.
     *
     * @param ds
     *            the datastore service
     * @param qry
     *            the query
     * @return entities as list
     */
    protected List<Entity> asEntityList(DatastoreService ds, Query qry) {
        PreparedQuery pq =
            txSet ? DatastoreUtil.prepare(ds, tx, qry) : DatastoreUtil.prepare(
                ds,
                qry);
        return DatastoreUtil.asList(pq, fetchOptions);
    }

    /**
     * Returns entities as query result list.
     *
     * @return entities as query result list
     */
    protected QueryResultList<Entity> asQueryResultEntityList() {
        DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
        PreparedQuery pq =
            txSet ? DatastoreUtil.prepare(ds, tx, query) : DatastoreUtil
                .prepare(ds, query);
        return DatastoreUtil.asQueryResultList(pq, fetchOptions);
    }

    /**
     * Returns entities as query result iterator.
     *
     * @return entities as query result iterator
     */
    protected QueryResultIterator<Entity> asQueryResultEntityIterator() {
        DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
        PreparedQuery pq =
            txSet ? DatastoreUtil.prepare(ds, tx, query) : DatastoreUtil
                .prepare(ds, query);
        return DatastoreUtil.asQueryResultIterator(pq, fetchOptions);
    }

    /**
     * Returns entities as query result iterable.
     *
     * @return entities as query result iterable
     */
    protected QueryResultIterable<Entity> asQueryResultEntityIterable() {
        DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
        PreparedQuery pq =
            txSet ? DatastoreUtil.prepare(ds, tx, query) : DatastoreUtil
                .prepare(ds, query);
        return DatastoreUtil.asQueryResultIterable(pq, fetchOptions);
    }

    /**
     * Returns a single entity.
     *
     * @return a single entity
     */
    protected Entity asSingleEntity() {
        if (!AppEngineUtil.isProduction() && query.getKind() == null) {
            List<Entity> list = asEntityList();
            if (list.size() == 0) {
                return null;
            }
            if (list.size() > 1) {
                throw new PreparedQuery.TooManyResultsException();
            }
            return list.get(0);
        }
        DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
        PreparedQuery pq =
            txSet ? DatastoreUtil.prepare(ds, tx, query) : DatastoreUtil
                .prepare(ds, query);
        return DatastoreUtil.asSingleEntity(pq);
    }

    /**
     * Returns a list of keys.
     *
     * @return a list of keys
     */
    public List<Key> asKeyList() {
        query.setKeysOnly();
        List<Entity> entityList = asEntityList();
        List<Key> ret = new ArrayList<Key>(entityList.size());
        for (Entity e : entityList) {
            ret.add(e.getKey());
        }
        return ret;
    }

    /**
     * Returns a number of entities.
     *
     * @return a number of entities
     */
    public int count() {
        query.setKeysOnly();
        List<Entity> entityList = asEntityList();
        return entityList.size();
    }

    /**
     * Returns a number of entities. This method can only return up to 1,000
     * results, but this method can return the results quickly.
     *
     * @return a number of entities
     */
    public int countQuickly() {
        DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
        PreparedQuery pq =
            txSet ? DatastoreUtil.prepare(ds, tx, query) : DatastoreUtil
                .prepare(ds, query);
        return DatastoreUtil.countEntities(pq);
    }

    /**
     * Return a minimum value of the property. The value does not include null.
     *
     * @param <T>
     *            the property type
     * @param propertyName
     *            the property name
     * @return a minimum value of the property
     * @throws NullPointerException
     *             if the propertyName parameter is null
     */
    @SuppressWarnings("unchecked")
    protected <T> T min(String propertyName) throws NullPointerException {
        if (propertyName == null) {
            throw new NullPointerException(
                "The propertyName parameter must not be null.");
        }
        query.addFilter(propertyName, FilterOperator.GREATER_THAN, null);
        query.addSort(propertyName, SortDirection.ASCENDING);
        fetchOptions.offset(0).limit(1);
        List<Entity> list = asEntityList();
        if (list.size() == 0) {
            return null;
        }
        return (T) list.get(0).getProperty(propertyName);
    }

    /**
     * Return a maximum value of the property.
     *
     * @param <T>
     *            the property type
     * @param propertyName
     *            the property name
     * @return a maximum value of the property
     * @throws NullPointerException
     *             if the propertyName parameter is null
     */
    @SuppressWarnings("unchecked")
    protected <T> T max(String propertyName) throws NullPointerException {
        if (propertyName == null) {
            throw new NullPointerException(
                "The propertyName parameter must not be null.");
        }
        query.addSort(propertyName, SortDirection.DESCENDING);
        fetchOptions.offset(0).limit(1);
        List<Entity> list = asEntityList();
        if (list.size() == 0) {
            return null;
        }
        return (T) list.get(0).getProperty(propertyName);
    }

    /**
     * Returns entities as {@link Iterable}.
     *
     * @return entities as {@link Iterable}
     */
    protected Iterable<Entity> asIterableEntities() {
        DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
        PreparedQuery pq =
            txSet ? DatastoreUtil.prepare(ds, tx, query) : DatastoreUtil
                .prepare(ds, query);
        return DatastoreUtil.asIterable(pq, fetchOptions);
    }
}
TOP

Related Classes of org.slim3.datastore.AbstractQuery

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.