1.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/Configuration.java Sun Aug 30 02:24:36 2015 +0200
1.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/configuration/Configuration.java Sun Aug 30 02:28:15 2015 +0200
1.3 @@ -19,7 +19,7 @@
1.4
1.5 import static info.globalcode.sql.dk.Xmlns.CONFIGURATION;
1.6 import static info.globalcode.sql.dk.Functions.findByName;
1.7 -import info.globalcode.sql.dk.formatting.DsvFormatter;
1.8 +import info.globalcode.sql.dk.formatting.BarChartFormatter;
1.9 import info.globalcode.sql.dk.formatting.SilentFormatter;
1.10 import info.globalcode.sql.dk.formatting.SingleRecordFormatter;
1.11 import info.globalcode.sql.dk.formatting.SingleValueFormatter;
1.12 @@ -73,7 +73,9 @@
1.13 l.add(new FormatterDefinition(TabularPrefetchingFormatter.NAME, TabularPrefetchingFormatter.class.getName()));
1.14 l.add(new FormatterDefinition(TabularWrappingFormatter.NAME, TabularWrappingFormatter.class.getName()));
1.15 l.add(new FormatterDefinition(TeXFormatter.NAME, TeXFormatter.class.getName()));
1.16 - l.add(new FormatterDefinition(DsvFormatter.NAME, DsvFormatter.class.getName()));
1.17 + //l.add(new FormatterDefinition(DsvFormatter.NAME, DsvFormatter.class.getName()));
1.18 + //l.add(new FormatterDefinition(SystemCommandExecutor.NAME, SystemCommandExecutor.class.getName()));
1.19 + l.add(new FormatterDefinition(BarChartFormatter.NAME, BarChartFormatter.class.getName()));
1.20 buildInFormatters = Collections.unmodifiableCollection(l);
1.21 }
1.22
1.23 @@ -88,7 +90,7 @@
1.24
1.25 /**
1.26 * @param name
1.27 - * @return
1.28 + * @return
1.29 * @throws ConfigurationException if no database with this name is configured
1.30 */
1.31 public DatabaseDefinition getDatabase(String name) throws ConfigurationException {
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/BarChartFormatter.java Sun Aug 30 02:28:15 2015 +0200
2.3 @@ -0,0 +1,96 @@
2.4 +/**
2.5 + * SQL-DK
2.6 + * Copyright © 2015 František Kučera (frantovo.cz)
2.7 + *
2.8 + * This program is free software: you can redistribute it and/or modify
2.9 + * it under the terms of the GNU General Public License as published by
2.10 + * the Free Software Foundation, either version 3 of the License, or
2.11 + * (at your option) any later version.
2.12 + *
2.13 + * This program is distributed in the hope that it will be useful,
2.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2.16 + * GNU General Public License for more details.
2.17 + *
2.18 + * You should have received a copy of the GNU General Public License
2.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
2.20 + */
2.21 +package info.globalcode.sql.dk.formatting;
2.22 +
2.23 +import info.globalcode.sql.dk.Functions;
2.24 +import info.globalcode.sql.dk.configuration.PropertyDeclaration;
2.25 +import info.globalcode.sql.dk.logging.LoggerProducer;
2.26 +import java.math.BigDecimal;
2.27 +import java.math.MathContext;
2.28 +import java.math.RoundingMode;
2.29 +import java.util.List;
2.30 +import java.util.logging.Level;
2.31 +import java.util.logging.Logger;
2.32 +
2.33 +/**
2.34 + *
2.35 + * @author Ing. František Kučera (frantovo.cz)
2.36 + */
2.37 +@PropertyDeclaration(name = BarChartFormatter.PROPERTY_PRECISION, type = Integer.class, defaultValue = BarChartFormatter.PROPERTY_PRECISION_DEFAULT, description = "number of characters representing 100 % in the bar chart")
2.38 +public class BarChartFormatter extends TabularPrefetchingFormatter {
2.39 +
2.40 + public static final String NAME = "barchart"; // bash-completion:formatter
2.41 + public static final String PROPERTY_PRECISION = "precision";
2.42 + protected static final String PROPERTY_PRECISION_DEFAULT = "100";
2.43 + private static final MathContext mathContext = MathContext.DECIMAL128;
2.44 + public static final Logger log = LoggerProducer.getLogger();
2.45 + private final BigDecimal chartPrecision;
2.46 + private final char chartFull;
2.47 + private final char chartEmpty;
2.48 +
2.49 + public BarChartFormatter(FormatterContext formatterContext) {
2.50 + super(formatterContext);
2.51 + chartPrecision = BigDecimal.valueOf(formatterContext.getProperties().getInteger(PROPERTY_PRECISION, Integer.parseInt(PROPERTY_PRECISION_DEFAULT)));
2.52 + chartFull = isAsciiNostalgia() ? '#' : '█';
2.53 + chartEmpty = isAsciiNostalgia() ? '~' : '░';
2.54 + // TODO: consider using partial blocks for more precision: https://en.wikipedia.org/wiki/Block_Elements
2.55 + }
2.56 +
2.57 + @Override
2.58 + protected void postprocessPrefetchedResultSet(ColumnsHeader currentHeader, List<Object[]> currentResultSet) {
2.59 + super.postprocessPrefetchedResultSet(currentHeader, currentResultSet);
2.60 +
2.61 + updateColumnWidth(currentHeader.getColumnCount(), chartPrecision.intValue());
2.62 +
2.63 + BigDecimal maximum = BigDecimal.ZERO;
2.64 + BigDecimal minimum = BigDecimal.ZERO;
2.65 + int lastIndex = currentHeader.getColumnCount() - 1;
2.66 +
2.67 + try {
2.68 + for (Object[] row : currentResultSet) {
2.69 + Object valueObject = row[lastIndex];
2.70 + if (valueObject != null) {
2.71 + BigDecimal value = new BigDecimal(valueObject.toString());
2.72 + maximum = maximum.max(value);
2.73 + minimum = minimum.min(value);
2.74 + }
2.75 + }
2.76 +
2.77 + BigDecimal range = maximum.subtract(minimum);
2.78 +
2.79 + for (Object[] row : currentResultSet) {
2.80 + Object valueObject = row[lastIndex];
2.81 + if (valueObject != null) {
2.82 + BigDecimal value = new BigDecimal(valueObject.toString());
2.83 + BigDecimal valueFromMinimum = value.subtract(minimum);
2.84 +
2.85 + BigDecimal points = chartPrecision.divide(range, mathContext).multiply(valueFromMinimum, mathContext);
2.86 + int pointsRounded = points.setScale(0, RoundingMode.HALF_UP).intValue();
2.87 + row[lastIndex] = Functions.repeat(chartFull, pointsRounded) + Functions.repeat(chartEmpty, chartPrecision.intValue() - pointsRounded);
2.88 + }
2.89 + }
2.90 +
2.91 + } catch (NumberFormatException e) {
2.92 + // https://en.wiktionary.org/wiki/parsable
2.93 + log.log(Level.SEVERE, "Last column must be number or an object with toString() value parsable to a number.");
2.94 + // FIXME: throw FormatterException
2.95 + throw e;
2.96 + }
2.97 + }
2.98 +
2.99 +}
3.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularFormatter.java Sun Aug 30 02:24:36 2015 +0200
3.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularFormatter.java Sun Aug 30 02:28:15 2015 +0200
3.3 @@ -277,4 +277,11 @@
3.4 protected void printTableIndent() {
3.5 out.print(" ");
3.6 }
3.7 +
3.8 + /**
3.9 + * @return whether should print only ASCII characters instead of unlimited Unicode.
3.10 + */
3.11 + protected boolean isAsciiNostalgia() {
3.12 + return asciiNostalgia;
3.13 + }
3.14 }
4.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularPrefetchingFormatter.java Sun Aug 30 02:24:36 2015 +0200
4.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularPrefetchingFormatter.java Sun Aug 30 02:28:15 2015 +0200
4.3 @@ -86,6 +86,8 @@
4.4 public void writeEndResultSet() {
4.5 prefetchDone = true;
4.6
4.7 + postprocessPrefetchedResultSet(currentHeader, currentResultSet);
4.8 +
4.9 super.writeStartResultSet(currentHeader);
4.10
4.11 for (Object[] row : currentResultSet) {
4.12 @@ -103,4 +105,15 @@
4.13 super.writeEndResultSet();
4.14 prefetchDone = false;
4.15 }
4.16 +
4.17 + /**
4.18 + * Optional post-processing – override in sub-classes if needed.
4.19 + * Don't forget to {@linkplain #updateColumnWidth(int, int)}
4.20 + *
4.21 + * @param currentHeader
4.22 + * @param currentResultSet
4.23 + */
4.24 + protected void postprocessPrefetchedResultSet(ColumnsHeader currentHeader, List<Object[]> currentResultSet) {
4.25 + }
4.26 +
4.27 }