All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.davidmoten.rx.jdbc.QuerySelect Maven / Gradle / Ivy

There is a newer version: 0.7.19
Show newest version
package com.github.davidmoten.rx.jdbc;

import static com.github.davidmoten.rx.jdbc.Conditions.checkNotNull;
import static com.github.davidmoten.rx.jdbc.Queries.bufferedParameters;

import java.sql.ResultSet;
import java.util.List;

import rx.Observable;
import rx.Observable.Operator;
import rx.functions.Func1;

import com.github.davidmoten.rx.RxUtil;
import com.github.davidmoten.rx.jdbc.tuple.Tuple2;
import com.github.davidmoten.rx.jdbc.tuple.Tuple3;
import com.github.davidmoten.rx.jdbc.tuple.Tuple4;
import com.github.davidmoten.rx.jdbc.tuple.Tuple5;
import com.github.davidmoten.rx.jdbc.tuple.Tuple6;
import com.github.davidmoten.rx.jdbc.tuple.Tuple7;
import com.github.davidmoten.rx.jdbc.tuple.TupleN;
import com.github.davidmoten.rx.jdbc.tuple.Tuples;

/**
 * A query and its executable context.
 */
final public class QuerySelect implements Query {

    private final String sql;
    private final Observable parameters;
    private final QueryContext context;
    private Observable depends = Observable.empty();

    /**
     * Constructor.
     * 
     * @param sql
     * @param parameters
     * @param depends
     * @param context
     */
    private QuerySelect(String sql, Observable parameters, Observable depends,
            QueryContext context) {
        checkNotNull(sql);
        checkNotNull(parameters);
        checkNotNull(depends);
        checkNotNull(context);
        this.sql = sql;
        this.parameters = parameters;
        this.depends = depends;
        this.context = context;
    }

    @Override
    public String sql() {
        return sql;
    }

    @Override
    public QueryContext context() {
        return context;
    }

    @Override
    public Observable parameters() {
        return parameters;
    }

    @Override
    public String toString() {
        return "QuerySelect [sql=" + sql + "]";
    }

    @Override
    public Observable depends() {
        return depends;
    }

    /**
     * Returns the results of running a select query with all sets of
     * parameters.
     * 
     * @return
     */
    public  Observable execute(Func1 function) {
        return bufferedParameters(this)
        // execute once per set of parameters
                .concatMap(executeOnce(function));
    }

    /**
     * Returns a {@link Func1} that itself returns the results of pushing one
     * set of parameters through a select query.
     * 
     * @param query
     * @return
     */
    private  Func1, Observable> executeOnce(
            final Func1 function) {
        return new Func1, Observable>() {
            @Override
            public Observable call(List params) {
                return executeOnce(params, function);
            }
        };
    }

    /**
     * Returns an Observable of the results of pushing one set of parameters
     * through a select query.
     * 
     * @param params
     *            one set of parameters to be run with the query
     * @return
     */
    private  Observable executeOnce(final List params,
            Func1 function) {
        return QuerySelectOperation.execute(this, params, function)
                .subscribeOn(context.scheduler());
    }

    /**
     * Builds a {@link QuerySelect}.
     */
    final public static class Builder {

        /**
         * Builds the standard stuff.
         */
        private final QueryBuilder builder;

        /**
         * Constructor.
         * 
         * @param sql
         * @param db
         */
        public Builder(String sql, Database db) {
            builder = new QueryBuilder(sql, db);
        }

        /**
         * Appends the given parameters to the parameter list for the query. If
         * there are more parameters than required for one execution of the
         * query then more than one execution of the query will occur.
         * 
         * @param parameters
         * @return this
         */
        public  Builder parameters(Observable parameters) {
            builder.parameters(parameters);
            return this;
        }

        /**
         * Appends the given parameter values to the parameter list for the
         * query. If there are more parameters than required for one execution
         * of the query then more than one execution of the query will occur.
         * 
         * @param objects
         * @return this
         */
        public Builder parameters(Object... objects) {
            builder.parameters(objects);
            return this;
        }

        /**
         * Appends a parameter to the parameter list for the query. If there are
         * more parameters than required for one execution of the query then
         * more than one execution of the query will occur.
         * 
         * @param value
         * @return this
         */
        public Builder parameter(Object value) {
            builder.parameter(value);
            return this;
        }

        /**
         * Appends a dependency to the dependencies that have to complete their
         * emitting before the query is executed.
         * 
         * @param dependency
         * @return this
         */
        public Builder dependsOn(Observable dependency) {
            builder.dependsOn(dependency);
            return this;
        }

