Package org.skife.jdbi.v2

Source Code of org.skife.jdbi.v2.Query

/*
* Copyright 2004-2007 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.exceptions.ResultSetException;
import org.skife.jdbi.v2.exceptions.UnableToCreateStatementException;
import org.skife.jdbi.v2.exceptions.UnableToExecuteStatementException;
import org.skife.jdbi.v2.tweak.ResultSetMapper;
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 org.skife.jdbi.v2.tweak.SQLLog;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
* Statement prviding convenience result handling for SQL queries.
*/
public class Query<ResultType> extends SQLStatement<Query<ResultType>> implements Iterable<ResultType>
{
    private final ResultSetMapper<ResultType> mapper;

    Query(Binding params,
          ResultSetMapper<ResultType> mapper,
          StatementLocator locator,
          StatementRewriter statementRewriter,
          Connection connection,
          StatementBuilder cache,
          String sql,
          StatementContext ctx,
          SQLLog log)
    {
        super(params, locator, statementRewriter, connection, cache, sql, ctx, log);
        this.mapper = mapper;
    }

    /**
     * Executes the select
     * <p/>
     * Will eagerly load all results
     *
     * @throws UnableToCreateStatementException
     *                            if there is an error creating the statement
     * @throws UnableToExecuteStatementException
     *                            if there is an error executing the statement
     * @throws ResultSetException if there is an error dealing with the result set
     */
    public List<ResultType> list()
    {
        return this.internalExecute(QueryPreperator.NO_OP, new QueryResultMunger<List<ResultType>>()
        {
            public List<ResultType> munge(Statement stmt) throws SQLException
            {
                ResultSet rs = stmt.getResultSet();
                List<ResultType> result_list = new ArrayList<ResultType>();
                int index = 0;
                while (rs.next()) {
                    result_list.add(mapper.map(index++, rs, getContext()));
                }
                return result_list;
            }
        }, QueryPostMungeCleanup.CLOSE_RESOURCES_QUIETLY);
    }

    /**
     * Executes the select
     * <p/>
     * Will eagerly load all results up to a maximum of <code>maxRows</code>
     *
     * @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 UnableToCreateStatementException
     *                            if there is an error creating the statement
     * @throws UnableToExecuteStatementException
     *                            if there is an error executing the statement
     * @throws ResultSetException if there is an error dealing with the result set
     */
    public List<ResultType> list(final int maxRows)
    {
        return this.internalExecute(QueryPreperator.NO_OP, new QueryResultMunger<List<ResultType>>()
        {
            public List<ResultType> munge(Statement stmt) throws SQLException
            {
                ResultSet rs = stmt.getResultSet();
                List<ResultType> result_list = new ArrayList<ResultType>();
                int index = 0;
                while (rs.next() && index < maxRows) {
                    result_list.add(mapper.map(index++, rs, getContext()));
                }
                return result_list;
            }
        }, QueryPostMungeCleanup.CLOSE_RESOURCES_QUIETLY);
    }

    /**
     * Used to execute the query and traverse the result set with a accumulator.
     * <a href="http://en.wikipedia.org/wiki/Fold_(higher-order_function)">Folding</a> 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> AccumulatorType fold(AccumulatorType accumulator, final Folder<AccumulatorType> folder)
    {
        final AtomicReference<AccumulatorType> acc = new AtomicReference<AccumulatorType>(accumulator);

        this.internalExecute(QueryPreperator.NO_OP, new QueryResultMunger<Void>()
        {
            public Void munge(Statement stmt) throws SQLException
            {
                ResultSet rs = stmt.getResultSet();
                while (rs.next()) {
                    acc.set(folder.fold(acc.get(), rs));
                }
                return null;
            }
        }, QueryPostMungeCleanup.CLOSE_RESOURCES_QUIETLY);
        return acc.get();
    }

    /**
     * Obtain a forward-only result set iterator. Note that you must explicitely close
     * the iterator to close the underlying resources.
     */
    public ResultIterator<ResultType> iterator()
    {
        /**
         * Okay, so this is a bit dodgy. It relies on the internal behavior so beware :-)
         *
         * Basically, the cleaner will be called right after execution and will *not* do anything
         * except store the values. When the iterator is closed, it will be called again and will
         * close the stored values
         */
        final QueryPostMungeCleanup cleaner = new QueryPostMungeCleanup()
        {
            private boolean skipNextClose = true;
            private SQLStatement query;
            private Statement stmt;
            private ResultSet rs;

            public void cleanup(SQLStatement query, Statement stmt, ResultSet rs)
            {
                if (skipNextClose) {
                    this.query = query;
                    this.stmt = stmt;
                    this.rs = rs;
                    skipNextClose = false;
                }
                else {
                    QueryPostMungeCleanup.CLOSE_RESOURCES_QUIETLY.cleanup(this.query, this.stmt, this.rs);
                }
            }
        };

        return this.internalExecute(QueryPreperator.NO_OP, new QueryResultMunger<ResultIterator<ResultType>>()
        {
            public ResultIterator<ResultType> munge(Statement results) throws SQLException
            {

                return new ResultSetResultIterator<ResultType>(mapper,
                                                               cleaner,
                                                               results.getResultSet(),
                                                               getContext());
            }
        }, cleaner);
    }

