Merge pull request #1785 from idugic/master

#1245
This commit is contained in:
Lukas Eder 2012-09-01 12:16:43 -07:00
commit d1c81e84b5
6 changed files with 342 additions and 19 deletions

View File

@ -0,0 +1,17 @@
#example properties file
jdbc.Driver=org.h2.Driver
jdbc.URL=jdbc:h2:~/test
jdbc.Schema=INFORMATION_SCHEMA
jdbc.User=sa
jdbc.Password=
generator=org.jooq.util.DefaultGenerator
generator.database=org.jooq.util.h2.H2Database
generator.database.includes=SCHEMATA,TABLES,COLUMNS,CONSTRAINTS,CROSS_REFERENCES,TYPE_INFO,FUNCTION_ALIASES,FUNCTION_COLUMNS,SEQUENCES
generator.database.excludes=
generator.generate.deprecated=false
generator.generate.instance-fields=false
generator.generate.records=false
generator.target.package=org.jooq.util.h2.information_schema
generator.target.directory=./src/main/java

View File

@ -0,0 +1,48 @@
#example properties file
jdbc.Driver=org.h2.Driver
#jdbc.URL=jdbc:h2:tcp://localhost/~/test
jdbc.URL=jdbc:h2:~/test
jdbc.Schema=PUBLIC
jdbc.User=sa
jdbc.Password=
generator=org.jooq.util.DefaultGenerator
generator.database=org.jooq.util.h2.H2Database
generator.database.includes=.*
generator.database.excludes=T_BOOK_DETAILS,SYSTEM_SEQUENCE.*
#Database enum type mappings
generator.database.enum-type.BOOLEAN_10=1,0
generator.database.enum-type.BOOLEAN_YN_UC="Y",N
generator.database.enum-type.BOOLEAN_YN_LC=y,"n"
generator.database.enum-type.BOOLEAN_YES_NO_UC="YES","NO"
generator.database.enum-type.BOOLEAN_YES_NO_LC=yes,no
generator.database.enum-type.BOOLEAN_TRUE_FALSE_UC=TRUE,FALSE
generator.database.enum-type.BOOLEAN_TRUE_FALSE_LC=true,false
generator.database.forced-type.BOOLEAN_10=(?i:(.*?\.)?T_BOOLEANS\.ONE_ZERO)
generator.database.forced-type.BOOLEAN_YN_UC=(?i:(.*?\.)?T_BOOLEANS\.Y_N_UC)
generator.database.forced-type.BOOLEAN_YN_LC=(?i:(.*?\.)?T_BOOLEANS\.Y_N_LC)
generator.database.forced-type.BOOLEAN_YES_NO_UC=(?i:(.*?\.)?T_BOOLEANS\.YES_NO_UC)
generator.database.forced-type.BOOLEAN_YES_NO_LC=(?i:(.*?\.)?T_BOOLEANS\.YES_NO_LC)
generator.database.forced-type.BOOLEAN_TRUE_FALSE_UC=(?i:(.*?\.)?T_BOOLEANS\.TRUE_FALSE_UC)
generator.database.forced-type.BOOLEAN_TRUE_FALSE_LC=(?i:(.*?\.)?T_BOOLEANS\.TRUE_FALSE_LC)
#[#677] Forced types
generator.database.forced-type.BOOLEAN=(?i:(.*?\.)?T_BOOLEANS\.(VC|C|N)_BOOLEAN)
#Generator configuration
generator.generate.relations=true
generator.generate.instance-fields=false
generator.generate.generated-annotation=false
#Generate a master data table enum from T_LANGUAGE
generator.generate.master-data-tables=T_LANGUAGE,T_658_11,T_658_21,T_658_31,T_658_12,T_658_22,T_658_32
generator.generate.master-data-table-literal.T_LANGUAGE=CD
generator.generate.master-data-table-description.T_LANGUAGE=DESCRIPTION
generator.generate.master-data-table-literal.T_658_12=CD
generator.generate.master-data-table-literal.T_658_22=CD
generator.generate.master-data-table-literal.T_658_32=CD
generator.target.package=org.jooq.test.h2.generatedclasses
generator.target.directory=./src