        /**
         * Appends a dependency on the result of the last transaction (
         * true for commit or false for rollback) to
         * the dependencies that have to complete their emitting before the
         * query is executed.
         * 
         * @return this
         */
        public Builder dependsOnLastTransaction() {
            builder.dependsOnLastTransaction();
            return this;
        }

        /**
         * Transforms the results using the given function.
         * 
         * @param function
         * @return
         */
        public  Observable get(Func1 function) {
            return new QuerySelect(builder.sql(), builder.parameters(), builder.depends(),
                    builder.context()).execute(function);
        }

        /**
         * 

* Transforms each row of the {@link ResultSet} into an instance of * T using automapping of the ResultSet columns into * corresponding constructor parameters that are assignable. Beyond * normal assignable criteria (for example Integer 123 is assignable to * a Double) other conversions exist to facilitate the automapping: *

*

* They are: *

    *
  • java.sql.Blob ➟ byte[]
  • *
  • java.sql.Blob ➟ java.io.InputStream
  • *
  • java.sql.Clob ➟ String
  • *
  • java.sql.Clob ➟ java.io.Reader
  • *
  • java.sql.Date ➟ java.util.Date
  • *
  • java.sql.Date ➟ Long
  • *
  • java.sql.Timestamp ➟ java.util.Date
  • *
  • java.sql.Timestamp ➟ Long
  • *
  • java.sql.Time ➟ java.util.Date
  • *
  • java.sql.Time ➟ Long
  • *
  • java.math.BigInteger ➟ * Short,Integer,Long,Float,Double,BigDecimal
  • *
  • java.math.BigDecimal ➟ * Short,Integer,Long,Float,Double,BigInteger
  • *

    * * @param cls * @return */ public Observable autoMap(Class cls) { return get(Util.autoMap(cls)); } /** * Automaps the first column of the ResultSet into the target class * cls. * * @param cls * @return */ public Observable getAs(Class cls) { return get(Tuples.single(cls)); } /** * Automaps all the columns of the {@link ResultSet} into the target * class cls. See {@link #autoMap(Class) autoMap()}. * * @param cls * @return */ public Observable> getTupleN(Class cls) { return get(Tuples.tupleN(cls)); } /** * Automaps all the columns of the {@link ResultSet} into {@link Object} * . See {@link #autoMap(Class) autoMap()}. * * @param cls * @return */ public Observable> getTupleN() { return get(Tuples.tupleN(Object.class)); } /** * Automaps the columns of the {@link ResultSet} into the specified * classes. See {@link #autoMap(Class) autoMap()}. * * @param cls1 * @param cls2 * @return */ public Observable> getAs(Class cls1, Class cls2) { return get(Tuples.tuple(cls1, cls2)); } /** * Automaps the columns of the {@link ResultSet} into the specified * classes. See {@link #autoMap(Class) autoMap()}. * * @param cls1 * @param cls2 * @param cls3 * @return */ public Observable> getAs(Class cls1, Class cls2, Class cls3) { return get(Tuples.tuple(cls1, cls2, cls3)); } /** * Automaps the columns of the {@link ResultSet} into the specified * classes. See {@link #autoMap(Class) autoMap()}. * * @param cls1 * @param cls2 * @param cls3 * @param cls4 * @return */ public Observable> getAs(Class cls1, Class cls2, Class cls3, Class cls4) { return get(Tuples.tuple(cls1, cls2, cls3, cls4)); } /** * Automaps the columns of the {@link ResultSet} into the specified * classes. See {@link #autoMap(Class) autoMap()}. * * @param cls1 * @param cls2 * @param cls3 * @param cls4 * @param cls5 * @return */ public Observable> getAs(Class cls1, Class cls2, Class cls3, Class cls4, Class cls5) { return get(Tuples.tuple(cls1, cls2, cls3, cls4, cls5)); } /** * Automaps the columns of the {@link ResultSet} into the specified * classes. See {@link #autoMap(Class) autoMap()}. * * @param cls1 * @param cls2 * @param cls3 * @param cls4 * @param cls5 * @param cls6 * @return */ public Observable> getAs( Class cls1, Class cls2, Class cls3, Class cls4, Class cls5, Class cls6) { return get(Tuples.tuple(cls1, cls2, cls3, cls4, cls5, cls6)); } /** * Automaps the columns of the {@link ResultSet} into the specified * classes. See {@link #autoMap(Class) autoMap()}. * * @param cls1 * @param cls2 * @param cls3 * @param cls4 * @param cls5 * @param cls6 * @param cls7 * @return */ public Observable> getAs( Class cls1, Class cls2, Class cls3, Class cls4, Class cls5, Class cls6, Class cls7) { return get(Tuples.tuple(cls1, cls2, cls3, cls4, cls5, cls6, cls7)); } public Observable count() { return get(RxUtil. constant(1)).count(); } /** * Returns an {@link Operator} to allow the query to be pushed * parameters via the {@link Observable#lift(Operator)} method. * * @return operator that acts on parameters */ public OperatorBuilder parameterOperator() { return new OperatorBuilder(this, OperatorType.PARAMETER); } /** * Returns an {@link Operator} to allow the query to be pushed * dependencies via the {@link Observable#lift(Operator)} method. * * @return operator that acts on dependencies */ public OperatorBuilder dependsOnOperator() { return new OperatorBuilder(this, OperatorType.DEPENDENCY); } /** * Returns an {@link Operator} that runs a select query for each list of * parameter objects in the source observable. * * @return */ public OperatorBuilder> parameterListOperator() { return new OperatorBuilder>(this, OperatorType.PARAMETER_LIST); } } /** * Builder pattern for select query {@link Operator}. */ public static class OperatorBuilder { private final Builder builder; private final OperatorType operatorType; /** * Constructor. * * @param builder * @param operatorType */ public OperatorBuilder(Builder builder, OperatorType operatorType) { this.builder = builder; this.operatorType = operatorType; } /** * Transforms the results using the given function. * * @param function * @return */ public Operator get(Func1 function) { return new QuerySelectOperator(builder, function, operatorType); } /** * See {@link Builder#autoMap(Class)}. * * @param cls * @return */ public Operator autoMap(Class cls) { return get(Util.autoMap(cls)); } /** * Automaps the first column of the ResultSet into the target class * cls. * * @param cls * @return */ public Operator getAs(Class cls) { return get(Tuples.single(cls)); } /** * Automaps all the columns of the {@link ResultSet} into the target * class cls. See {@link #autoMap(Class) autoMap()}. * * @param cls * @return */ public Operator, R> getTupleN(Class cls) { return get(Tuples.tupleN(cls)); } /** * Automaps all the columns of the {@link ResultSet} into {@link Object} * . See {@link #autoMap(Class) autoMap()}. * * @param cls * @return */ public Operator, R> getTupleN() { return get(Tuples.tupleN(Object.class)); } /** * Automaps the columns of the {@link ResultSet} into the specified * classes. See {@link #autoMap(Class) autoMap()}. * * @param cls1 * @param cls2 * @return */ public Operator, R> getAs(Class cls1, Class cls2) { return get(Tuples.tuple(cls1, cls2)); } /** * Automaps the columns of the {@link ResultSet} into the specified * classes. See {@link #autoMap(Class) autoMap()}. * * @param cls1 * @param cls2 * @param cls3 * @return */ public Operator, R> getAs(Class cls1, Class cls2, Class cls3) { return get(Tuples.tuple(cls1, cls2, cls3)); } /** * Automaps the columns of the {@link ResultSet} into the specified * classes. See {@link #autoMap(Class) autoMap()}. * * @param cls1 * @param cls2 * @param cls3 * @param cls4 * @return */ public Operator, R> getAs(Class cls1, Class cls2, Class cls3, Class cls4) { return get(Tuples.tuple(cls1, cls2, cls3, cls4)); } /** * Automaps the columns of the {@link ResultSet} into the specified * classes. See {@link #autoMap(Class) autoMap()}. * * @param cls1 * @param cls2 * @param cls3 * @param cls4 * @param cls5 * @return */ public Operator, R> getAs(Class cls1, Class cls2, Class cls3, Class cls4, Class cls5) { return get(Tuples.tuple(cls1, cls2, cls3, cls4, cls5)); } /** * Automaps the columns of the {@link ResultSet} into the specified * classes. See {@link #autoMap(Class) autoMap()}. * * @param cls1 * @param cls2 * @param cls3 * @param cls4 * @param cls5 * @param cls6 * @return */ public Operator, R> getAs( Class cls1, Class cls2, Class cls3, Class cls4, Class cls5, Class cls6) { return get(Tuples.tuple(cls1, cls2, cls3, cls4, cls5, cls6)); } /** * Automaps the columns of the {@link ResultSet} into the specified * classes. See {@link #autoMap(Class) autoMap()}. * * @param cls1 * @param cls2 * @param cls3 * @param cls4 * @param cls5 * @param cls6 * @param cls7 * @return */ public Operator, R> getAs( Class cls1, Class cls2, Class cls3, Class cls4, Class cls5, Class cls6, Class cls7) { return get(Tuples.tuple(cls1, cls2, cls3, cls4, cls5, cls6, cls7)); } } }