View Javadoc
1   package org.davidmoten.rx.jdbc;
2   
3   import java.util.ArrayList;
4   import java.util.Arrays;
5   import java.util.Collections;
6   import java.util.List;
7   
8   import javax.annotation.Nonnull;
9   
10  import com.github.davidmoten.guavamini.Preconditions;
11  
12  import io.reactivex.Flowable;
13  
14  abstract class ParametersBuilder<T> {
15  
16      private static final Flowable<List<Object>> SINGLE_EMPTY_LIST = Flowable.just(Collections.emptyList());
17  
18      private final List<Flowable<List<Object>>> parameterGroups = new ArrayList<>();
19      // for building up a number of parameters
20      private final List<Object> parameterBuffer = new ArrayList<>();
21      private final SqlInfo sqlInfo;
22  
23      ParametersBuilder(@Nonnull String sql) {
24          this.sqlInfo = SqlInfo.parse(sql);
25      }
26  
27      @SuppressWarnings("unchecked")
28      public final T parameterStream(@Nonnull Flowable<?> values) {
29          Preconditions.checkNotNull(values);
30          if (sqlInfo.numParameters() == 0) {
31              parameterListStream(values.map(x -> Collections.emptyList()));
32          } else {
33              parameterListStream((Flowable<List<?>>) (Flowable<?>) values.buffer(sqlInfo.numParameters()));
34          }
35          return (T) this;
36      }
37  
38      @SuppressWarnings("unchecked")
39      public final T parameterListStream(@Nonnull Flowable<List<?>> valueLists) {
40          Preconditions.checkNotNull(valueLists, "valueLists cannot be null");
41          useAndCloseParameterBuffer();
42          parameterGroups.add((Flowable<List<Object>>) (Flowable<?>) valueLists);
43          return (T) this;
44      }
45  
46      public final T parameters(@Nonnull List<?> values) {
47          return parameterList(values.toArray());
48      }
49  
50      @SuppressWarnings("unchecked")
51      public final T parameter(@Nonnull String name, Object value) {
52          Preconditions.checkNotNull(name, "name cannot be null");
53          parameterBuffer.add(new Parameter(name, value));
54          return (T) this;
55      }
56  
57      public final T parameter(Object value) {
58          return parameters(value);
59      }
60  
61      public final T parameters(@Nonnull Object... values) {
62          return parameterList(values);
63      }
64  
65      @SuppressWarnings("unchecked")
66      private final T parameterList(Object[] values) {
67          Preconditions.checkNotNull(values);
68          if (values.length == 0) {
69              // no effect
70              return (T) this;
71          }
72          Preconditions.checkArgument(sqlInfo.numParameters() == 0 || values.length % sqlInfo.numParameters() == 0,
73                  "number of values should be a multiple of number of parameters in sql: " + sqlInfo.sql());
74          Preconditions.checkArgument(Arrays.stream(values)
75                  .allMatch(o -> sqlInfo.names().isEmpty() || (o instanceof Parameter && ((Parameter) o).hasName())));
76          for (Object val : values) {
77              if (val == null) {
78                  parameterBuffer.add(Parameter.NULL);
79              } else {
80                  parameterBuffer.add(val);
81              }
82          }
83          return (T) this;
84      }
85  
86      final Flowable<List<Object>> parameterGroupsToFlowable() {
87          useAndCloseParameterBuffer();
88          Flowable<List<Object>> pg;
89          if (parameterGroups.isEmpty()) {
90              pg = SINGLE_EMPTY_LIST;
91          } else {
92              pg = Flowable.concat(parameterGroups);
93          }
94          return pg;
95      }
96  
97      private void useAndCloseParameterBuffer() {
98          // called when about to add stream of parameters or about to call get
99          if (!parameterBuffer.isEmpty()) {
100             Flowable<List<Object>> p;
101             if (sqlInfo.numParameters() > 0) {
102                 p = Flowable //
103                         .fromIterable(new ArrayList<>(parameterBuffer)) //
104                         .buffer(sqlInfo.numParameters());
105             } else {
106                 p = Flowable //
107                         .fromIterable(new ArrayList<>(parameterBuffer)) //
108                         .map(x -> Collections.emptyList());
109             }
110             parameterGroups.add(p);
111             parameterBuffer.clear();
112         }
113     }
114 
115 }