View Javadoc
1   package org.davidmoten.rx.jdbc;
2   
3   import java.sql.Connection;
4   import java.sql.ResultSet;
5   import java.util.ArrayList;
6   import java.util.Collections;
7   import java.util.List;
8   import java.util.stream.Collectors;
9   
10  import org.davidmoten.rx.jdbc.callable.CallableResultSet1;
11  import org.davidmoten.rx.jdbc.callable.CallableResultSet2;
12  import org.davidmoten.rx.jdbc.callable.CallableResultSet3;
13  import org.davidmoten.rx.jdbc.callable.CallableResultSet4;
14  import org.davidmoten.rx.jdbc.callable.CallableResultSetN;
15  import org.davidmoten.rx.jdbc.callable.internal.Getter1;
16  import org.davidmoten.rx.jdbc.callable.internal.Getter2;
17  import org.davidmoten.rx.jdbc.callable.internal.Getter3;
18  import org.davidmoten.rx.jdbc.callable.internal.Getter4;
19  import org.davidmoten.rx.jdbc.callable.internal.GetterN;
20  import org.davidmoten.rx.jdbc.callable.internal.In;
21  import org.davidmoten.rx.jdbc.callable.internal.InOut;
22  import org.davidmoten.rx.jdbc.callable.internal.InParameterPlaceholder;
23  import org.davidmoten.rx.jdbc.callable.internal.Out;
24  import org.davidmoten.rx.jdbc.callable.internal.ParameterPlaceholder;
25  import org.davidmoten.rx.jdbc.tuple.Tuple2;
26  import org.davidmoten.rx.jdbc.tuple.Tuple3;
27  import org.davidmoten.rx.jdbc.tuple.Tuple4;
28  import org.davidmoten.rx.jdbc.tuple.TupleN;
29  
30  import com.github.davidmoten.guavamini.Lists;
31  import com.github.davidmoten.guavamini.Preconditions;
32  
33  import io.reactivex.Completable;
34  import io.reactivex.Flowable;
35  import io.reactivex.Single;
36  import io.reactivex.functions.Function;
37  
38  public final class CallableBuilder implements Getter1 {
39  
40      final String sql;
41      final List<ParameterPlaceholder> params = new ArrayList<>();
42  
43      Flowable<?> inStream;
44  
45      final Single<Connection> connection;
46      final Database db;
47  
48      public CallableBuilder(String sql, Single<Connection> connection, Database db) {
49          this.sql = sql;
50          this.connection = connection;
51          this.db = db;
52      }
53  
54      public TransactedCallableBuilder transacted() {
55          return new TransactedCallableBuilder(this);
56      }
57  
58      @SuppressWarnings("unchecked")
59      public Flowable<List<Object>> parameterGroups() {
60          int numInParameters = params.stream() //
61                  .filter(x -> x instanceof InParameterPlaceholder) //
62                  .collect(Collectors.counting()).intValue();
63          if (numInParameters == 0) {
64              return inStream.map(x -> Collections.singletonList(x));
65          } else {
66              return (Flowable<List<Object>>) (Flowable<?>) inStream.buffer(numInParameters);
67          }
68      }
69  
70      public CallableBuilder in() {
71          params.add(In.IN);
72          return this;
73      }
74  
75      public Completable input(Flowable<?> f) {
76          Preconditions.checkArgument(inStream == null, "you can only specify in flowable once, current=" + inStream);
77          this.inStream = f;
78          return build();
79      }
80  
81      public Completable once() {
82          return input(1);
83      }
84  
85      public Completable input(Object... objects) {
86          return input(Flowable.fromArray(objects));
87      }
88  
89      public <T> CallableBuilder1<T> inOut(Type type, Class<T> cls) {
90          params.add(new InOut(type, cls));
91          return new CallableBuilder1<T>(this, cls);
92      }
93  
94      public <T> CallableBuilder1<T> out(Type type, Class<T> cls) {
95          params.add(new Out(type, cls));
96          return new CallableBuilder1<T>(this, cls);
97      }
98  
99      @Override
100     public <T> CallableResultSets1Builder<T> get(Function<? super ResultSet, ? extends T> function) {
101         return new CallableResultSets1Builder<T>(this, function);
102     }
103 
104     public <T> CallableResultSets1Builder<T> autoMap(Class<T> cls) {
105         return get(Util.autoMap(cls));
106     }
107 
108     private Completable build() {
109         return Call.createWithZeroOutParameters(connection, sql, parameterGroups(), params).ignoreElements();
110     }
111 
112     public static final class CallableBuilder1<T1> implements Getter1 {
113 
114         private final CallableBuilder b;
115         private final Class<T1> cls;
116 
117         public CallableBuilder1(CallableBuilder b, Class<T1> cls) {
118             this.b = b;
119             this.cls = cls;
120         }
121 
122         public CallableBuilder1<T1> in() {
123             b.in();
124             return this;
125         }
126 
127         public <T2> CallableBuilder2<T1, T2> out(Type type, Class<T2> cls2) {
128             b.out(type, cls2);
129             return new CallableBuilder2<T1, T2>(b, cls, cls2);
130         }
131 
132         public <T2> CallableBuilder2<T1, T2> inOut(Type type, Class<T2> cls2) {
133             b.inOut(type, cls2);
134             return new CallableBuilder2<T1, T2>(b, cls, cls2);
135         }
136 
137         public Flowable<T1> input(Flowable<?> f) {
138             b.input(f);
139             return build();
140         }
141 
142         public Flowable<T1> input(Object... objects) {
143             return input(Flowable.fromArray(objects));
144         }
145 
146         @Override
147         public <T> CallableResultSets1Builder<T> get(Function<? super ResultSet, ? extends T> function) {
148             return new CallableResultSets1Builder<T>(b, function);
149         }
150 
151         public <T> CallableResultSets1Builder<T> autoMap(Class<T> cls) {
152             return get(Util.autoMap(cls));
153         }
154 
155         private Flowable<T1> build() {
156             return Call.createWithOneOutParameter(b.connection, b.sql, b.parameterGroups(), b.params, cls) //
157                     .dematerialize();
158         }
159     }
160 
161     public static final class CallableBuilder2<T1, T2> implements Getter1 {
162 
163         private final CallableBuilder b;
164         private final Class<T1> cls1;
165         private final Class<T2> cls2;
166 
167         public CallableBuilder2(CallableBuilder b, Class<T1> cls1, Class<T2> cls2) {
168             this.b = b;
169             this.cls1 = cls1;
170             this.cls2 = cls2;
171         }
172 
173         public <T3> CallableBuilder3<T1, T2, T3> out(Type type, Class<T3> cls3) {
174             b.out(type, cls3);
175             return new CallableBuilder3<T1, T2, T3>(b, cls1, cls2, cls3);
176         }
177 
178         public Flowable<Tuple2<T1, T2>> input(Flowable<?> f) {
179             b.input(f);
180             return build();
181         }
182 
183         public CallableBuilder2<T1, T2> in() {
184             b.in();
185             return this;
186         }
187 
188         public Flowable<Tuple2<T1, T2>> input(Object... objects) {
189             return input(Flowable.fromArray(objects));
190         }
191 
192         public <T3> CallableBuilder3<T1, T2, T3> inOut(Type type, Class<T3> cls3) {
193             b.inOut(type, cls3);
194             return new CallableBuilder3<T1, T2, T3>(b, cls1, cls2, cls3);
195         }
196 
197         @Override
198         public <T> CallableResultSets1Builder<T> get(Function<? super ResultSet, ? extends T> function) {
199             return new CallableResultSets1Builder<T>(b, function);
200         }
201 
202         public <T> CallableResultSets1Builder<T> autoMap(Class<T> cls) {
203             return get(Util.autoMap(cls));
204         }
205 
206         private Flowable<Tuple2<T1, T2>> build() {
207             return Call.createWithTwoOutParameters(b.connection, b.sql, b.parameterGroups(), b.params, cls1, cls2) //
208                     .dematerialize();
209         }
210     }
211 
212     public static final class CallableBuilder3<T1, T2, T3> implements Getter1 {
213 
214         private final CallableBuilder b;
215         private final Class<T1> cls1;
216         private final Class<T2> cls2;
217         private final Class<T3> cls3;
218 
219         public CallableBuilder3(CallableBuilder b, Class<T1> cls1, Class<T2> cls2, Class<T3> cls3) {
220             this.b = b;
221             this.cls1 = cls1;
222             this.cls2 = cls2;
223             this.cls3 = cls3;
224         }
225 
226         public <T4> CallableBuilder4<T1, T2, T3, T4> out(Type type, Class<T4> cls4) {
227             b.out(type, cls4);
228             return new CallableBuilder4<T1, T2, T3, T4>(b, cls1, cls2, cls3, cls4);
229         }
230 
231         public Flowable<Tuple3<T1, T2, T3>> input(Flowable<?> f) {
232             b.input(f);
233             return build();
234         }
235 
236         public CallableBuilder3<T1, T2, T3> in() {
237             b.in();
238             return this;
239         }
240 
241         public Flowable<Tuple3<T1, T2, T3>> input(Object... objects) {
242             return input(Flowable.fromArray(objects));
243         }
244 
245         public <T4> CallableBuilder4<T1, T2, T3, T4> inOut(Type type, Class<T4> cls4) {
246             b.inOut(type, cls4);
247             return new CallableBuilder4<T1, T2, T3, T4>(b, cls1, cls2, cls3, cls4);
248         }
249 
250         @Override
251         public <T> CallableResultSets1Builder<T> get(Function<? super ResultSet, ? extends T> function) {
252             return new CallableResultSets1Builder<T>(b, function);
253         }
254 
255         public <T> CallableResultSets1Builder<T> autoMap(Class<T> cls) {
256             return get(Util.autoMap(cls));
257         }
258 
259         private Flowable<Tuple3<T1, T2, T3>> build() {
260             return Call
261                     .createWithThreeOutParameters(b.connection, b.sql, b.parameterGroups(), b.params, cls1, cls2, cls3) //
262                     .dematerialize();
263         }
264     }
265 
266     public static final class CallableBuilder4<T1, T2, T3, T4> implements Getter1 {
267 
268         private final CallableBuilder b;
269         private final Class<T1> cls1;
270         private final Class<T2> cls2;
271         private final Class<T3> cls3;
272         private final Class<T4> cls4;
273 
274         public CallableBuilder4(CallableBuilder b, Class<T1> cls1, Class<T2> cls2, Class<T3> cls3, Class<T4> cls4) {
275             this.b = b;
276             this.cls1 = cls1;
277             this.cls2 = cls2;
278             this.cls3 = cls3;
279             this.cls4 = cls4;
280         }
281 
282         public Flowable<Tuple4<T1, T2, T3, T4>> input(Flowable<?> f) {
283             b.input(f);
284             return build();
285         }
286 
287         public CallableBuilder4<T1, T2, T3, T4> in() {
288             b.in();
289             return this;
290         }
291 
292         public Flowable<Tuple4<T1, T2, T3, T4>> input(Object... objects) {
293             return input(Flowable.fromArray(objects));
294         }
295 
296         public CallableBuilderN inOut(Type type, Class<T3> cls5) {
297             b.inOut(type, cls5);
298             return new CallableBuilderN(b, Lists.newArrayList(cls1, cls2, cls3, cls4, cls5));
299         }
300 
301         public CallableBuilderN out(Type type, Class<?> cls5) {
302             b.out(type, cls5);
303             return new CallableBuilderN(b, Lists.newArrayList(cls1, cls2, cls3, cls4, cls5));
304         }
305 
306         @Override
307         public <T> CallableResultSets1Builder<T> get(Function<? super ResultSet, ? extends T> function) {
308             return new CallableResultSets1Builder<T>(b, function);
309         }
310 
311         public <T> CallableResultSets1Builder<T> autoMap(Class<T> cls) {
312             return get(Util.autoMap(cls));
313         }
314 
315         private Flowable<Tuple4<T1, T2, T3, T4>> build() {
316             return Call
317                     .createWithFourOutParameters(b.connection, b.sql, b.parameterGroups(), b.params, cls1, cls2, cls3,
318                             cls4) //
319                     .dematerialize();
320         }
321     }
322 
323     public static final class CallableBuilderN implements Getter1 {
324 
325         private final CallableBuilder b;
326         private final List<Class<?>> outClasses;
327 
328         public CallableBuilderN(CallableBuilder b, List<Class<?>> outClasses) {
329             this.b = b;
330             this.outClasses = outClasses;
331         }
332 
333         public Flowable<TupleN<Object>> input(Flowable<?> f) {
334             b.input(f);
335             return build();
336         }
337 
338         public CallableBuilderN in() {
339             b.in();
340             return this;
341         }
342 
343         public Flowable<TupleN<Object>> input(Object... objects) {
344             return input(Flowable.fromArray(objects));
345         }
346 
347         public CallableBuilderN out(Type type, Class<?> cls) {
348             b.out(type, cls);
349             return new CallableBuilderN(b, createList(outClasses, cls));
350         }
351 
352         @Override
353         public <T> CallableResultSets1Builder<T> get(Function<? super ResultSet, ? extends T> function) {
354             return new CallableResultSets1Builder<T>(b, function);
355         }
356 
357         public <T> CallableResultSets1Builder<T> autoMap(Class<T> cls) {
358             return get(Util.autoMap(cls));
359         }
360 
361         private Flowable<TupleN<Object>> build() {
362             return Call.createWithNParameters(b.connection, b.sql, b.parameterGroups(), b.params, outClasses) //
363                     .dematerialize();
364         }
365 
366     }
367 
368     public static final class CallableResultSets1Builder<T1> implements Getter2<T1> {
369 
370         private final CallableBuilder b;
371         private final Function<? super ResultSet, ? extends T1> f1;
372 
373         CallableResultSets1Builder(CallableBuilder b, Function<? super ResultSet, ? extends T1> function) {
374             this.b = b;
375             this.f1 = function;
376         }
377 
378         public CallableResultSets1Builder<T1> out(Type type, Class<?> cls5) {
379             b.out(type, cls5);
380             return this;
381         }
382 
383         public <T2> CallableResultSets2Builder<T1, T2> autoMap(Class<T2> cls) {
384             return get(Util.autoMap(cls));
385         }
386 
387         public <T2> CallableResultSets2Builder<T1, T2> get(Function<? super ResultSet, ? extends T2> f2) {
388             return new CallableResultSets2Builder<T1, T2>(b, f1, f2);
389         }
390 
391         public Flowable<CallableResultSet1<T1>> input(Flowable<?> f) {
392             b.input(f);
393             return build();
394         }
395 
396         public CallableResultSets1Builder<T1> in() {
397             b.in();
398             return this;
399         }
400 
401         public Flowable<CallableResultSet1<T1>> input(Object... objects) {
402             return input(Flowable.fromArray(objects));
403         }
404 
405         public CallableResultSets1Builder<T1> inOut(Type type, Class<?> cls) {
406             b.inOut(type, cls);
407             return this;
408         }
409 
410         private Flowable<CallableResultSet1<T1>> build() {
411             return Call.createWithOneResultSet(b.connection, b.sql, b.parameterGroups(), b.params, f1, 0) //
412                     .dematerialize();
413         }
414 
415     }
416 
417     public static final class CallableResultSets2Builder<T1, T2> implements Getter3<T1, T2> {
418 
419         private final CallableBuilder b;
420         private final Function<? super ResultSet, ? extends T1> f1;
421         private final Function<? super ResultSet, ? extends T2> f2;
422 
423         CallableResultSets2Builder(CallableBuilder b, Function<? super ResultSet, ? extends T1> f1,
424                 Function<? super ResultSet, ? extends T2> f2) {
425             this.b = b;
426             this.f1 = f1;
427             this.f2 = f2;
428         }
429 
430         public CallableResultSets2Builder<T1, T2> out(Type type, Class<?> cls5) {
431             b.out(type, cls5);
432             return this;
433         }
434 
435         public Flowable<CallableResultSet2<T1, T2>> input(Flowable<?> f) {
436             b.input(f);
437             return build();
438         }
439 
440         public CallableResultSets2Builder<T1, T2> in() {
441             b.in();
442             return this;
443         }
444 
445         public Flowable<CallableResultSet2<T1, T2>> input(Object... objects) {
446             return input(Flowable.fromArray(objects));
447         }
448 
449         public CallableResultSets2Builder<T1, T2> inOut(Type type, Class<?> cls) {
450             b.inOut(type, cls);
451             return this;
452         }
453 
454         public <T3> CallableResultSets3Builder<T1, T2, T3> autoMap(Class<T3> cls) {
455             return get(Util.autoMap(cls));
456         }
457 
458         public <T3> CallableResultSets3Builder<T1, T2, T3> get(Function<? super ResultSet, ? extends T3> f3) {
459             return new CallableResultSets3Builder<T1, T2, T3>(b, f1, f2, f3);
460         }
461 
462         private Flowable<CallableResultSet2<T1, T2>> build() {
463             return Call.createWithTwoResultSets(b.connection, b.sql, b.parameterGroups(), b.params, f1, f2, 0) //
464                     .dematerialize();
465         }
466     }
467 
468     public static final class CallableResultSets3Builder<T1, T2, T3> implements Getter4<T1, T2, T3> {
469 
470         private final CallableBuilder b;
471         private final Function<? super ResultSet, ? extends T1> f1;
472         private final Function<? super ResultSet, ? extends T2> f2;
473         private final Function<? super ResultSet, ? extends T3> f3;
474 
475         CallableResultSets3Builder(CallableBuilder b, Function<? super ResultSet, ? extends T1> f1,
476                 Function<? super ResultSet, ? extends T2> f2, Function<? super ResultSet, ? extends T3> f3) {
477             this.b = b;
478             this.f1 = f1;
479             this.f2 = f2;
480             this.f3 = f3;
481         }
482 
483         public CallableResultSets3Builder<T1, T2, T3> out(Type type, Class<?> cls5) {
484             b.out(type, cls5);
485             return this;
486         }
487 
488         public CallableResultSets3Builder<T1, T2, T3> in() {
489             b.in();
490             return this;
491         }
492 
493         public Flowable<CallableResultSet3<T1, T2, T3>> input(Flowable<?> f) {
494             b.input(f);
495             return build();
496         }
497 
498         public Flowable<CallableResultSet3<T1, T2, T3>> input(Object... objects) {
499             return input(Flowable.fromArray(objects));
500         }
501 
502         public CallableResultSets3Builder<T1, T2, T3> inOut(Type type, Class<?> cls) {
503             b.inOut(type, cls);
504             return this;
505         }
506 
507         public <T4> CallableResultSets4Builder<T1, T2, T3, T4> autoMap(Class<T4> cls) {
508             return get(Util.autoMap(cls));
509         }
510 
511         public <T4> CallableResultSets4Builder<T1, T2, T3, T4> get(Function<? super ResultSet, ? extends T4> f4) {
512             return new CallableResultSets4Builder<T1, T2, T3, T4>(b, f1, f2, f3, f4);
513         }
514 
515         private Flowable<CallableResultSet3<T1, T2, T3>> build() {
516             return Call.createWithThreeResultSets(b.connection, b.sql, b.parameterGroups(), b.params, f1, f2, f3, 0) //
517                     .dematerialize();
518         }
519     }
520 
521     public static final class CallableResultSets4Builder<T1, T2, T3, T4> implements GetterN {
522 
523         private final CallableBuilder b;
524         private final Function<? super ResultSet, ? extends T1> f1;
525         private final Function<? super ResultSet, ? extends T2> f2;
526         private final Function<? super ResultSet, ? extends T3> f3;
527         private final Function<? super ResultSet, ? extends T4> f4;
528 
529         CallableResultSets4Builder(CallableBuilder b, Function<? super ResultSet, ? extends T1> f1,
530                 Function<? super ResultSet, ? extends T2> f2, Function<? super ResultSet, ? extends T3> f3,
531                 Function<? super ResultSet, ? extends T4> f4) {
532             this.b = b;
533             this.f1 = f1;
534             this.f2 = f2;
535             this.f3 = f3;
536             this.f4 = f4;
537         }
538 
539         public CallableResultSets4Builder<T1, T2, T3, T4> out(Type type, Class<?> cls5) {
540             b.out(type, cls5);
541             return this;
542         }
543 
544         public CallableResultSets4Builder<T1, T2, T3, T4> in() {
545             b.in();
546             return this;
547         }
548 
549         public Flowable<CallableResultSet4<T1, T2, T3, T4>> input(Flowable<?> f) {
550             b.input(f);
551             return build();
552         }
553 
554         public Flowable<CallableResultSet4<T1, T2, T3, T4>> input(Object... objects) {
555             return input(Flowable.fromArray(objects));
556         }
557 
558         public CallableResultSets4Builder<T1, T2, T3, T4> inOut(Type type, Class<?> cls) {
559             b.inOut(type, cls);
560             return this;
561         }
562 
563         public <T> CallableResultSetsNBuilder autoMap(Class<T> cls) {
564             return get(Util.autoMap(cls));
565         }
566 
567         @SuppressWarnings("unchecked")
568         public CallableResultSetsNBuilder get(Function<? super ResultSet, ?> f5) {
569             return new CallableResultSetsNBuilder(b, Lists.newArrayList(f1, f2, f3, f4, f5));
570         }
571 
572         public Flowable<CallableResultSet4<T1, T2, T3, T4>> build() {
573             return Call.createWithFourResultSets(b.connection, b.sql, b.parameterGroups(), b.params, f1, f2, f3, f4, 0)
574                     .dematerialize();
575         }
576     }
577 
578     public static final class CallableResultSetsNBuilder {
579 
580         private final CallableBuilder b;
581         private final List<Function<? super ResultSet, ?>> functions;
582 
583         CallableResultSetsNBuilder(CallableBuilder b, List<Function<? super ResultSet, ?>> functions) {
584             this.b = b;
585             this.functions = functions;
586         }
587 
588         public CallableResultSetsNBuilder in() {
589             b.in();
590             return this;
591         }
592 
593         public Flowable<CallableResultSetN> input(Flowable<?> f) {
594             b.input(f);
595             return build();
596         }
597 
598         public Flowable<CallableResultSetN> input(Object... objects) {
599             return input(Flowable.fromArray(objects));
600         }
601 
602         public CallableResultSetsNBuilder inOut(Type type, Class<?> cls) {
603             b.inOut(type, cls);
604             return this;
605         }
606 
607         public <T> CallableResultSetsNBuilder autoMap(Class<T> cls) {
608             return get(Util.autoMap(cls));
609         }
610 
611         public CallableResultSetsNBuilder get(Function<? super ResultSet, ?> f) {
612             functions.add(f);
613             return this;
614         }
615 
616         private Flowable<CallableResultSetN> build() {
617             return Call.createWithNResultSets(b.connection, b.sql, b.parameterGroups(), b.params, functions, 0) //
618                     .dematerialize();
619         }
620     }
621 
622     private static <T> List<T> createList(List<T> list, T t) {
623         ArrayList<T> r = new ArrayList<>(list);
624         r.add(t);
625         return r;
626     }
627 
628 }