    /**
     * Executes the select.
     * <p/>
     * 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
     */
    public ResultType first()
    {
        return this.internalExecute(QueryPreperator.MAX_ROWS_ONE, new QueryResultMunger<ResultType>()
        {
            public final ResultType munge(final Statement stt) throws SQLException
            {
                ResultSet rs = stt.getResultSet();
                if (rs.next()) {
                    return mapper.map(0, rs, getContext());
                }
                else {
                    // no result matches
                    return null;
                }
            }
        }, QueryPostMungeCleanup.CLOSE_RESOURCES_QUIETLY);
    }

    /**
     * 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 <Type> Query<Type> map(Class<Type> resultType)
    {
        return this.map(new BeanMapper<Type>(resultType));
    }

    public <T> Query<T> map(ResultSetMapper<T> mapper)
    {
        return new Query<T>(getParameters(),
                            mapper,
                            getStatementLocator(),
                            getRewriter(),
                            getConnection(),
                            getStatementBuilder(),
                            getSql(),
                            getContext(),
                            getLog());
    }

    /**
     * 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 i the number of rows to fetch in a bunch
     *
     * @return the modified query
     */
    public Query<ResultType> setFetchSize(final int i)
    {
        this.addStatementCustomizer(new StatementCustomizer()
        {
            public void beforeExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException
            {
                stmt.setFetchSize(i);
            }

            public void afterExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException
            {
            }
        });
        return this;
    }

    /**
     * Specify the maimum number of rows the query is to return. This uses the underlying JDBC
     * {@link Statement#setMaxRows(int)}}.
     *
     * @param i maximum number of rows to return
     *
     * @return modified query
     */
    public Query<ResultType> setMaxRows(final int i)
    {
        this.addStatementCustomizer(new StatementCustomizer()
        {
            public void beforeExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException
            {
                stmt.setMaxRows(i);
            }

            public void afterExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException
            {
            }
        });
        return this;
    }

    /**
     * Specify the maimum field size in the result set. This uses the underlying JDBC
     * {@link Statement#setMaxFieldSize(int)}
     *
     * @param i maximum field size
     *
     * @return modified query
     */
    public Query<ResultType> setMaxFieldSize(final int i)
    {
        this.addStatementCustomizer(new StatementCustomizer()
        {
            public void beforeExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException
            {
                stmt.setMaxFieldSize(i);
            }

            public void afterExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException
            {
            }

        });
        return this;
    }

    /**
     * Specify that the fetch order should be reversed, uses the underlying
     * {@link Statement#setFetchDirection(int)}
     *
     * @return the modified query
     */
    public Query<ResultType> fetchReverse()
    {
        this.addStatementCustomizer(new StatementCustomizer()
        {
            public void beforeExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException
            {
                stmt.setFetchDirection(ResultSet.FETCH_REVERSE);
            }

            public void afterExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException
            {
            }

        });
        return this;
    }

    /**
     * Specify that the fetch order should be forward, uses the underlying
     * {@link Statement#setFetchDirection(int)}
     *
     * @return the modified query
     */
    public Query<ResultType> fetchForward()
    {
        this.addStatementCustomizer(new StatementCustomizer()
        {
            public void beforeExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException
            {
                stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
            }

            public void afterExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException
            {
            }

        });
        return this;
    }
}
TOP

Related Classes of org.skife.jdbi.v2.Query

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.