org.skife.jdbi.v2.Query Maven / Gradle / Ivy
/*
* Copyright (C) 2004 - 2014 Brian McCallister
*
* 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.skife.jdbi.v2;
import org.skife.jdbi.v2.tweak.ResultSetMapper;
import org.skife.jdbi.v2.tweak.SQLLog;
import org.skife.jdbi.v2.tweak.StatementBuilder;
import org.skife.jdbi.v2.tweak.StatementCustomizer;
import org.skife.jdbi.v2.tweak.StatementLocator;
import org.skife.jdbi.v2.tweak.StatementRewriter;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/**
* Statement providing convenience result handling for SQL queries.
*/
public class Query extends SQLStatement> implements ResultBearing
{
private final ResultSetMapper mapper;
private final MappingRegistry mappingRegistry;
Query(Binding params,
ResultSetMapper mapper,
StatementLocator locator,
StatementRewriter statementRewriter,
Handle handle,
StatementBuilder cache,
String sql,
ConcreteStatementContext ctx,
SQLLog log,
TimingCollector timingCollector,
Collection customizers,
MappingRegistry mappingRegistry,
Foreman foreman,
ContainerFactoryRegistry containerFactoryRegistry)
{
super(params, locator, statementRewriter, handle, cache, sql, ctx, log, timingCollector, customizers, foreman, containerFactoryRegistry);
this.mapper = mapper;
this.mappingRegistry = mappingRegistry.createChild();
}
/**
* Executes the select
*
* Will eagerly load all results
*
* @throws org.skife.jdbi.v2.exceptions.UnableToCreateStatementException
* if there is an error creating the statement
* @throws org.skife.jdbi.v2.exceptions.UnableToExecuteStatementException
* if there is an error executing the statement
* @throws org.skife.jdbi.v2.exceptions.ResultSetException if there is an error dealing with the result set
*/
@Override
public List list()
{
return list(List.class);
}
@Override
public ContainerType list(Class containerType)
{
ContainerBuilder builder = getContainerMapperRegistry().createBuilderFor(containerType);
return fold(builder, new Folder3, ResultType>()
{
@Override
public ContainerBuilder fold(ContainerBuilder accumulator,
ResultType rs,
FoldController ctl,
StatementContext ctx) throws SQLException
{
accumulator.add(rs);
return accumulator;
}
}).build();
}
/**
* Executes the select
*
* Will eagerly load all results up to a maximum of maxRows
*
* @param maxRows The maximum number of results to include in the result, any
* rows in the result set beyond this number will be ignored.
*
* @throws org.skife.jdbi.v2.exceptions.UnableToCreateStatementException
* if there is an error creating the statement
* @throws org.skife.jdbi.v2.exceptions.UnableToExecuteStatementException
* if there is an error executing the statement
* @throws org.skife.jdbi.v2.exceptions.ResultSetException if there is an error dealing with the result set
*/
@Override
public List list(final int maxRows)
{
try {
return this.internalExecute(new QueryResultSetMunger>(this)
{
@Override
public List munge(ResultSet rs) throws SQLException
{
List result_list = new ArrayList();
int index = 0;
while (rs.next() && index < maxRows) {
result_list.add(mapper.map(index++, rs, getContext()));
}
return result_list;
}
});
}
finally {
cleanup();
}
}
/**
* Used to execute the query and traverse the result set with a accumulator.
* Folding over the
* result involves invoking a callback for each row, passing into the callback the return value
* from the previous function invocation.
*
* @param accumulator The initial accumulator value
* @param folder Defines the function which will fold over the result set.
*
* @return The return value from the last invocation of {@link Folder#fold(Object, java.sql.ResultSet)}
*
* @see org.skife.jdbi.v2.Folder
*/
public AccumulatorType fold(AccumulatorType accumulator, final Folder2 folder)
{
final AtomicReference acc = new AtomicReference(accumulator);
try {
this.internalExecute(new QueryResultSetMunger(this)
{
@Override
public Void munge(ResultSet rs) throws SQLException
{
while (rs.next()) {
acc.set(folder.fold(acc.get(), rs, getContext()));
}
return null;
}
});
return acc.get();
}
finally {
cleanup();
}
}
public AccumulatorType fold(final AccumulatorType accumulator,
final Folder3 folder)
{
try {
return this.internalExecute(new QueryResultSetMunger(this)
{
private int idx = 0;
private AccumulatorType ac = accumulator;
@Override
protected AccumulatorType munge(ResultSet rs) throws SQLException
{
final FoldController ctl = new FoldController(rs);
while (!ctl.isAborted() && rs.next()) {
ResultType row_value = mapper.map(idx++, rs, getContext());
this.ac = folder.fold(ac, row_value, ctl, getContext());
}
return ac;
}
});
}
finally {
cleanup();
}
}
/**
* Used to execute the query and traverse the result set with a accumulator.
* Folding over the
* result involves invoking a callback for each row, passing into the callback the return value
* from the previous function invocation.
*
* @param accumulator The initial accumulator value
* @param folder Defines the function which will fold over the result set.
*
* @return The return value from the last invocation of {@link Folder#fold(Object, java.sql.ResultSet)}
*
* @see org.skife.jdbi.v2.Folder
* @deprecated Use {@link Query#fold(Object, Folder2)}
*/
public AccumulatorType fold(AccumulatorType accumulator, final Folder folder)
{
final AtomicReference acc = new AtomicReference(accumulator);
try {
this.internalExecute(new QueryResultSetMunger(this)
{
@Override
public Void munge(ResultSet rs) throws SQLException
{
while (rs.next()) {
acc.set(folder.fold(acc.get(), rs));
}
return null;
}
});
return acc.get();
}
finally {
cleanup();
}
}
/**
* Obtain a forward-only result set iterator. Note that you must explicitely close
* the iterator to close the underlying resources.
*/
@Override
public ResultIterator iterator()
{
return this.internalExecute(new QueryResultMunger>()
{
@Override
public ResultIterator munge(Statement stmt) throws SQLException
{
return new ResultSetResultIterator(mapper,
Query.this,
stmt,
getContext());
}
});
}
/**
* Executes the select.
*
* Specifies a maximum of one result on the JDBC statement, and map that one result
* as the return value, or return null if there is nothing in the results
*
* @return first result, mapped, or null if there is no first result
*/
@Override
public ResultType first()
{
return (ResultType) first(UnwrappedSingleValue.class);
}
@Override
public T first(Class containerType)
{
// Kill Bill specific: assume our queries will always either use LIMIT 1 or will return exactly one row (see ResultReturnThing)
// This saves a roundtrip (set @@SQL_SELECT_LIMIT=1)
//addStatementCustomizer(StatementCustomizers.MAX_ROW_ONE);
ContainerBuilder builder = getContainerMapperRegistry().createBuilderFor(containerType);
return (T) this.fold(builder, new Folder3()
{
@Override
public ContainerBuilder fold(ContainerBuilder accumulator, ResultType rs, FoldController control, StatementContext ctx) throws SQLException
{
accumulator.add(rs);
control.abort();
return accumulator;
}
}).build();
}
/**
* Provide basic JavaBean mapping capabilities. Will instantiate an instance of resultType
* for each row and set the JavaBean properties which match fields in the result set.
*
* @param resultType JavaBean class to map result set fields into the properties of, by name
*
* @return a Query which provides the bean property mapping
*/
public Query map(Class resultType)
{
return this.map(new BeanMapper(resultType));
}
/**
* Makes use of registered mappers to map the result set to the desired type.
*
* @param resultType the type to map the query results to
*
* @return a new query instance which will map to the desired type
*
* @see DBI#registerMapper(org.skife.jdbi.v2.tweak.ResultSetMapper)
* @see DBI#registerMapper(ResultSetMapperFactory)
* @see Handle#registerMapper(ResultSetMapperFactory)
* @see Handle#registerMapper(org.skife.jdbi.v2.tweak.ResultSetMapper)
*/
public Query mapTo(Class resultType)
{
return this.map(new RegisteredMapper(resultType, mappingRegistry));
}
public Query map(ResultSetMapper mapper)
{
return new Query(getParameters(),
mapper,
getStatementLocator(),
getRewriter(),
getHandle(),
getStatementBuilder(),
getSql(),
getConcreteContext(),
getLog(),
getTimingCollector(),
getStatementCustomizers(),
mappingRegistry.createChild(),
getForeman().createChild(),
getContainerMapperRegistry().createChild());
}
/**
* Specify the fetch size for the query. This should cause the results to be
* fetched from the underlying RDBMS in groups of rows equal to the number passed.
* This is useful for doing chunked streaming of results when exhausting memory
* could be a problem.
*
* @param fetchSize the number of rows to fetch in a bunch
*
* @return the modified query
*/
public Query setFetchSize(final int fetchSize)
{
this.addStatementCustomizer(new StatementCustomizers.FetchSizeCustomizer(fetchSize));
return this;
}
/**
* Specify the maimum number of rows the query is to return. This uses the underlying JDBC
* {@link Statement#setMaxRows(int)}}.
*
* @param maxRows maximum number of rows to return
*
* @return modified query
*/
public Query setMaxRows(final int maxRows)
{
this.addStatementCustomizer(new StatementCustomizers.MaxRowsCustomizer(maxRows));
return this;
}
/**
* Specify the maimum field size in the result set. This uses the underlying JDBC
* {@link Statement#setMaxFieldSize(int)}
*
* @param maxFields maximum field size
*
* @return modified query
*/
public Query setMaxFieldSize(final int maxFields)
{
this.addStatementCustomizer(new StatementCustomizers.MaxFieldSizeCustomizer(maxFields));
return this;
}
/**
* Specify that the fetch order should be reversed, uses the underlying
* {@link Statement#setFetchDirection(int)}
*
* @return the modified query
*/
public Query fetchReverse()
{
setFetchDirection(ResultSet.FETCH_REVERSE);
return this;
}
/**
* Specify that the fetch order should be forward, uses the underlying
* {@link Statement#setFetchDirection(int)}
*
* @return the modified query
*/
public Query fetchForward()
{
setFetchDirection(ResultSet.FETCH_FORWARD);
return this;
}
public void registerMapper(ResultSetMapper m)
{
//this.mappingRegistry.add(new InferredMapperFactory(m));
throw new UnsupportedOperationException("[OPTIMIZATION] Registering a custom ResultSetMapper on a Query is disabled");
}
public void registerMapper(ResultSetMapperFactory m)
{
//this.mappingRegistry.add(m);
throw new UnsupportedOperationException("[OPTIMIZATION] Registering a custom ResultSetMapperFactory on a Query is disabled");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy