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 }