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