11package org .neo4j .shell .prettyprint ;
22
3+ import java .util .ArrayList ;
4+ import java .util .Collections ;
5+ import java .util .EnumSet ;
6+ import java .util .Iterator ;
7+ import java .util .List ;
8+ import java .util .Map ;
9+ import java .util .Set ;
10+ import javax .annotation .Nonnull ;
11+ import javax .annotation .Nullable ;
12+
313import org .neo4j .driver .internal .InternalRecord ;
14+ import org .neo4j .driver .internal .value .NumberValueAdapter ;
415import org .neo4j .driver .v1 .Record ;
516import org .neo4j .driver .v1 .Value ;
617import org .neo4j .driver .v1 .summary .ResultSummary ;
718import org .neo4j .shell .state .BoltResult ;
819
9- import javax .annotation .Nonnull ;
10- import javax .annotation .Nullable ;
11- import java .util .*;
12-
1320import static java .util .Arrays .asList ;
1421import static java .util .concurrent .TimeUnit .MILLISECONDS ;
1522
@@ -47,15 +54,15 @@ private int formatResultAndCountRows(String[] columns,
4754 LinePrinter output ) {
4855
4956 List <Record > topRecords = take (records , numSampleRows );
50- int [] columnSizes = calculateColumnSizes (columns , topRecords );
57+ int [] columnSizes = calculateColumnSizes (columns , topRecords , records . hasNext () );
5158
5259 int totalWidth = 1 ;
5360 for (int columnSize : columnSizes ) {
5461 totalWidth += columnSize + 3 ;
5562 }
5663
5764 StringBuilder builder = new StringBuilder (totalWidth );
58- String headerLine = formatRow (builder , columnSizes , columns );
65+ String headerLine = formatRow (builder , columnSizes , columns , new boolean [ columnSizes . length ] );
5966 int lineWidth = totalWidth - 2 ;
6067 String dashes = "+" + OutputFormatter .repeat ('-' , lineWidth ) + "+" ;
6168
@@ -76,14 +83,21 @@ private int formatResultAndCountRows(String[] columns,
7683 return numberOfRows ;
7784 }
7885
79- private int [] calculateColumnSizes (@ Nonnull String [] columns , @ Nonnull List <Record > data ) {
86+ /**
87+ * Calculate the size of the columns for table formatting
88+ * @param columns the column names
89+ * @param data (sample) data
90+ * @param moreDataAfterSamples if there is more data that should be written into the table after `data`
91+ * @return the column sizes
92+ */
93+ private int [] calculateColumnSizes (@ Nonnull String [] columns , @ Nonnull List <Record > data , boolean moreDataAfterSamples ) {
8094 int [] columnSizes = new int [columns .length ];
8195 for (int i = 0 ; i < columns .length ; i ++) {
8296 columnSizes [i ] = columns [i ].length ();
8397 }
8498 for (Record record : data ) {
8599 for (int i = 0 ; i < columns .length ; i ++) {
86- int len = formatValue (record .get (i )). length ( );
100+ int len = columnLengthForValue (record .get (i ), moreDataAfterSamples );
87101 if (columnSizes [i ] < len ) {
88102 columnSizes [i ] = len ;
89103 }
@@ -92,9 +106,24 @@ private int[] calculateColumnSizes(@Nonnull String[] columns, @Nonnull List<Reco
92106 return columnSizes ;
93107 }
94108
109+ /**
110+ * The length of a column, where Numbers are always getting enough space to fit the highest number possible.
111+ *
112+ * @param value the value to calculate the length for
113+ * @param moreDataAfterSamples if there is more data that should be written into the table after `data`
114+ * @return the column size for this value.
115+ */
116+ private int columnLengthForValue (Value value , boolean moreDataAfterSamples ) {
117+ if (value instanceof NumberValueAdapter && moreDataAfterSamples ) {
118+ return 19 ; // The number of digits of Long.Max
119+ } else {
120+ return formatValue (value ).length ();
121+ }
122+ }
123+
95124 private String formatRecord (StringBuilder sb , int [] columnSizes , Record record ) {
96125 sb .setLength (0 );
97- return formatRow (sb , columnSizes , formatValues (record ));
126+ return formatRow (sb , columnSizes , formatValues (record ), new boolean [ columnSizes . length ] );
98127 }
99128
100129 private String [] formatValues (Record record ) {
@@ -105,8 +134,21 @@ private String[] formatValues(Record record) {
105134 return row ;
106135 }
107136
108- private String formatRow (StringBuilder sb , int [] columnSizes , String [] row ) {
109- sb .append ("|" );
137+ /**
138+ * Format one row of data.
139+ *
140+ * @param sb the StringBuilder to use
141+ * @param columnSizes the size of all columns
142+ * @param row the data
143+ * @param continuation for each column whether it holds the remainder of data that did not fit in the column
144+ * @return the String result
145+ */
146+ private String formatRow (StringBuilder sb , int [] columnSizes , String [] row , boolean [] continuation ) {
147+ if (!continuation [0 ]) {
148+ sb .append ("|" );
149+ } else {
150+ sb .append ("\\ " );
151+ }
110152 boolean remainder = false ;
111153 for (int i = 0 ; i < row .length ; i ++) {
112154 sb .append (" " );
@@ -117,6 +159,7 @@ private String formatRow(StringBuilder sb, int[] columnSizes, String[] row) {
117159 if (wrap ) {
118160 sb .append (txt , 0 , length );
119161 row [i ] = txt .substring (length );
162+ continuation [i ] = true ;
120163 remainder = true ;
121164 } else {
122165 sb .append (txt , 0 , length - 1 );
@@ -129,11 +172,15 @@ private String formatRow(StringBuilder sb, int[] columnSizes, String[] row) {
129172 } else {
130173 sb .append (OutputFormatter .repeat (' ' , length ));
131174 }
132- sb .append (" |" );
175+ if (i == row .length -1 || !continuation [i +1 ]) {
176+ sb .append (" |" );
177+ } else {
178+ sb .append (" \\ " );
179+ }
133180 }
134181 if (wrap && remainder ) {
135182 sb .append (OutputFormatter .NEWLINE );
136- formatRow (sb , columnSizes , row );
183+ formatRow (sb , columnSizes , row , continuation );
137184 }
138185 return sb .toString ();
139186 }
0 commit comments