View Javadoc
1   package com.github.davidmoten.rx.jdbc;
2   
3   import static com.github.davidmoten.rx.jdbc.Conditions.checkNotNull;
4   import static com.github.davidmoten.rx.jdbc.Queries.bufferedParameters;
5   
6   import java.sql.ResultSet;
7   import java.util.List;
8   
9   import rx.Observable;
10  import rx.Observable.Operator;
11  import rx.functions.Func1;
12  
13  import com.github.davidmoten.rx.jdbc.NamedParameters.JdbcQuery;
14  import com.github.davidmoten.rx.jdbc.tuple.Tuple2;
15  import com.github.davidmoten.rx.jdbc.tuple.Tuple3;
16  import com.github.davidmoten.rx.jdbc.tuple.Tuple4;
17  import com.github.davidmoten.rx.jdbc.tuple.Tuple5;
18  import com.github.davidmoten.rx.jdbc.tuple.Tuple6;
19  import com.github.davidmoten.rx.jdbc.tuple.Tuple7;
20  import com.github.davidmoten.rx.jdbc.tuple.TupleN;
21  import com.github.davidmoten.rx.jdbc.tuple.Tuples;
22  
23  /**
24   * A query and its executable context.
25   */
26  final public class QuerySelect implements Query {
27  
28      // Note has one ? to match the expected one parameter
29      static final String RETURN_GENERATED_KEYS = "RETURN_GENERATED_KEYS?";
30  
31      private final Observable<Parameter> parameters;
32      private final QueryContext context;
33      private Observable<?> depends = Observable.empty();
34      private final JdbcQuery jdbcQuery;
35  
36      /**
37       * Constructor.
38       * 
39       * @param sql
40       *            jdbc select statement or the word RETURN_GENERATED_KEYS
41       * @param parameters
42       *            if sql == RETURN_GENERATED_KEYS then the first parameter will
43       *            be the ResultSet to be used as source
44       * @param depends
45       * @param context
46       */
47      QuerySelect(String sql, Observable<Parameter> parameters, Observable<?> depends,
48              QueryContext context) {
49          checkNotNull(sql);
50          checkNotNull(parameters);
51          checkNotNull(depends);
52          checkNotNull(context);
53          this.jdbcQuery = NamedParameters.parse(sql);
54          this.parameters = parameters;
55          this.depends = depends;
56          this.context = context;
57      }
58  
59      @Override
60      public String sql() {
61          return jdbcQuery.sql();
62      }
63  
64      @Override
65      public QueryContext context() {
66          return context;
67      }
68  
69      @Override
70      public Observable<Parameter> parameters() {
71          return parameters;
72      }
73  
74  
75      @Override
76      public List<String> names() {
77          return jdbcQuery.names();
78      }
79      
80      @Override
81      public String toString() {
82          return "QuerySelect [sql=" + sql() + "]";
83      }
84  
85      @Override
86      public Observable<?> depends() {
87          return depends;
88      }
89  
90      /**
91       * Returns the results of running a select query with all sets of
92       * parameters.
93       * 
94       * @return
95       */
96      public <T> Observable<T> execute(ResultSetMapper<? extends T> function) {
97          return bufferedParameters(this)
98          // execute once per set of parameters
99                  .concatMap(executeOnce(function));
100     }
101 
102     /**
103      * Returns a {@link Func1} that itself returns the results of pushing one
104      * set of parameters through a select query.
105      * 
106      * @param query
107      * @return
108      */
109     private <T> Func1<List<Parameter>, Observable<T>> executeOnce(
110             final ResultSetMapper<? extends T> function) {
111         return new Func1<List<Parameter>, Observable<T>>() {
112             @Override
113             public Observable<T> call(List<Parameter> params) {
114                 return executeOnce(params, function);
115             }
116         };
117     }
118 
119     /**
120      * Returns an Observable of the results of pushing one set of parameters
121      * through a select query.
122      * 
123      * @param params
124      *            one set of parameters to be run with the query
125      * @return
126      */
127     private <T> Observable<T> executeOnce(final List<Parameter> params,
128             ResultSetMapper<? extends T> function) {
129         return QuerySelectOnSubscribe.execute(this, params, function).subscribeOn(
130                 context.scheduler());
131     }
132 
133     /**
134      * Builds a {@link QuerySelect}.
135      */
136     public static final class Builder {
137 
138         /**
139          * Builds the standard stuff.
140          */
141         private final QueryBuilder builder;
142 
143         /**
144          * Constructor.
145          * 
146          * @param sql
147          * @param db
148          */
149         public Builder(String sql, Database db) {
150             builder = new QueryBuilder(sql, db);
151         }
152 
153         /**
154          * Appends the given parameters to the parameter list for the query. If
155          * there are more parameters than required for one execution of the
156          * query then more than one execution of the query will occur.
157          * 
158          * @param parameters
159          * @return this
160          */
161         public <T> Builder parameters(Observable<T> parameters) {
162             builder.parameters(parameters);
163             return this;
164         }
165 
166         /**
167          * Appends the given parameter values to the parameter list for the
168          * query. If there are more parameters than required for one execution
169          * of the query then more than one execution of the query will occur.
170          * 
171          * @param objects
172          * @return this
173          */
174         public Builder parameters(Object... objects) {
175             builder.parameters(objects);
176             return this;
177         }
178 
179         /**
180          * Appends a parameter to the parameter list for the query. If there are
181          * more parameters than required for one execution of the query then
182          * more than one execution of the query will occur.
183          * 
184          * @param value
185          * @return this
186          */
187         public Builder parameter(Object value) {
188             builder.parameter(value);
189             return this;
190         }
191 
192         /**
193          * Sets a named parameter. If name is null throws a
194          * {@link NullPointerException}. If value is instance of Observable then
195          * throws an {@link IllegalArgumentException}.
196          * 
197          * @param name
198          *            the parameter name. Cannot be null.
199          * @param value
200          *            the parameter value
201          */
202         public Builder parameter(String name, Object value) {
203             builder.parameter(name, value);
204             return this;
205         }
206 
207         /**
208          * Appends a dependency to the dependencies that have to complete their
209          * emitting before the query is executed.
210          * 
211          * @param dependency
212          * @return this
213          */
214         public Builder dependsOn(Observable<?> dependency) {
215             builder.dependsOn(dependency);
216             return this;
217         }
218 
219         /**
220          * Appends a dependency on the result of the last transaction (
221          * <code>true</code> for commit or <code>false</code> for rollback) to
222          * the dependencies that have to complete their emitting before the
223          * query is executed.
224          * 
225          * @return this
226          */
227         public Builder dependsOnLastTransaction() {
228             builder.dependsOnLastTransaction();
229             return this;
230         }
231 
232         /**
233          * Transforms the results using the given function.
234          * 
235          * @param function
236          * @return
237          */
238         public <T> Observable<T> get(ResultSetMapper<? extends T> function) {
239             return get(function, builder);
240         }
241 
242         static <T> Observable<T> get(ResultSetMapper<? extends T> function, QueryBuilder builder) {
243             return new QuerySelect(builder.sql(), builder.parameters(), builder.depends(),
244                     builder.context()).execute(function);
245         }
246 
247         /**
248          * <p>
249          * Transforms each row of the {@link ResultSet} into an instance of
250          * <code>T</code> using <i>automapping</i> of the ResultSet columns into
251          * corresponding constructor parameters that are assignable. Beyond
252          * normal assignable criteria (for example Integer 123 is assignable to
253          * a Double) other conversions exist to facilitate the automapping:
254          * </p>
255          * <p>
256          * They are:
257          * <ul>
258          * <li>java.sql.Blob &#10143; byte[]</li>
259          * <li>java.sql.Blob &#10143; java.io.InputStream</li>
260          * <li>java.sql.Clob &#10143; String</li>
261          * <li>java.sql.Clob &#10143; java.io.Reader</li>
262          * <li>java.sql.Date &#10143; java.util.Date</li>
263          * <li>java.sql.Date &#10143; Long</li>
264          * <li>java.sql.Timestamp &#10143; java.util.Date</li>
265          * <li>java.sql.Timestamp &#10143; Long</li>
266          * <li>java.sql.Time &#10143; java.util.Date</li>
267          * <li>java.sql.Time &#10143; Long</li>
268          * <li>java.math.BigInteger &#10143;
269          * Short,Integer,Long,Float,Double,BigDecimal</li>
270          * <li>java.math.BigDecimal &#10143;
271          * Short,Integer,Long,Float,Double,BigInteger</li>
272          * </p>
273          * 
274          * @param cls
275          * @return
276          */
277         public <T> Observable<T> autoMap(Class<T> cls) {
278             return autoMap(cls, builder);
279         }
280 
281         static <T> Observable<T> autoMap(Class<T> cls, QueryBuilder builder) {
282             Util.setSqlFromQueryAnnotation(cls, builder);
283             return get(Util.autoMap(cls), builder);
284         }
285 
286         /**
287          * Automaps the first column of the ResultSet into the target class
288          * <code>cls</code>.
289          * 
290          * @param cls
291          * @return
292          */
293         public <S> Observable<S> getAs(Class<S> cls) {
294             return get(Tuples.single(cls));
295         }
296 
297         /**
298          * Automaps all the columns of the {@link ResultSet} into the target
299          * class <code>cls</code>. See {@link #autoMap(Class) autoMap()}.
300          * 
301          * @param cls
302          * @return
303          */
304         public <S> Observable<TupleN<S>> getTupleN(Class<S> cls) {
305             return get(Tuples.tupleN(cls));
306         }
307 
308         /**
309          * Automaps all the columns of the {@link ResultSet} into {@link Object}
310          * . See {@link #autoMap(Class) autoMap()}.
311          * 
312          * @param cls
313          * @return
314          */
315         public <S> Observable<TupleN<Object>> getTupleN() {
316             return get(Tuples.tupleN(Object.class));
317         }
318 
319         /**
320          * Automaps the columns of the {@link ResultSet} into the specified
321          * classes. See {@link #autoMap(Class) autoMap()}.
322          * 
323          * @param cls1
324          * @param cls2
325          * @return
326          */
327         public <T1, T2> Observable<Tuple2<T1, T2>> getAs(Class<T1> cls1, Class<T2> cls2) {
328             return get(Tuples.tuple(cls1, cls2));
329         }
330 
331         /**
332          * Automaps the columns of the {@link ResultSet} into the specified
333          * classes. See {@link #autoMap(Class) autoMap()}.
334          * 
335          * @param cls1
336          * @param cls2
337          * @param cls3
338          * @return
339          */
340         public <T1, T2, T3> Observable<Tuple3<T1, T2, T3>> getAs(Class<T1> cls1, Class<T2> cls2,
341                 Class<T3> cls3) {
342             return get(Tuples.tuple(cls1, cls2, cls3));
343         }
344 
345         /**
346          * Automaps the columns of the {@link ResultSet} into the specified
347          * classes. See {@link #autoMap(Class) autoMap()}.
348          * 
349          * @param cls1
350          * @param cls2
351          * @param cls3
352          * @param cls4
353          * @return
354          */
355         public <T1, T2, T3, T4> Observable<Tuple4<T1, T2, T3, T4>> getAs(Class<T1> cls1,
356                 Class<T2> cls2, Class<T3> cls3, Class<T4> cls4) {
357             return get(Tuples.tuple(cls1, cls2, cls3, cls4));
358         }
359 
360         /**
361          * Automaps the columns of the {@link ResultSet} into the specified
362          * classes. See {@link #autoMap(Class) autoMap()}.
363          * 
364          * @param cls1
365          * @param cls2
366          * @param cls3
367          * @param cls4
368          * @param cls5
369          * @return
370          */
371         public <T1, T2, T3, T4, T5> Observable<Tuple5<T1, T2, T3, T4, T5>> getAs(Class<T1> cls1,
372                 Class<T2> cls2, Class<T3> cls3, Class<T4> cls4, Class<T5> cls5) {
373             return get(Tuples.tuple(cls1, cls2, cls3, cls4, cls5));
374         }
375 
376         /**
377          * Automaps the columns of the {@link ResultSet} into the specified
378          * classes. See {@link #autoMap(Class) autoMap()}.
379          * 
380          * @param cls1
381          * @param cls2
382          * @param cls3
383          * @param cls4
384          * @param cls5
385          * @param cls6
386          * @return
387          */
388         public <T1, T2, T3, T4, T5, T6> Observable<Tuple6<T1, T2, T3, T4, T5, T6>> getAs(
389                 Class<T1> cls1, Class<T2> cls2, Class<T3> cls3, Class<T4> cls4, Class<T5> cls5,
390                 Class<T6> cls6) {
391             return get(Tuples.tuple(cls1, cls2, cls3, cls4, cls5, cls6));
392         }
393 
394         /**
395          * Automaps the columns of the {@link ResultSet} into the specified
396          * classes. See {@link #autoMap(Class) autoMap()}.
397          * 
398          * @param cls1
399          * @param cls2
400          * @param cls3
401          * @param cls4
402          * @param cls5
403          * @param cls6
404          * @param cls7
405          * @return
406          */
407         public <T1, T2, T3, T4, T5, T6, T7> Observable<Tuple7<T1, T2, T3, T4, T5, T6, T7>> getAs(
408                 Class<T1> cls1, Class<T2> cls2, Class<T3> cls3, Class<T4> cls4, Class<T5> cls5,
409                 Class<T6> cls6, Class<T7> cls7) {
410             return get(Tuples.tuple(cls1, cls2, cls3, cls4, cls5, cls6, cls7));
411         }
412 
413         public Observable<Integer> count() {
414             return get(Util.toOne()).count();
415         }
416 
417         /**
418          * Returns an {@link Operator} to allow the query to be pushed
419          * parameters via the {@link Observable#lift(Operator)} method.
420          * 
421          * @return operator that acts on parameters
422          */
423         public OperatorBuilder<Object> parameterOperator() {
424             return new OperatorBuilder<Object>(this, OperatorType.PARAMETER);
425         }
426 
427         /**
428          * Returns an {@link Operator} to allow the query to be pushed
429          * dependencies via the {@link Observable#lift(Operator)} method.
430          * 
431          * @return operator that acts on dependencies
432          */
433         public OperatorBuilder<Object> dependsOnOperator() {
434             return new OperatorBuilder<Object>(this, OperatorType.DEPENDENCY);
435         }
436 
437         /**
438          * Returns an {@link Operator} that runs a select query for each list of
439          * parameter objects in the source observable.
440          * 
441          * @return
442          */
443         public OperatorBuilder<Observable<Object>> parameterListOperator() {
444             return new OperatorBuilder<Observable<Object>>(this, OperatorType.PARAMETER_LIST);
445         }
446 
447     }
448 
449     /**
450      * Builder pattern for select query {@link Operator}.
451      */
452     public static class OperatorBuilder<R> {
453 
454         private final Builder builder;
455         private final OperatorType operatorType;
456 
457         /**
458          * Constructor.
459          * 
460          * @param builder
461          * @param operatorType
462          */
463         public OperatorBuilder(Builder builder, OperatorType operatorType) {
464             this.builder = builder;
465             this.operatorType = operatorType;
466         }
467 
468         /**
469          * Transforms the results using the given function.
470          * 
471          * @param function
472          * @return
473          */
474         public <T> Operator<T, R> get(ResultSetMapper<? extends T> function) {
475             return new QuerySelectOperator<T, R>(builder, function, operatorType);
476         }
477 
478         /**
479          * See {@link Builder#autoMap(Class)}.
480          * 
481          * @param cls
482          * @return
483          */
484         public <S> Operator<S, R> autoMap(Class<S> cls) {
485             return get(Util.autoMap(cls));
486         }
487 
488         /**
489          * Automaps the first column of the ResultSet into the target class
490          * <code>cls</code>.
491          * 
492          * @param cls
493          * @return
494          */
495         public <S> Operator<S, R> getAs(Class<S> cls) {
496             return get(Tuples.single(cls));
497         }
498 
499         /**
500          * Automaps all the columns of the {@link ResultSet} into the target
501          * class <code>cls</code>. See {@link #autoMap(Class) autoMap()}.
502          * 
503          * @param cls
504          * @return
505          */
506         public <S> Operator<TupleN<S>, R> getTupleN(Class<S> cls) {
507             return get(Tuples.tupleN(cls));
508         }
509 
510         /**
511          * Automaps all the columns of the {@link ResultSet} into {@link Object}
512          * . See {@link #autoMap(Class) autoMap()}.
513          * 
514          * @param cls
515          * @return
516          */
517         public <S> Operator<TupleN<Object>, R> getTupleN() {
518             return get(Tuples.tupleN(Object.class));
519         }
520 
521         /**
522          * Automaps the columns of the {@link ResultSet} into the specified
523          * classes. See {@link #autoMap(Class) autoMap()}.
524          * 
525          * @param cls1
526          * @param cls2
527          * @return
528          */
529         public <T1, T2> Operator<Tuple2<T1, T2>, R> getAs(Class<T1> cls1, Class<T2> cls2) {
530             return get(Tuples.tuple(cls1, cls2));
531         }
532 
533         /**
534          * Automaps the columns of the {@link ResultSet} into the specified
535          * classes. See {@link #autoMap(Class) autoMap()}.
536          * 
537          * @param cls1
538          * @param cls2
539          * @param cls3
540          * @return
541          */
542         public <T1, T2, T3> Operator<Tuple3<T1, T2, T3>, R> getAs(Class<T1> cls1, Class<T2> cls2,
543                 Class<T3> cls3) {
544             return get(Tuples.tuple(cls1, cls2, cls3));
545         }
546 
547         /**
548          * Automaps the columns of the {@link ResultSet} into the specified
549          * classes. See {@link #autoMap(Class) autoMap()}.
550          * 
551          * @param cls1
552          * @param cls2
553          * @param cls3
554          * @param cls4
555          * @return
556          */
557         public <T1, T2, T3, T4> Operator<Tuple4<T1, T2, T3, T4>, R> getAs(Class<T1> cls1,
558                 Class<T2> cls2, Class<T3> cls3, Class<T4> cls4) {
559             return get(Tuples.tuple(cls1, cls2, cls3, cls4));
560         }
561 
562         /**
563          * Automaps the columns of the {@link ResultSet} into the specified
564          * classes. See {@link #autoMap(Class) autoMap()}.
565          * 
566          * @param cls1
567          * @param cls2
568          * @param cls3
569          * @param cls4
570          * @param cls5
571          * @return
572          */
573         public <T1, T2, T3, T4, T5> Operator<Tuple5<T1, T2, T3, T4, T5>, R> getAs(Class<T1> cls1,
574                 Class<T2> cls2, Class<T3> cls3, Class<T4> cls4, Class<T5> cls5) {
575             return get(Tuples.tuple(cls1, cls2, cls3, cls4, cls5));
576         }
577 
578         /**
579          * Automaps the columns of the {@link ResultSet} into the specified
580          * classes. See {@link #autoMap(Class) autoMap()}.
581          * 
582          * @param cls1
583          * @param cls2
584          * @param cls3
585          * @param cls4
586          * @param cls5
587          * @param cls6
588          * @return
589          */
590         public <T1, T2, T3, T4, T5, T6> Operator<Tuple6<T1, T2, T3, T4, T5, T6>, R> getAs(
591                 Class<T1> cls1, Class<T2> cls2, Class<T3> cls3, Class<T4> cls4, Class<T5> cls5,
592                 Class<T6> cls6) {
593             return get(Tuples.tuple(cls1, cls2, cls3, cls4, cls5, cls6));
594         }
595 
596         /**
597          * Automaps the columns of the {@link ResultSet} into the specified
598          * classes. See {@link #autoMap(Class) autoMap()}.
599          * 
600          * @param cls1
601          * @param cls2
602          * @param cls3
603          * @param cls4
604          * @param cls5
605          * @param cls6
606          * @param cls7
607          * @return
608          */
609         public <T1, T2, T3, T4, T5, T6, T7> Operator<Tuple7<T1, T2, T3, T4, T5, T6, T7>, R> getAs(
610                 Class<T1> cls1, Class<T2> cls2, Class<T3> cls3, Class<T4> cls4, Class<T5> cls5,
611                 Class<T6> cls6, Class<T7> cls7) {
612             return get(Tuples.tuple(cls1, cls2, cls3, cls4, cls5, cls6, cls7));
613         }
614 
615     }
616 
617 }