1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.graph.query.process;
25
26 import java.util.Collections;
27 import java.util.Iterator;
28 import java.util.List;
29 import net.jcip.annotations.Immutable;
30 import org.modeshape.common.collection.ImmutableProblems;
31 import org.modeshape.common.collection.Problems;
32 import org.modeshape.common.collection.SimpleProblems;
33 import org.modeshape.common.util.StringUtil;
34 import org.modeshape.graph.GraphI18n;
35 import org.modeshape.graph.Location;
36 import org.modeshape.graph.query.model.TypeSystem;
37 import org.modeshape.graph.query.model.TypeSystem.TypeFactory;
38
39
40
41
42 @Immutable
43 public class QueryResults implements org.modeshape.graph.query.QueryResults {
44 private static final Problems NO_PROBLEMS = new ImmutableProblems(new SimpleProblems());
45
46 private static final long serialVersionUID = 1L;
47
48 private final Problems problems;
49 private final Columns columns;
50 private final List<Object[]> tuples;
51 private final Statistics statistics;
52 private final String plan;
53
54
55
56
57
58
59
60
61
62
63 public QueryResults( Columns columns,
64 Statistics statistics,
65 List<Object[]> tuples,
66 Problems problems,
67 String plan ) {
68 assert columns != null;
69 assert statistics != null;
70 this.problems = problems != null ? problems : NO_PROBLEMS;
71 this.columns = columns;
72 this.tuples = tuples;
73 this.statistics = statistics;
74 this.plan = plan;
75 }
76
77
78
79
80
81
82
83
84 public QueryResults( Columns columns,
85 Statistics statistics,
86 List<Object[]> tuples ) {
87 this(columns, statistics, tuples, NO_PROBLEMS, null);
88 }
89
90
91
92
93
94
95
96
97 public QueryResults( Columns columns,
98 Statistics statistics,
99 Problems problems ) {
100 this(columns, statistics, Collections.<Object[]>emptyList(), problems, null);
101 }
102
103
104
105
106
107
108
109 public QueryResults( Columns columns,
110 Statistics statistics ) {
111 this(columns, statistics, Collections.<Object[]>emptyList(), null, null);
112 }
113
114
115
116
117
118
119 public Columns getColumns() {
120 return columns;
121 }
122
123
124
125
126
127
128 public Cursor getCursor() {
129 return new TupleCursor(columns, tuples.iterator());
130 }
131
132
133
134
135
136
137 public List<Object[]> getTuples() {
138 return tuples;
139 }
140
141
142
143
144
145
146 public int getRowCount() {
147 return tuples.size();
148 }
149
150
151
152
153
154
155 public String getPlan() {
156 return plan;
157 }
158
159
160
161
162
163
164 public Problems getProblems() {
165 return problems;
166 }
167
168
169
170
171
172
173 public boolean hasErrors() {
174 return getProblems().hasErrors();
175 }
176
177
178
179
180
181
182 public boolean hasWarnings() {
183 return getProblems().hasWarnings();
184 }
185
186
187
188
189
190
191 public Statistics getStatistics() {
192 return statistics;
193 }
194
195
196
197
198
199
200 @Override
201 public String toString() {
202 return toString(null, Integer.MAX_VALUE);
203 }
204
205
206
207
208
209
210
211
212
213 public String toString( TypeSystem typeSystem,
214 int maxTuples ) {
215 StringBuilder sb = new StringBuilder();
216 toString(typeSystem, sb, maxTuples);
217 return sb.toString();
218 }
219
220
221
222
223
224
225
226
227 public void toString( TypeSystem typeSystem,
228 StringBuilder sb ) {
229 toString(typeSystem, sb, Integer.MAX_VALUE);
230 }
231
232
233
234
235
236
237
238
239
240 public void toString( TypeSystem typeSystem,
241 StringBuilder sb,
242 int maxTuples ) {
243 int[] columnWidths = determineColumnWidths(typeSystem, Integer.MAX_VALUE, true);
244 printDelimiterLine(sb, columnWidths, true);
245 printHeader(sb, columnWidths);
246 printDelimiterLine(sb, columnWidths, true);
247 printLines(typeSystem, sb, columnWidths, maxTuples);
248 printDelimiterLine(sb, columnWidths, false);
249 }
250
251
252
253
254
255
256
257
258
259
260 protected int[] determineColumnWidths( TypeSystem typeSystem,
261 int maxWidth,
262 boolean useData ) {
263 assert maxWidth > 0;
264 int tupleLength = columns.getTupleSize();
265 int[] columnWidths = new int[tupleLength + 1];
266 for (int i = 0; i != columnWidths.length; ++i) {
267 columnWidths[i] = 0;
268 }
269
270 String rowNumber = Integer.toString(getTuples().size());
271 columnWidths[0] = rowNumber.length();
272
273
274 List<String> tupleValueNames = columns.getTupleValueNames();
275 for (int i = 0, j = 1, max = tupleValueNames.size(); i != max; ++i, ++j) {
276 String name = tupleValueNames.get(i);
277 columnWidths[j] = Math.max(Math.min(maxWidth, name.length()), columnWidths[j]);
278 }
279
280 if (useData) {
281 for (Object[] tuple : getTuples()) {
282 for (int i = 0, j = 1; i != tupleLength; ++i, ++j) {
283 String valueStr = stringOf(typeSystem, tuple[i]);
284 if (valueStr == null) continue;
285 columnWidths[j] = Math.max(Math.min(maxWidth, valueStr.length()), columnWidths[j]);
286 }
287 }
288 }
289 return columnWidths;
290 }
291
292 protected String stringOf( TypeSystem typeSystem,
293 Object value ) {
294 if (value == null) return null;
295 if (typeSystem == null) return value.toString();
296 TypeFactory<?> typeFactory = typeSystem.getTypeFactory(value);
297 return typeFactory.asReadableString(value);
298 }
299
300 protected void printHeader( StringBuilder sb,
301 int[] columnWidths ) {
302
303 sb.append("| ").append(StringUtil.justifyLeft("#", columnWidths[0], ' ')).append(' ');
304
305 sb.append('|');
306 int i = 1;
307 for (String name : columns.getTupleValueNames()) {
308 sb.append(' ');
309 sb.append(StringUtil.justifyLeft(name, columnWidths[i], ' '));
310 sb.append(" |");
311 ++i;
312 }
313 sb.append('\n');
314 }
315
316 protected void printLines( TypeSystem typeSystem,
317 StringBuilder sb,
318 int[] columnWidths,
319 int maxRowsToPrint ) {
320 int rowNumber = 1;
321 int tupleLength = columns.getTupleSize();
322
323 if (maxRowsToPrint > tuples.size()) {
324
325 for (Object[] tuple : getTuples()) {
326 printTuple(typeSystem, sb, columnWidths, rowNumber, tupleLength, tuple);
327 ++rowNumber;
328 }
329 } else {
330
331 for (Object[] tuple : getTuples()) {
332 printTuple(typeSystem, sb, columnWidths, rowNumber, tupleLength, tuple);
333 if (rowNumber >= maxRowsToPrint) break;
334 ++rowNumber;
335 }
336 }
337
338 }
339
340 private final void printTuple( TypeSystem typeSystem,
341 StringBuilder sb,
342 int[] columnWidths,
343 int rowNumber,
344 int tupleLength,
345 Object[] tuple ) {
346
347 sb.append("| ").append(StringUtil.justifyLeft(Integer.toString(rowNumber), columnWidths[0], ' ')).append(' ');
348
349 for (int i = 0, j = 1; i != tupleLength; ++i, ++j) {
350 String valueStr = stringOf(typeSystem, tuple[i]);
351 valueStr = StringUtil.justifyLeft(valueStr, columnWidths[j], ' ');
352 sb.append('|').append(' ').append(valueStr).append(' ');
353 }
354 sb.append('|');
355 sb.append('\n');
356 }
357
358 protected void printDelimiterLine( StringBuilder sb,
359 int[] columnWidths,
360 boolean includeLineFeed ) {
361 sb.append('+');
362 for (int i = 0, max = columnWidths.length; i != max; ++i) {
363 for (int j = 0, width = columnWidths[i] + 2; j != width; ++j) {
364 sb.append('-');
365 }
366 sb.append('+');
367 }
368 if (includeLineFeed) sb.append('\n');
369 }
370
371
372
373
374 public final class TupleCursor implements Cursor {
375 private final Columns columns;
376 private final Iterator<Object[]> iterator;
377 private Object[] currentTuple;
378 private int tupleIndex;
379
380 protected TupleCursor( Columns columns,
381 Iterator<Object[]> iterator ) {
382 this.iterator = iterator;
383 this.columns = columns;
384 this.tupleIndex = -1;
385 }
386
387
388
389
390
391
392 public boolean hasNext() {
393 return iterator.hasNext();
394 }
395
396
397
398
399
400
401 public void next() {
402 currentTuple = iterator.next();
403 ++tupleIndex;
404 }
405
406
407
408
409
410
411 public Location getLocation( int columnNumber ) {
412 return (Location)currentTuple[columns.getLocationIndexForColumn(columnNumber)];
413 }
414
415
416
417
418
419
420 public Location getLocation( String selectorName ) {
421 return (Location)currentTuple[columns.getLocationIndex(selectorName)];
422 }
423
424
425
426
427
428
429 public int getRowIndex() {
430 return tupleIndex;
431 }
432
433
434
435
436
437
438 public Object getValue( int columnNumber ) {
439 if (columnNumber >= columns.getColumnCount()) {
440 throw new IndexOutOfBoundsException();
441 }
442 if (currentTuple == null) {
443 throw new IllegalStateException(GraphI18n.nextMethodMustBeCalledBeforeGettingValue.text());
444 }
445 return currentTuple[columnNumber];
446 }
447
448
449
450
451
452
453 public Object getValue( String columnName ) {
454 if (currentTuple == null) {
455 throw new IllegalStateException(GraphI18n.nextMethodMustBeCalledBeforeGettingValue.text());
456 }
457 return currentTuple[columns.getColumnIndexForName(columnName)];
458 }
459 }
460 }