54 } |
54 } |
55 |
55 |
56 /** |
56 /** |
57 * A mutable handle to one value of an ordered sequence of columns of a row or |
57 * A mutable handle to one value of an ordered sequence of columns of a row or |
58 * of out parameters. Columns have a 1-based index and optionally an |
58 * of out parameters. Columns have a 1-based index and optionally an |
59 * identifier. Identifiers are not guaranteed to be unique. Only {@code clone} |
59 * identifier. Identifiers are not guaranteed to be unique. |
60 * and {@code slice} create new instances. All other methods return this |
60 * <br> |
61 * instance (modifying it if necessary) including {@code forEach}, |
61 * A newly created Column is initially positioned on the first column of |
62 * {@code next}, and {@code iterator}. |
62 * it's sequence. The position is modified by calls to {@link #at(int)}, |
|
63 * {@link #at(String)}, {@link #next()}, or {@link #next(int)}. |
|
64 * The methods {@link #clone()}, {@link #slice(int)}, |
|
65 * {@link #forEach(Consumer)}, and {@link #iterator()} create new instances. |
|
66 * All other methods return this instance (modifying it if necessary) |
|
67 * including {@link #next()}, and {@link #forEachRemaining(Consumer)}. |
|
68 * <br> |
|
69 * In cases where the result of an operation has no columns, an instance of |
|
70 * this class may represent an empty sequence of columns. Instances |
|
71 * associated to the empty sequence return 0 from calls to {@link #index()} |
|
72 * and {@link #absoluteIndex()}. It is illegal to modify the position or |
|
73 * accesses any attribute of a column if the sequence is empty. |
63 */ |
74 */ |
64 public interface Column extends Result, Iterable<Column>, Iterator<Column>, Cloneable { |
75 public interface Column extends Result, Iterable<Column>, Iterator<Column>, Cloneable { |
65 |
76 |
66 /** |
77 /** |
67 * Return the value of this column as an instance of the given type. |
78 * Return the value of this column as an instance of the given type. |
68 * |
79 * |
69 * @param <T> |
80 * @param <T> |
70 * @param type |
81 * @param type |
71 * @return the value of this {@link Column} |
82 * @return the value of this {@link Column} |
|
83 * @throws IllegalStateException if the column sequence is empty. |
72 */ |
84 */ |
73 public <T> T get(Class<T> type); |
85 public <T> T get(Class<T> type); |
74 |
86 |
75 /** |
87 /** |
76 * Return the value of this {@link Column} as an instance of the default |
88 * Return the value of this {@link Column} as an instance of the default |
77 * Java type for this column. |
89 * Java type for this column. |
78 * |
90 * |
79 * @param <T> |
91 * @param <T> |
80 * @return the value of this {@link Column} |
92 * @return the value of this {@link Column} |
|
93 * @throws IllegalStateException if the column sequence is empty. |
81 */ |
94 */ |
82 public default <T> T get() { |
95 public default <T> T get() { |
83 return get(javaType()); |
96 return get(javaType()); |
84 } |
97 } |
85 |
98 |
86 /** |
99 /** |
87 * Return the identifier of this {@link Column}. May be null. |
100 * Return the identifier of this {@link Column}. May be null. |
88 * |
101 * |
89 * @return the identifier of this {@link Column}. May be null |
102 * @return the identifier of this {@link Column}. May be null |
|
103 * @throws IllegalStateException if the column sequence is empty. |
90 */ |
104 */ |
91 public String identifier(); |
105 public String identifier(); |
92 |
106 |
93 /** |
107 /** |
94 * Return the 1-based index of this {@link Column}. The returned value is |
108 * Return the 1-based index of this {@link Column}. If the column |
95 * relative to the slice if this {@link Column} is the result of a call to |
109 * sequence is empty, the return value is 0. |
96 * {@code slice()}. {@code |
110 * <br> |
97 * col.slice(n).index() == 1}. |
111 * The returned value is relative to the slice if this {@link Column} is |
98 * |
112 * the result of a call to {@link #slice(int)}. |
|
113 * <br> |
|
114 * {@code col.slice(n).index() == 1}. |
|
115 * <br> |
|
116 * {@code col.slice(n).next().index() == 2}. |
|
117 * |
99 * @return the index of this {@link Column} |
118 * @return the index of this {@link Column} |
100 */ |
119 */ |
101 public int index(); |
120 public int index(); |
102 |
121 |
103 /** |
122 /** |
104 * Return the 1-based index of this {@link Column} relative to the original |
123 * Return the 1-based index of this {@link Column} relative to the original |
105 * sequence of values. |
124 * sequence of values. If the column sequence is empty, the return value |
|
125 * is 0. |
|
126 * <br> |
106 * {@code col.absoluteIndex() == col.slice(n).absoluteIndex()}. |
127 * {@code col.absoluteIndex() == col.slice(n).absoluteIndex()}. |
107 * |
128 * |
108 * @return the absolute 1-based index of this {@link Column} |
129 * @return the absolute 1-based index of this {@link Column} |
109 */ |
130 */ |
110 public int absoluteIndex(); |
131 public int absoluteIndex(); |
111 |
132 |
112 /** |
133 /** |
113 * Return the SQL type of the value of this {@link Column}. |
134 * Return the SQL type of the value of this {@link Column}. |
114 * |
135 * |
115 * @return the SQL type of this value |
136 * @return the SQL type of this value |
|
137 * @throws IllegalStateException if the column sequence is empty. |
116 */ |
138 */ |
117 public SqlType sqlType(); |
139 public SqlType sqlType(); |
118 |
140 |
119 /** |
141 /** |
120 * Return the Java type that best represents the value of this |
142 * Return the Java type that best represents the value of this |
121 * {@link Column}. |
143 * {@link Column}. |
122 * |
144 * |
123 * @param <T> |
145 * @param <T> |
124 * @return a {@link Class} that best represents the value of this |
146 * @return a {@link Class} that best represents the value of this |
125 * {@link Column} |
147 * {@link Column} |
|
148 * @throws IllegalStateException if the column sequence is empty. |
126 */ |
149 */ |
127 public <T>Class<T> javaType(); |
150 public <T>Class<T> javaType(); |
128 |
151 |
129 /** |
152 /** |
130 * The length of the current value if defined. |
153 * The length of the current value if defined. |
131 * |
154 * |
132 * @return |
155 * @return |
133 * @throws UnsupportedOperationException if the length of the current value |
156 * @throws UnsupportedOperationException if the length of the current value |
134 * is undefined |
157 * is undefined |
|
158 * @throws IllegalStateException if the column sequence is empty. |
135 */ |
159 */ |
136 public long length(); |
160 public long length(); |
137 |
161 |
138 /** |
162 /** |
139 * Return the number of remaining values accessible by this {@link Column} |
163 * Return the number of remaining values accessible by this {@link Column} |
156 * information. |
180 * information. |
157 * |
181 * |
158 * @param id an identifier. Not null |
182 * @param id an identifier. Not null |
159 * @return this {@link Column} |
183 * @return this {@link Column} |
160 * @throws NoSuchElementException if id does not identify exactly one value |
184 * @throws NoSuchElementException if id does not identify exactly one value |
|
185 * @throws IllegalStateException if the column sequence is empty. |
161 */ |
186 */ |
162 public Column at(String id); |
187 public Column at(String id); |
163 |
188 |
164 /** |
189 /** |
165 * Modify this {@link Column} to point to the value at {@code index}. The |
190 * Modify this {@link Column} to point to the value at {@code index}. The |
166 * first value is at index 1. Negative numbers count back from the last |
191 * first value is at index 1. Negative numbers count back from the last |
167 * value. The last value is at index -1. |
192 * value. The last value is at index -1. |
168 * |
193 * |
169 * @param index a new index |
194 * @param index a new index |
170 * @return this {@link Column} |
195 * @return this {@link Column} |
171 * @throws NoSuchElementException if {@code index > length} or |
196 * @throws NoSuchElementException if {@code index > length}, |
172 * {@code index < -length} |
197 * {@code index < -length}, or {@code index == 0} |
|
198 * @throws IllegalStateException if the column sequence is empty. |
173 */ |
199 */ |
174 public Column at(int index); |
200 public Column at(int index); |
175 |
201 |
176 /** |
202 /** |
177 * Modify this {@link Column} to point to the value at the current index + |
203 * Modify this {@link Column} to point to the value at the current index + |
178 * {@code offset}. If {@code offset} is 0 this is a noop. If {@code offset} |
204 * {@code offset}. If {@code offset} is 0 this is a noop. If {@code offset} |
179 * is negative the new index is less than the current index. If the new |
205 * is negative the new index is less than the current index. If the new |
180 * index would be less than 1 or greater than length this {@link Column} is |
206 * index would be less than 1 or greater than the sequence length this |
181 * not modified and {@link IllegalArgumentException} is thrown. |
207 * {@link Column} is not modified and {@link IllegalArgumentException} is |
|
208 * thrown. |
182 * |
209 * |
183 * @param offset an increment to the current index |
210 * @param offset an increment to the current index |
184 * @return this {@link Column} |
211 * @return this {@link Column} |
185 * @throws NoSuchElementException if the new index would be less than 1 or |
212 * @throws NoSuchElementException if the new index would be less than 1 or |
186 * greater than {@code length} |
213 * greater than the sequence length. |
|
214 * @throws IllegalStateException if the column sequence is empty. |
187 */ |
215 */ |
188 public default Column next(int offset) { |
216 public default Column next(int offset) { |
|
217 if (index() == 0) { |
|
218 throw new IllegalStateException(); |
|
219 } |
189 int newIndex = index() + offset; |
220 int newIndex = index() + offset; |
190 if (offset > numberOfValuesRemaining() || newIndex < 1) { |
221 if (offset > numberOfValuesRemaining() || newIndex < 1) { |
191 throw new NoSuchElementException(); |
222 throw new NoSuchElementException(); |
192 } |
223 } |
193 return at(newIndex); |
224 return at(newIndex); |
197 * Return a new {@link Column} that is a handle to a subsequence of the |
228 * Return a new {@link Column} that is a handle to a subsequence of the |
198 * sequence of values referenced by this {@link Column}. The subsequence |
229 * sequence of values referenced by this {@link Column}. The subsequence |
199 * consists of {@code numValues} number of values. If {@code numValues} is |
230 * consists of {@code numValues} number of values. If {@code numValues} is |
200 * positive the values are the value of this column and its successors. If |
231 * positive the values are the value of this column and its successors. If |
201 * {@code numValues} is negative the values are the predecessors of this |
232 * {@code numValues} is negative the values are the predecessors of this |
202 * column not including this {@link Column}. The order of the values of the |
233 * column not including this {@link Column}. |
203 * new {@link Column} is the same as the order of the values of this |
234 * <br> |
204 * {@link Column}. The returned {@link Column} points to the first value of |
235 * The returned {@link Column} is positioned on the first value of the |
205 * the slice. This {@link Column} is not modified. |
236 * slice. |
|
237 * <br> |
|
238 * The order of the values of the new {@link Column} is the same as the |
|
239 * order of the values of this {@link Column}. This {@link Column} |
|
240 * is not modified. |
206 * |
241 * |
207 * @param numValues the number of columns to include in the slice |
242 * @param numValues the number of columns to include in the slice |
208 * @return a new {@link Column}. |
243 * @return a new {@link Column}. |
209 * @throws NoSuchElementException if the current index plus |
244 * @throws NoSuchElementException if the current index plus |
210 * {@code numValues} is greater than the number of values of this |
245 * {@code numValues} is greater than the sequence length or less than 1 |
211 * {@link Column} or less than 1 |
246 * @throws IllegalStateException if the column sequence is empty. |
212 */ |
247 */ |
213 public Column slice(int numValues); |
248 public Column slice(int numValues); |
214 |
249 |
215 /** |
250 /** |
216 * Return a new {@link Column} that is a duplicate of this {@link Column}. |
251 * Return a new {@link Column} that is a duplicate of this {@link Column}. |
223 /** |
258 /** |
224 * Modify this {@link Column} to point to the next value in the sequence. |
259 * Modify this {@link Column} to point to the next value in the sequence. |
225 * |
260 * |
226 * @return this {@link Column} |
261 * @return this {@link Column} |
227 * @throws NoSuchElementException if the new index would be greater than |
262 * @throws NoSuchElementException if the new index would be greater than |
228 * {@code length} |
263 * the sequence length. |
229 */ |
264 * @throws IllegalStateException if the column sequence is empty. |
230 @Override |
265 */ |
231 public default Column next() { |
266 public default Column next() { |
232 return next(1); |
267 return next(1); |
233 } |
268 } |
234 |
269 |
|
270 /** |
|
271 * {@inheritDoc} |
|
272 */ |
235 @Override |
273 @Override |
236 public default boolean hasNext() { |
274 public default boolean hasNext() { |
237 return numberOfValuesRemaining() > 0; |
275 return numberOfValuesRemaining() > 0; |
238 } |
276 } |
239 |
277 |
|
278 /** |
|
279 * {@inheritDoc} |
|
280 */ |
240 @Override |
281 @Override |
241 public default void forEach(Consumer<? super Column> action) { |
282 public default void forEach(Consumer<? super Column> action) { |
242 do { |
283 if (index() == 0) { |
243 action.accept(this); |
284 return; |
244 if (!hasNext()) break; |
285 } |
245 next(); |
286 action.accept(this.clone()); |
246 } while (true); |
287 while (hasNext()) { |
247 } |
288 action.accept(next().clone()); |
248 |
289 } |
|
290 } |
|
291 |
|
292 /** |
|
293 * {@inheritDoc} |
|
294 */ |
249 @Override |
295 @Override |
250 public default Column iterator() { |
296 public default Iterator<Column> iterator() { |
251 return this.clone(); |
297 return new Iterator<Column>() { |
|
298 Column next = Column.this.index() == 0 ? null : Column.this.clone(); |
|
299 |
|
300 @Override |
|
301 public boolean hasNext() { |
|
302 return next != null; |
|
303 } |
|
304 |
|
305 @Override |
|
306 public Column next() { |
|
307 if (!hasNext()) { |
|
308 throw new NoSuchElementException(); |
|
309 } |
|
310 |
|
311 Column prev = next.clone(); |
|
312 |
|
313 if (next.hasNext()) { |
|
314 next.next(); |
|
315 } |
|
316 else { |
|
317 next = null; |
|
318 } |
|
319 |
|
320 return prev; |
|
321 } |
|
322 }; |
252 } |
323 } |
253 |
324 |
254 /** |
325 /** |
255 * TODO This almost certainly works correctly but it doesn't integrate well |
326 * TODO This almost certainly works correctly but it doesn't integrate well |
256 * with the other access patterns. A better approach would be a Spliterator |
327 * with the other access patterns. A better approach would be a Spliterator |