git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@1291 f203690c-595d-4dc9-a70b-905162fa7fd2tags/jackcess-3.0.1
@@ -4,6 +4,12 @@ | |||
<author email="javajedi@users.sf.net">Tim McCune</author> | |||
</properties> | |||
<body> | |||
<release version="3.0.1" date="TBD"> | |||
<action dev="jahlborn" type="update"> | |||
Add ColumnFormatter utility which can apply Column "Format" property | |||
for display of column values. | |||
</action> | |||
</release> | |||
<release version="3.0.0" date="2019-02-08" description="Update to Java 8"> | |||
<action dev="jahlborn" type="update"> | |||
Jackcess now requires a Java 8+ runtime. As part of this update, all |
@@ -215,7 +215,7 @@ limitations under the License. | |||
* | |||
* <table border="1" width="25%" cellpadding="3" cellspacing="0"> | |||
* <tr class="TableHeadingColor" align="left"><th>Function</th><th>Supported</th></tr> | |||
* <tr class="TableRowColor"><td>Format[$]</td><td>Partial</td></tr> | |||
* <tr class="TableRowColor"><td>Format[$]</td><td>Y</td></tr> | |||
* <tr class="TableRowColor"><td>InStr</td><td>Y</td></tr> | |||
* <tr class="TableRowColor"><td>InStrRev</td><td>Y</td></tr> | |||
* <tr class="TableRowColor"><td>LCase[$]</td><td>Y</td></tr> |
@@ -16,6 +16,8 @@ limitations under the License. | |||
package com.healthmarketscience.jackcess.impl; | |||
import com.healthmarketscience.jackcess.expr.Value; | |||
@@ -40,4 +42,8 @@ public abstract class ColEvalContext extends BaseEvalContext | |||
protected String withErrorContext(String msg) { | |||
return _col.withErrorContext(msg); | |||
} | |||
protected Value toValue(Object val) { | |||
return toValue(val, _col.getType()); | |||
} | |||
} |
@@ -65,7 +65,7 @@ public class ColValidatorEvalContext extends ColEvalContext | |||
@Override | |||
public Value getThisColumnValue() { | |||
return toValue(_val, getCol().getType()); | |||
return toValue(_val); | |||
} | |||
@Override |
@@ -29,6 +29,7 @@ import com.healthmarketscience.jackcess.expr.EvalContext; | |||
import com.healthmarketscience.jackcess.expr.EvalException; | |||
import com.healthmarketscience.jackcess.expr.Function; | |||
import com.healthmarketscience.jackcess.expr.FunctionLookup; | |||
import com.healthmarketscience.jackcess.expr.LocaleContext; | |||
import com.healthmarketscience.jackcess.expr.NumericConfig; | |||
import com.healthmarketscience.jackcess.expr.TemporalConfig; | |||
import com.healthmarketscience.jackcess.expr.Value; | |||
@@ -473,11 +474,11 @@ public class DefaultFunctions | |||
} | |||
}); | |||
private static boolean stringIsNumeric(EvalContext ctx, Value param) { | |||
private static boolean stringIsNumeric(LocaleContext ctx, Value param) { | |||
return (maybeGetAsBigDecimal(ctx, param) != null); | |||
} | |||
static BigDecimal maybeGetAsBigDecimal(EvalContext ctx, Value param) { | |||
static BigDecimal maybeGetAsBigDecimal(LocaleContext ctx, Value param) { | |||
try { | |||
return param.getAsBigDecimal(ctx); | |||
} catch(EvalException ignored) { | |||
@@ -490,7 +491,7 @@ public class DefaultFunctions | |||
return (maybeGetAsDateTimeValue(ctx, param) != null); | |||
} | |||
static Value maybeGetAsDateTimeValue(EvalContext ctx, Value param) { | |||
static Value maybeGetAsDateTimeValue(LocaleContext ctx, Value param) { | |||
try { | |||
// see if we can coerce to date/time | |||
return param.getAsDateTimeValue(ctx); |
@@ -38,6 +38,7 @@ import com.healthmarketscience.jackcess.expr.ParseException; | |||
import com.healthmarketscience.jackcess.expr.TemporalConfig; | |||
import com.healthmarketscience.jackcess.expr.Value; | |||
import com.healthmarketscience.jackcess.impl.ColumnImpl; | |||
import org.apache.commons.lang3.StringUtils; | |||
/** | |||
@@ -89,7 +90,7 @@ class ExpressionTokenizer | |||
exprStr = exprStr.trim(); | |||
} | |||
if((exprStr == null) || (exprStr.length() == 0)) { | |||
if(StringUtils.isEmpty(exprStr)) { | |||
return null; | |||
} | |||
@@ -41,6 +41,7 @@ import com.healthmarketscience.jackcess.expr.EvalException; | |||
import com.healthmarketscience.jackcess.expr.NumericConfig; | |||
import com.healthmarketscience.jackcess.expr.TemporalConfig; | |||
import com.healthmarketscience.jackcess.expr.Value; | |||
import org.apache.commons.lang3.StringUtils; | |||
import static com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.ExprBuf; | |||
/** | |||
@@ -114,40 +115,41 @@ public class FormatUtil | |||
private static final Map<String,Fmt> PREDEF_FMTS = new HashMap<String,Fmt>(); | |||
static { | |||
PREDEF_FMTS.put("General Date", args -> ValueSupport.toValue( | |||
putPredefFormat("General Date", args -> ValueSupport.toValue( | |||
args.coerceToDateTimeValue().getAsString())); | |||
PREDEF_FMTS.put("Long Date", | |||
putPredefFormat("Long Date", | |||
new PredefDateFmt(TemporalConfig.Type.LONG_DATE)); | |||
PREDEF_FMTS.put("Medium Date", | |||
putPredefFormat("Medium Date", | |||
new PredefDateFmt(TemporalConfig.Type.MEDIUM_DATE)); | |||
PREDEF_FMTS.put("Short Date", | |||
putPredefFormat("Short Date", | |||
new PredefDateFmt(TemporalConfig.Type.SHORT_DATE)); | |||
PREDEF_FMTS.put("Long Time", | |||
putPredefFormat("Long Time", | |||
new PredefDateFmt(TemporalConfig.Type.LONG_TIME)); | |||
PREDEF_FMTS.put("Medium Time", | |||
putPredefFormat("Medium Time", | |||
new PredefDateFmt(TemporalConfig.Type.MEDIUM_TIME)); | |||
PREDEF_FMTS.put("Short Time", | |||
putPredefFormat("Short Time", | |||
new PredefDateFmt(TemporalConfig.Type.SHORT_TIME)); | |||
PREDEF_FMTS.put("General Number", args -> ValueSupport.toValue( | |||
putPredefFormat("General Number", args -> ValueSupport.toValue( | |||
args.coerceToNumberValue().getAsString())); | |||
PREDEF_FMTS.put("Currency", | |||
putPredefFormat("Currency", | |||
new PredefNumberFmt(NumericConfig.Type.CURRENCY)); | |||
PREDEF_FMTS.put("Euro", new PredefNumberFmt(NumericConfig.Type.EURO)); | |||
PREDEF_FMTS.put("Fixed", | |||
putPredefFormat("Euro", new PredefNumberFmt(NumericConfig.Type.EURO)); | |||
putPredefFormat("Fixed", | |||
new PredefNumberFmt(NumericConfig.Type.FIXED)); | |||
PREDEF_FMTS.put("Standard", | |||
putPredefFormat("Standard", | |||
new PredefNumberFmt(NumericConfig.Type.STANDARD)); | |||
PREDEF_FMTS.put("Percent", | |||
putPredefFormat("Percent", | |||
new PredefNumberFmt(NumericConfig.Type.PERCENT)); | |||
PREDEF_FMTS.put("Scientific", new ScientificPredefNumberFmt()); | |||
putPredefFormat("Scientific", new ScientificPredefNumberFmt()); | |||
PREDEF_FMTS.put("True/False", new PredefBoolFmt("True", "False")); | |||
PREDEF_FMTS.put("Yes/No", new PredefBoolFmt("Yes", "No")); | |||
PREDEF_FMTS.put("On/Off", new PredefBoolFmt("On", "Off")); | |||
putPredefFormat("True/False", new PredefBoolFmt("True", "False")); | |||
putPredefFormat("Yes/No", new PredefBoolFmt("Yes", "No")); | |||
putPredefFormat("On/Off", new PredefBoolFmt("On", "Off")); | |||
} | |||
private static final Fmt NULL_FMT = args -> ValueSupport.EMPTY_STR_VAL; | |||
private static final Fmt DUMMY_FMT = args -> args.getNonNullExpr(); | |||
private static final char QUOTE_CHAR = '"'; | |||
private static final char ESCAPE_CHAR = '\\'; | |||
@@ -282,6 +284,15 @@ public class FormatUtil | |||
_firstWeekType = firstWeekType; | |||
} | |||
public Args setExpr(Value expr) { | |||
_expr = expr; | |||
return this; | |||
} | |||
public Value getNonNullExpr() { | |||
return (_expr.isNull() ? ValueSupport.EMPTY_STR_VAL : _expr); | |||
} | |||
public boolean isNullOrEmptyString() { | |||
return(_expr.isNull() || | |||
// only a string value could ever be an empty string | |||
@@ -385,37 +396,67 @@ public class FormatUtil | |||
public String getAsString() { | |||
return _expr.getAsString(_ctx); | |||
} | |||
public Value format(Fmt fmt) { | |||
Value origExpr = _expr; | |||
try { | |||
return fmt.format(this); | |||
} catch(EvalException ee) { | |||
// values which cannot be formatted as the target type are just | |||
// returned "as is" | |||
return origExpr; | |||
} | |||
} | |||
} | |||
private FormatUtil() {} | |||
/** | |||
* Utility for leveraging format support outside of expression evaluation. | |||
*/ | |||
public static class StandaloneFormatter | |||
{ | |||
private final Fmt _fmt; | |||
private final Args _args; | |||
private StandaloneFormatter(Fmt fmt, Args args) { | |||
_fmt = fmt; | |||
_args = args; | |||
} | |||
public Value format(Value expr) { | |||
return _args.setExpr(expr).format(_fmt); | |||
} | |||
} | |||
public static Value format(EvalContext ctx, Value expr, String fmtStr, | |||
int firstDay, int firstWeekType) { | |||
Args args = new Args(ctx, expr, firstDay, firstWeekType); | |||
return args.format(createFormat(args, fmtStr)); | |||
} | |||
try { | |||
Args args = new Args(ctx, expr, firstDay, firstWeekType); | |||
public static StandaloneFormatter createStandaloneFormatter( | |||
EvalContext ctx, String fmtStr, int firstDay, int firstWeekType) { | |||
Args args = new Args(ctx, null, firstDay, firstWeekType); | |||
Fmt fmt = createFormat(args, fmtStr); | |||
return new StandaloneFormatter(fmt, args); | |||
} | |||
Fmt predefFmt = PREDEF_FMTS.get(fmtStr); | |||
if(predefFmt != null) { | |||
if(args.isNullOrEmptyString()) { | |||
// predefined formats return empty string for null | |||
return ValueSupport.EMPTY_STR_VAL; | |||
} | |||
return predefFmt.format(args); | |||
} | |||
private static Fmt createFormat(Args args, String fmtStr) { | |||
Fmt predefFmt = PREDEF_FMTS.get(fmtStr); | |||
if(predefFmt != null) { | |||
return predefFmt; | |||
} | |||
// TODO implement caching for custom formats? put into Bindings. use | |||
// special "cache" prefix to know which caches to clear when evalconfig | |||
// is altered (could also cache other Format* functions) | |||
if(StringUtils.isEmpty(fmtStr)) { | |||
return DUMMY_FMT; | |||
} | |||
return parseCustomFormat(fmtStr, args).format(args); | |||
// TODO implement caching for custom formats? put into Bindings. use | |||
// special "cache" prefix to know which caches to clear when evalconfig | |||
// is altered (could also cache other Format* functions) | |||
} catch(EvalException ee) { | |||
// values which cannot be formatted as the target type are just | |||
// returned "as is" | |||
return expr; | |||
} | |||
return parseCustomFormat(fmtStr, args); | |||
} | |||
private static Fmt parseCustomFormat(String fmtStr, Args args) { | |||
@@ -1178,6 +1219,14 @@ public class FormatUtil | |||
} | |||
} | |||
private static void putPredefFormat(String key, Fmt fmt) { | |||
// predefined formats return empty string for null | |||
Fmt wrapFmt = args -> (args.isNullOrEmptyString() ? | |||
ValueSupport.EMPTY_STR_VAL : | |||
fmt.format(args)); | |||
PREDEF_FMTS.put(key, wrapFmt); | |||
} | |||
private static final class PredefDateFmt implements Fmt | |||
{ | |||
private final TemporalConfig.Type _type; |
@@ -0,0 +1,150 @@ | |||
/* | |||
Copyright (c) 2019 James Ahlborn | |||
Licensed under the Apache License, Version 2.0 (the "License"); | |||
you may not use this file except in compliance with the License. | |||
You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
*/ | |||
package com.healthmarketscience.jackcess.util; | |||
import java.io.IOException; | |||
import java.util.Map; | |||
import com.healthmarketscience.jackcess.Column; | |||
import com.healthmarketscience.jackcess.PropertyMap; | |||
import com.healthmarketscience.jackcess.expr.EvalConfig; | |||
import com.healthmarketscience.jackcess.expr.EvalException; | |||
import com.healthmarketscience.jackcess.impl.ColEvalContext; | |||
import com.healthmarketscience.jackcess.impl.ColumnImpl; | |||
import com.healthmarketscience.jackcess.impl.expr.FormatUtil; | |||
import org.apache.commons.lang3.StringUtils; | |||
/** | |||
* Utility for applying Column formatting to column values for display. This | |||
* utility loads the "Format" property from the given column and builds an | |||
* appropriate formatter (essentially leveraging the internals of the | |||
* expression execution engine's support for the "Format()" function). Since | |||
* formats leverage the expression evaluation engine, the underlying | |||
* Database's {@link EvalConfig} can be used to alter how this utility formats | |||
* values. Note, formatted values may be suitable for <i>display only</i> | |||
* (i.e. a formatted value may not be accepted as an input value to a Table | |||
* add/update method). | |||
* | |||
* @author James Ahlborn | |||
* @usage _general_class_ | |||
*/ | |||
public class ColumnFormatter | |||
{ | |||
private final ColumnImpl _col; | |||
private final FormatEvalContext _ctx; | |||
private String _fmtStr; | |||
private FormatUtil.StandaloneFormatter _fmt; | |||
public ColumnFormatter(Column col) throws IOException { | |||
_col = (ColumnImpl)col; | |||
_ctx = new FormatEvalContext(_col); | |||
reload(); | |||
} | |||
/** | |||
* Returns the currently loaded "Format" property for this formatter, may be | |||
* {@code null}. | |||
*/ | |||
public String getFormatString() { | |||
return _fmtStr; | |||
} | |||
/** | |||
* Sets the given format string as the "Format" property for the underlying | |||
* Column and reloads this formatter. | |||
* | |||
* @param fmtStr the new format string. may be {@code null}, in which case | |||
* the "Format" property is removed from the underlying Column | |||
*/ | |||
public void setFormatString(String fmtStr) throws IOException { | |||
PropertyMap props = _col.getProperties(); | |||
if(!StringUtils.isEmpty(fmtStr)) { | |||
props.put(PropertyMap.FORMAT_PROP, fmtStr); | |||
} else { | |||
props.remove(PropertyMap.FORMAT_PROP); | |||
} | |||
props.save(); | |||
reload(); | |||
} | |||
/** | |||
* Formats the given value according to the format currently defined for the | |||
* underlying Column. | |||
* | |||
* @param val a valid input value for the DataType of the underlying Column | |||
* (i.e. a value which could be passed to a Table add/update | |||
* method for this Column). may be {@code null} | |||
* | |||
* @return the formatted result, always non-{@code null} | |||
*/ | |||
public String format(Object val) { | |||
return _ctx.format(val); | |||
} | |||
/** | |||
* Convenience method for retrieving the appropriate Column value from the | |||
* given row array and formatting it. | |||
* | |||
* @return the formatted result, always non-{@code null} | |||
*/ | |||
public String getRowValue(Object[] rowArray) { | |||
return format(_col.getRowValue(rowArray)); | |||
} | |||
/** | |||
* Convenience method for retrieving the appropriate Column value from the | |||
* given row map and formatting it. | |||
* | |||
* @return the formatted result, always non-{@code null} | |||
*/ | |||
public String getRowValue(Map<String,?> rowMap) { | |||
return format(_col.getRowValue(rowMap)); | |||
} | |||
/** | |||
* If the properties for the underlying Column have been modified directly | |||
* (or the EvalConfig for the underlying Database has been modified), this | |||
* method may be called to reload the format for the underlying Column. | |||
*/ | |||
public final void reload() throws IOException { | |||
_fmt = null; | |||
_fmtStr = null; | |||
_fmtStr = (String)_col.getProperties().getValue(PropertyMap.FORMAT_PROP); | |||
_fmt = FormatUtil.createStandaloneFormatter(_ctx, _fmtStr, 1, 1); | |||
} | |||
/** | |||
* Utility class to provide an EvalContext for the expression evaluation | |||
* engine format support. | |||
*/ | |||
private class FormatEvalContext extends ColEvalContext | |||
{ | |||
private FormatEvalContext(ColumnImpl col) { | |||
super(col); | |||
} | |||
public String format(Object val) { | |||
try { | |||
return _fmt.format(toValue(val)).getAsString(this); | |||
} catch(EvalException ee) { | |||
// invalid values for a given format result in returning the value as is | |||
return val.toString(); | |||
} | |||
} | |||
} | |||
} |
@@ -27,7 +27,7 @@ import com.healthmarketscience.jackcess.Column; | |||
* | |||
* @author James Ahlborn | |||
*/ | |||
public interface ColumnValidator | |||
public interface ColumnValidator | |||
{ | |||
/** | |||
* Validates and/or manipulates the given potential new value for the given |
@@ -117,18 +117,24 @@ public class TestUtil | |||
public static Database create(FileFormat fileFormat, boolean keep) | |||
throws Exception | |||
{ | |||
return create(fileFormat, keep, false); | |||
return create(fileFormat, keep, true); | |||
} | |||
public static Database createMem(FileFormat fileFormat) throws Exception { | |||
return create(fileFormat, false, true); | |||
return create(fileFormat); | |||
} | |||
public static Database createFile(FileFormat fileFormat) throws Exception { | |||
return create(fileFormat, false, false); | |||
} | |||
private static Database create(FileFormat fileFormat, boolean keep, | |||
boolean inMem) | |||
throws Exception | |||
{ | |||
FileChannel channel = (inMem ? MemFileChannel.newChannel() : null); | |||
FileChannel channel = ((inMem && !keep) ? MemFileChannel.newChannel() : | |||
null); | |||
if (fileFormat == FileFormat.GENERIC_JET4) { | |||
// while we don't support creating GENERIC_JET4 as a jackcess feature, |
@@ -72,7 +72,7 @@ public class CodecHandlerTest extends TestCase | |||
private static void doTestCodecHandler(boolean simple) throws Exception | |||
{ | |||
for(Database.FileFormat ff : SUPPORTED_FILEFORMATS) { | |||
Database db = TestUtil.create(ff); | |||
Database db = TestUtil.createFile(ff); | |||
int pageSize = ((DatabaseImpl)db).getFormat().PAGE_SIZE; | |||
File dbFile = db.getFile(); | |||
db.close(); | |||
@@ -163,7 +163,7 @@ public class CodecHandlerTest extends TestCase | |||
assertEquals(valuePrefix.length() + 100, value.length()); | |||
} | |||
private static void encodeFile(File dbFile, int pageSize, boolean simple) | |||
private static void encodeFile(File dbFile, int pageSize, boolean simple) | |||
throws Exception | |||
{ | |||
long dbLen = dbFile.length(); | |||
@@ -174,7 +174,7 @@ public class CodecHandlerTest extends TestCase | |||
bb.clear(); | |||
fileChannel.read(bb, offset); | |||
int pageNumber = (int)(offset / pageSize); | |||
if(simple) { | |||
simpleEncode(bb.array(), bb.array(), pageNumber, 0, pageSize); | |||
@@ -221,12 +221,12 @@ public class CodecHandlerTest extends TestCase | |||
} | |||
} | |||
private static final class SimpleCodecHandler implements CodecHandler | |||
private static final class SimpleCodecHandler implements CodecHandler | |||
{ | |||
private final TempBufferHolder _bufH = TempBufferHolder.newHolder( | |||
TempBufferHolder.Type.HARD, true); | |||
private final PageChannel _channel; | |||
private SimpleCodecHandler(PageChannel channel) { | |||
_channel = channel; | |||
} | |||
@@ -238,37 +238,37 @@ public class CodecHandlerTest extends TestCase | |||
public boolean canDecodeInline() { | |||
return true; | |||
} | |||
public void decodePage(ByteBuffer inPage, ByteBuffer outPage, | |||
int pageNumber) | |||
throws IOException | |||
int pageNumber) | |||
throws IOException | |||
{ | |||
byte[] arr = inPage.array(); | |||
simpleDecode(arr, arr, pageNumber); | |||
} | |||
public ByteBuffer encodePage(ByteBuffer page, int pageNumber, | |||
int pageOffset) | |||
int pageOffset) | |||
throws IOException | |||
{ | |||
ByteBuffer bb = _bufH.getPageBuffer(_channel); | |||
bb.clear(); | |||
simpleEncode(page.array(), bb.array(), pageNumber, pageOffset, | |||
simpleEncode(page.array(), bb.array(), pageNumber, pageOffset, | |||
page.limit()); | |||
return bb; | |||
} | |||
} | |||
private static final class FullCodecHandler implements CodecHandler | |||
private static final class FullCodecHandler implements CodecHandler | |||
{ | |||
private final TempBufferHolder _bufH = TempBufferHolder.newHolder( | |||
TempBufferHolder.Type.HARD, true); | |||
private final PageChannel _channel; | |||
private FullCodecHandler(PageChannel channel) { | |||
_channel = channel; | |||
} | |||
public boolean canEncodePartialPage() { | |||
return false; | |||
} | |||
@@ -276,17 +276,17 @@ public class CodecHandlerTest extends TestCase | |||
public boolean canDecodeInline() { | |||
return true; | |||
} | |||
public void decodePage(ByteBuffer inPage, ByteBuffer outPage, | |||
int pageNumber) | |||
throws IOException | |||
public void decodePage(ByteBuffer inPage, ByteBuffer outPage, | |||
int pageNumber) | |||
throws IOException | |||
{ | |||
byte[] arr = inPage.array(); | |||
fullDecode(arr, arr, pageNumber); | |||
} | |||
public ByteBuffer encodePage(ByteBuffer page, int pageNumber, | |||
int pageOffset) | |||
public ByteBuffer encodePage(ByteBuffer page, int pageNumber, | |||
int pageOffset) | |||
throws IOException | |||
{ | |||
assertEquals(0, pageOffset); |
@@ -0,0 +1,114 @@ | |||
/* | |||
Copyright (c) 2019 James Ahlborn | |||
Licensed under the Apache License, Version 2.0 (the "License"); | |||
you may not use this file except in compliance with the License. | |||
You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
*/ | |||
package com.healthmarketscience.jackcess.util; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.Map; | |||
import com.healthmarketscience.jackcess.Column; | |||
import com.healthmarketscience.jackcess.ColumnBuilder; | |||
import com.healthmarketscience.jackcess.CursorBuilder; | |||
import com.healthmarketscience.jackcess.DataType; | |||
import com.healthmarketscience.jackcess.Database; | |||
import com.healthmarketscience.jackcess.Database.FileFormat; | |||
import com.healthmarketscience.jackcess.IndexCursor; | |||
import com.healthmarketscience.jackcess.PropertyMap; | |||
import com.healthmarketscience.jackcess.Row; | |||
import com.healthmarketscience.jackcess.Table; | |||
import com.healthmarketscience.jackcess.TableBuilder; | |||
import junit.framework.TestCase; | |||
import static com.healthmarketscience.jackcess.TestUtil.*; | |||
import static com.healthmarketscience.jackcess.impl.JetFormatTest.*; | |||
/** | |||
* | |||
* @author James Ahlborn | |||
*/ | |||
public class ColumnFormatterTest extends TestCase | |||
{ | |||
public void testFormat() throws Exception { | |||
for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) { | |||
Database db = create(fileFormat); | |||
db.setEvaluateExpressions(true); | |||
Table t = new TableBuilder("test") | |||
.addColumn(new ColumnBuilder("id", DataType.LONG).setAutoNumber(true)) | |||
.addColumn(new ColumnBuilder("data1", DataType.TEXT) | |||
.putProperty(PropertyMap.FORMAT_PROP, | |||
">@@\\x\\x")) | |||
.addColumn(new ColumnBuilder("data2", DataType.LONG) | |||
.putProperty(PropertyMap.FORMAT_PROP, | |||
"#.#E+0")) | |||
.addColumn(new ColumnBuilder("data3", DataType.MONEY) | |||
.putProperty(PropertyMap.FORMAT_PROP, | |||
"Currency")) | |||
.toTable(db); | |||
ColumnFormatter d1Fmt = new ColumnFormatter(t.getColumn("data1")); | |||
ColumnFormatter d2Fmt = new ColumnFormatter(t.getColumn("data2")); | |||
ColumnFormatter d3Fmt = new ColumnFormatter(t.getColumn("data3")); | |||
t.addRow(Column.AUTO_NUMBER, "foobar", 37, "0.03"); | |||
t.addRow(Column.AUTO_NUMBER, "37", 4500, 4500); | |||
t.addRow(Column.AUTO_NUMBER, "foobarbaz", -37, "-37.13"); | |||
t.addRow(Column.AUTO_NUMBER, null, null, null); | |||
List<String> found = new ArrayList<>(); | |||
for(Row r : t) { | |||
found.add(d1Fmt.getRowValue(r)); | |||
found.add(d2Fmt.getRowValue(r)); | |||
found.add(d3Fmt.getRowValue(r)); | |||
} | |||
assertEquals(Arrays.asList( | |||
"FOxxOBAR", "3.7E+1", "$0.03", | |||
"37xx", "4.5E+3", "$4,500.00", | |||
"FOxxOBARBAZ", "-3.7E+1", "($37.13)", | |||
"", "", ""), | |||
found); | |||
d1Fmt.setFormatString("Scientific"); | |||
d2Fmt.setFormatString(null); | |||
d3Fmt.setFormatString("General Date"); | |||
assertEquals("Scientific", t.getColumn("data1").getProperties() | |||
.getValue(PropertyMap.FORMAT_PROP)); | |||
assertEquals("General Date", t.getColumn("data3").getProperties() | |||
.getValue(PropertyMap.FORMAT_PROP)); | |||
found = new ArrayList<>(); | |||
for(Row r : t) { | |||
found.add(d1Fmt.getRowValue(r)); | |||
found.add(d2Fmt.getRowValue(r)); | |||
found.add(d3Fmt.getRowValue(r)); | |||
} | |||
assertEquals(Arrays.asList( | |||
"foobar", "37", "12:43:12 AM", | |||
"3.70E+1", "4500", "4/26/1912", | |||
"foobarbaz", "-37", "11/23/1899 3:07:12 AM", | |||
"", "", ""), | |||
found); | |||
db.close(); | |||
} | |||
} | |||
} |