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 ➟ byte[]</li>
259 * <li>java.sql.Blob ➟ java.io.InputStream</li>
260 * <li>java.sql.Clob ➟ String</li>
261 * <li>java.sql.Clob ➟ java.io.Reader</li>
262 * <li>java.sql.Date ➟ java.util.Date</li>
263 * <li>java.sql.Date ➟ Long</li>
264 * <li>java.sql.Timestamp ➟ java.util.Date</li>
265 * <li>java.sql.Timestamp ➟ Long</li>
266 * <li>java.sql.Time ➟ java.util.Date</li>
267 * <li>java.sql.Time ➟ Long</li>
268 * <li>java.math.BigInteger ➟
269 * Short,Integer,Long,Float,Double,BigDecimal</li>
270 * <li>java.math.BigDecimal ➟
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 }