View File

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-2.1.0.xsd">
<jdbc>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:~/test</url>
<user>sa</user>
<password></password>
</jdbc>
<generator>
<name>org.jooq.util.DefaultGenerator</name>
<database>
<name>org.jooq.util.h2.H2Database</name>
<includes>.*</includes>
<excludes>T_BOOK_DETAILS,SYSTEM_SEQUENCE.*</excludes>
<recordVersionFields>REC_VERSION</recordVersionFields>
<recordTimestampFields>REC_TIMESTAMP</recordTimestampFields>
<dateAsTimestamp>false</dateAsTimestamp>
<unsignedTypes>true</unsignedTypes>
<inputSchema>PUBLIC</inputSchema>
<masterDataTables>
<masterDataTable>
<name>T_LANGUAGE</name>
<literal>CD</literal>
<description>DESCRIPTION</description>
</masterDataTable>
<masterDataTable>
<name>T_658_11</name>
</masterDataTable>
<masterDataTable>
<name>T_658_21</name>
</masterDataTable>
<masterDataTable>
<name>T_658_31</name>
</masterDataTable>
<masterDataTable>
<name>T_658_12</name>
<literal>CD</literal>
</masterDataTable>
<masterDataTable>
<name>T_658_22</name>
<literal>CD</literal>
</masterDataTable>
<masterDataTable>
<name>T_658_32</name>
<literal>CD</literal>
</masterDataTable>
</masterDataTables>
<customTypes>
<customType>
<name>org.jooq.test._.converters.Boolean_10</name>
<converter>org.jooq.test._.converters.Boolean_10_Converter</converter>
</customType>
<customType>
<name>org.jooq.test._.converters.Boolean_TF_LC</name>
<converter>org.jooq.test._.converters.Boolean_TF_LC_Converter</converter>
</customType>
<customType>
<name>org.jooq.test._.converters.Boolean_TF_UC</name>
<converter>org.jooq.test._.converters.Boolean_TF_UC_Converter</converter>
</customType>
<customType>
<name>org.jooq.test._.converters.Boolean_YN_LC</name>
<converter>org.jooq.test._.converters.Boolean_YN_LC_Converter</converter>
</customType>
<customType>
<name>org.jooq.test._.converters.Boolean_YN_UC</name>
<converter>org.jooq.test._.converters.Boolean_YN_UC_Converter</converter>
</customType>
<customType>
<name>org.jooq.test._.converters.Boolean_YES_NO_LC</name>
<converter>org.jooq.test._.converters.Boolean_YES_NO_LC_Converter</converter>
</customType>
<customType>
<name>org.jooq.test._.converters.Boolean_YES_NO_UC</name>
<converter>org.jooq.test._.converters.Boolean_YES_NO_UC_Converter</converter>
</customType>
</customTypes>
<forcedTypes>
<forcedType>
<name>BOOLEAN</name>
<expressions>(?i:(.*?.)?T_BOOLEANS.(VC|C|N)_BOOLEAN)</expressions>
</forcedType>
<forcedType>
<name>org.jooq.test._.converters.Boolean_YES_NO_LC</name>
<expressions>(?i:(.*?.)?T_BOOLEANS.YES_NO_LC)</expressions>
</forcedType>
<forcedType>
<name>org.jooq.test._.converters.Boolean_YES_NO_UC</name>
<expressions>(?i:(.*?.)?T_BOOLEANS.YES_NO_UC)</expressions>
</forcedType>
<forcedType>
<name>org.jooq.test._.converters.Boolean_YN_LC</name>
<expressions>(?i:(.*?.)?T_BOOLEANS.Y_N_LC)</expressions>
</forcedType>
<forcedType>
<name>org.jooq.test._.converters.Boolean_YN_UC</name>
<expressions>(?i:(.*?.)?T_BOOLEANS.Y_N_UC)</expressions>
</forcedType>
<forcedType>
<name>org.jooq.test._.converters.Boolean_TF_LC</name>
<expressions>(?i:(.*?.)?T_BOOLEANS.TRUE_FALSE_LC)</expressions>
</forcedType>
<forcedType>
<name>org.jooq.test._.converters.Boolean_TF_UC</name>
<expressions>(?i:(.*?.)?T_BOOLEANS.TRUE_FALSE_UC)</expressions>
</forcedType>
<forcedType>
<name>org.jooq.test._.converters.Boolean_10</name>
<expressions>(?i:(.*?.)?T_BOOLEANS.ONE_ZERO)</expressions>
</forcedType>
</forcedTypes>
</database>
<generate>
<relations>true</relations>
<navigationMethods>true</navigationMethods>
<deprecated>true</deprecated>
<instanceFields>false</instanceFields>
<generatedAnnotation>false</generatedAnnotation>
<records>false</records>
<pojos>false</pojos>
<interfaces>true</interfaces>
<daos>true</daos>
<jpaAnnotations>false</jpaAnnotations>
</generate>
<target>
<packageName>org.jooq.test.h2.generatedclasses</packageName>
<directory>./src</directory>
</target>
</generator>
</configuration>

