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)); } } }