/***************************************************************** * 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 * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * 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.CayenneRuntimeException; import org.apache.cayenne.ObjectContext; import org.apache.cayenne.ResultBatchIterator; import org.apache.cayenne.ResultIterator; import org.apache.cayenne.ResultIteratorCallback; import org.apache.cayenne.map.EntityResolver; import org.apache.cayenne.map.QueryDescriptor; import java.sql.Statement; import java.util.List; import java.util.Map; /** * A query that represents a named parameterized selecting query stored in the mapping. The * actual query is resolved during execution. * * @since 4.0 */ public class MappedSelect<T> extends AbstractMappedQuery implements Select<T> { /** * Loads query with the given name, which selects objects of a given persistent class, * from the mapping configuration. * * @param queryName name of the mapped query * @param rootClass the Class of objects fetched by this query */ public static <T> MappedSelect<T> query(String queryName, Class<T> rootClass) { return new MappedSelect<>(queryName, rootClass); } /** * Loads query with the given name from the mapping configuration. * * @param queryName name of the mapped query */ public static MappedSelect<?> query(String queryName) { return new MappedSelect<>(queryName); } protected Class<T> resultClass; protected Integer fetchLimit; protected Integer fetchOffset; protected Integer statementFetchSize; protected Integer pageSize; protected boolean forceNoCache; protected MappedSelect(String queryName) { super(queryName); } protected MappedSelect(String queryName, Class<T> resultClass) { super(queryName); this.resultClass = resultClass; } /** * Resets query fetch limit - a parameter that defines max number of objects * that should be ever be fetched from the database. */ public MappedSelect<T> limit(int fetchLimit) { this.fetchLimit = fetchLimit; this.replacementQuery = null; return this; } /** * Resets query fetch offset - a parameter that defines how many objects * should be skipped when reading data from the database. */ public MappedSelect<T> offset(int fetchOffset) { this.fetchOffset = fetchOffset; this.replacementQuery = null; return this; } /** * Sets fetch size of the PreparedStatement generated for this query. Only * non-negative values would change the default size. * * @see Statement#setFetchSize(int) */ public MappedSelect<T> statementFetchSize(int statementFetchSize) { this.statementFetchSize = statementFetchSize; this.replacementQuery = null; return this; } /** * Resets query page size. A non-negative page size enables query result * pagination that saves memory and processing time for large lists if only * parts of the result are ever going to be accessed. */ public MappedSelect<T> pageSize(int pageSize) { this.pageSize = pageSize; this.replacementQuery = null; return this; } /** * Forces query cache to be refreshed during the execution of this query. */ public MappedSelect<T> forceNoCache() { this.forceNoCache = true; this.replacementQuery = null; return this; } @SuppressWarnings("unchecked") @Override public MappedSelect<T> params(Map<String, ?> parameters) { return (MappedSelect<T>) super.params(parameters); } @SuppressWarnings("unchecked") @Override public MappedSelect<T> param(String name, Object value) { return (MappedSelect<T>) super.param(name, value); } public List<T> select(ObjectContext context) { return context.select(this); } @Override public T selectOne(ObjectContext context) { return context.selectOne(this); } @Override public T selectFirst(ObjectContext context) { return context.selectFirst(limit(1)); } @Override public void iterate(ObjectContext context, ResultIteratorCallback<T> callback) { context.iterate(this, callback); } @Override public ResultIterator<T> iterator(ObjectContext context) { return context.iterator(this); } @Override public ResultBatchIterator<T> batchIterator(ObjectContext context, int size) { return context.batchIterator(this, size); } @Override protected Query createReplacementQuery(EntityResolver resolver) { QueryDescriptor descriptor = resolver.getQueryDescriptor(queryName); Query query = super.createReplacementQuery(resolver); QueryCacheStrategy cacheStrategyOverride = null; if (forceNoCache) { QueryCacheStrategy cacheStrategy = query.getMetaData(resolver).getCacheStrategy(); if (QueryCacheStrategy.LOCAL_CACHE == cacheStrategy) { cacheStrategyOverride = QueryCacheStrategy.LOCAL_CACHE_REFRESH; } else if (QueryCacheStrategy.SHARED_CACHE == cacheStrategy) { cacheStrategyOverride = QueryCacheStrategy.SHARED_CACHE_REFRESH; } } switch (descriptor.getType()) { case QueryDescriptor.SELECT_QUERY: SelectQuery selectQuery = (SelectQuery) query; if (fetchLimit != null) { selectQuery.setFetchLimit(fetchLimit); } if (fetchOffset != null) { selectQuery.setFetchOffset(fetchOffset); } if (statementFetchSize != null) { selectQuery.setStatementFetchSize(statementFetchSize); } if (pageSize != null) { selectQuery.setPageSize(pageSize); } if (cacheStrategyOverride != null) { selectQuery.setCacheStrategy(cacheStrategyOverride); } break; case QueryDescriptor.SQL_TEMPLATE: SQLTemplate sqlTemplate = (SQLTemplate) query; if (fetchLimit != null) { sqlTemplate.setFetchLimit(fetchLimit); } if (fetchOffset != null) { sqlTemplate.setFetchOffset(fetchOffset); } if (statementFetchSize != null) { sqlTemplate.setStatementFetchSize(statementFetchSize); } if (pageSize != null) { sqlTemplate.setPageSize(pageSize); } if (cacheStrategyOverride != null) { sqlTemplate.setCacheStrategy(cacheStrategyOverride); } break; case QueryDescriptor.EJBQL_QUERY: EJBQLQuery ejbqlQuery = (EJBQLQuery) query; if (fetchLimit != null) { ejbqlQuery.setFetchLimit(fetchLimit); } if (fetchOffset != null) { ejbqlQuery.setFetchOffset(fetchOffset); } if (statementFetchSize != null) { ejbqlQuery.setStatementFetchSize(statementFetchSize); } if (pageSize != null) { ejbqlQuery.setPageSize(pageSize); } if (cacheStrategyOverride != null) { ejbqlQuery.setCacheStrategy(cacheStrategyOverride); } break; case QueryDescriptor.PROCEDURE_QUERY: ProcedureQuery procedureQuery = (ProcedureQuery) query; if (fetchLimit != null) { procedureQuery.setFetchLimit(fetchLimit); } if (fetchOffset != null) { procedureQuery.setFetchOffset(fetchOffset); } if (statementFetchSize != null) { procedureQuery.setStatementFetchSize(statementFetchSize); } if (pageSize != null) { procedureQuery.setPageSize(pageSize); } if (cacheStrategyOverride != null) { procedureQuery.setCacheStrategy(cacheStrategyOverride); } break; default: throw new CayenneRuntimeException("Unknown query type: %s", descriptor.getType()); } return query; } }