View File

@ -41,7 +41,10 @@ import static junit.framework.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@ -86,6 +89,45 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658,
super(delegate);
}
@Test
public void testFormat() throws Exception {
jOOQAbstractTest.reset = false;
// Insert test numbers
create().insertInto(T639(), T639_ID(), T639_BIG_DECIMAL())
.values(1, null)
.values(2, new BigDecimal("0"))
.values(3, new BigDecimal("1"))
.values(4, new BigDecimal("1.2"))
.values(5, new BigDecimal("1.23"))
.values(6, new BigDecimal("1.23456789"))
.values(7, new BigDecimal("12.3"))
.values(8, new BigDecimal("123.4"))
.values(9, new BigDecimal("1234.5"))
.values(10, new BigDecimal("12345678.9"))
.values(11, new BigDecimal("0.1"))
.values(12, new BigDecimal("0.12"))
.values(13, new BigDecimal("0.123456789"))
.execute();
String format = create().select(T639_ID(), T639_BIG_DECIMAL()).from(T639()).fetch().format();
// Collect decimal point indexes
Set<Integer> decimalPointIndexSet = new HashSet<Integer>();
for (String formatLine : format.split("\n")) {
// Include only data lines
if (formatLine.startsWith("|")) {
decimalPointIndexSet.add(formatLine.indexOf("."));
}
}
// Remove -1 position
decimalPointIndexSet.remove(-1);
// Check if all decimal points have the same position
assertEquals(1, decimalPointIndexSet.size());
}
@Test
public void testFormatHTML() throws Exception {
List<Field<?>> fields = TBook().getFields();

View File

@ -1222,6 +1222,11 @@ public abstract class jOOQAbstractTest<
new CRUDTests(this).testNonUpdatables();
}
@Test
public void testFormat() throws Exception {
new FormatTests(this).testFormat();
}
@Test
public void testFormatHTML() throws Exception {
new FormatTests(this).testFormatHTML();

View File

@ -88,6 +88,7 @@ import org.w3c.dom.Element;
/**
* @author Lukas Eder
* @author Ivan Dugic
*/
class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
@ -937,33 +938,73 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
@Override
public final String format(int maxRecords) {
final int MAX_WIDTH = 50;
final int COL_MIN_WIDTH = 4;
final int COL_MAX_WIDTH = 50;
// Numeric columns have greater max width because values are aligned
final int NUM_COL_MAX_WIDTH = 100;
final int MAX_RECORDS = 50;
StringBuilder sb = new StringBuilder();
Map<Field<?>, Integer> widths = new HashMap<Field<?>, Integer>();
// Initialise widths
// Get max decimal places for numeric type columns
Map<Field<?>, Integer> decimalPlacesMap = new HashMap<Field<?>, Integer>();
for (Field<?> f : getFields()) {
widths.put(f, 4);
if (Number.class.isAssignableFrom(f.getType())) {
List<Integer> decimalPlacesList = new ArrayList<Integer>();
// Initialize
decimalPlacesList.add(0);
// Collect all decimal places for the column values
String value;
for (int i = 0; i < min(MAX_RECORDS, size()); i++) {
value = format0(getValue(i, f));
decimalPlacesList.add(getDecimalPlaces(value));
}
// Find max
decimalPlacesMap.put(f, Collections.max(decimalPlacesList));
}
}
// Find width for every field to satisfy formatting the first 50 records
// Get max column widths
Map<Field<?>, Integer> widthMap = new HashMap<Field<?>, Integer>();
int colMaxWidth;
for (Field<?> f : getFields()) {
widths.put(f, min(MAX_WIDTH, max(widths.get(f), f.getName().length())));
// Is number column?
boolean isNumCol = Number.class.isAssignableFrom(f.getType());
colMaxWidth = isNumCol ? NUM_COL_MAX_WIDTH : COL_MAX_WIDTH;
// Collect all widths for the column
List<Integer> widthList = new ArrayList<Integer>();
// Add column name width first
widthList.add(min(colMaxWidth, max(COL_MIN_WIDTH, f.getName().length())));
// Add column values width
String value;
for (int i = 0; i < min(MAX_RECORDS, size()); i++) {
widths.put(f, min(MAX_WIDTH, max(widths.get(f), format0(getValue(i, f)).length())));
value = format0(getValue(i, f));
// Align number values before width is calculated
if (isNumCol) {
value = alignNumberValue(decimalPlacesMap.get(f), value);
}
widthList.add(min(colMaxWidth, value.length()));
}
// Find max
widthMap.put(f, Collections.max(widthList));
}
// Begin the writing
// ---------------------------------------------------------------------
StringBuilder sb = new StringBuilder();
// Write top line
sb.append("+");
for (Field<?> f : getFields()) {
sb.append(rightPad("", widths.get(f), "-"));
sb.append(rightPad("", widthMap.get(f), "-"));
sb.append("+");
}
@ -973,20 +1014,20 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
String padded;
if (Number.class.isAssignableFrom(f.getType())) {
padded = leftPad(f.getName(), widths.get(f));
padded = leftPad(f.getName(), widthMap.get(f));
}
else {
padded = rightPad(f.getName(), widths.get(f));
padded = rightPad(f.getName(), widthMap.get(f));
}
sb.append(abbreviate(padded, widths.get(f)));
sb.append(abbreviate(padded, widthMap.get(f)));
sb.append("|");
}
// Write separator
sb.append("\n+");
for (Field<?> f : getFields()) {
sb.append(rightPad("", widths.get(f), "-"));
sb.append(rightPad("", widthMap.get(f), "-"));
sb.append("+");
}
@ -995,16 +1036,21 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
sb.append("\n|");
for (Field<?> f : getFields()) {
String value = format0(getValue(i, f)).replace("\n", "{lf}").replace("\r", "{cr}");
String padded;
String padded;
if (Number.class.isAssignableFrom(f.getType())) {
padded = leftPad(value, widths.get(f));
// Align number value before left pad
value = alignNumberValue(decimalPlacesMap.get(f), value);
// Left pad
padded = leftPad(value, widthMap.get(f));
}
else {
padded = rightPad(value, widths.get(f));
// Right pad
padded = rightPad(value, widthMap.get(f));
}
sb.append(abbreviate(padded, widths.get(f)));
sb.append(abbreviate(padded, widthMap.get(f)));
sb.append("|");
}
}
@ -1013,7 +1059,7 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
if (size() > 0) {
sb.append("\n+");
for (Field<?> f : getFields()) {
sb.append(rightPad("", widths.get(f), "-"));
sb.append(rightPad("", widthMap.get(f), "-"));
sb.append("+");
}
}
@ -1028,6 +1074,34 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
return sb.toString();
}
private String alignNumberValue(Integer columnDecimalPlaces, String value) {
if (!"{null}".equals(value) && columnDecimalPlaces != 0) {
int decimalPlaces = getDecimalPlaces(value);
int rightPadSize = value.length() + columnDecimalPlaces - decimalPlaces;
if (decimalPlaces == 0) {
// If integer value, add one for decimal point
value = rightPad(value, rightPadSize + 1);
}
else {
value = rightPad(value, rightPadSize);
}
}
return value;
}
private Integer getDecimalPlaces(String value) {
int decimalPlaces = 0;
int dotIndex = value.indexOf(".");
if (dotIndex != -1) {
decimalPlaces = value.length() - dotIndex - 1;
}
return decimalPlaces;
}
@Override
public final String formatHTML() {
StringBuilder sb = new StringBuilder();
@ -1140,6 +1214,10 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
else if (value instanceof EnumType) {
formatted = ((EnumType) value).getLiteral();
}
else if (value instanceof Number) {
// Remove insignificant zeros
formatted = value.toString().replaceAll("(?:(\\..*[^0])0+|\\.0+)$", "$1");
}
else {
formatted = value.toString();
}