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 }