diff options
6 files changed, 218 insertions, 9 deletions
diff --git a/src/changes/changes.xml b/src/changes/changes.xml index d9bfccd..25c8189 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -4,6 +4,12 @@ <author email="javajedi@users.sf.net">Tim McCune</author> </properties> <body> + <release version="2.1.5" date="TBD"> + <action dev="jahlborn" type="update"> + Change multi-value complex columns so that they return all relevant + column properties. + </action> + </release> <release version="2.1.4" date="2016-05-18"> <action dev="jahlborn" type="fix" system="SourceForge2" issue="131"> Fix missing column names in AppendQuery SQL strings. diff --git a/src/main/java/com/healthmarketscience/jackcess/PropertyMap.java b/src/main/java/com/healthmarketscience/jackcess/PropertyMap.java index 6a78a3f..89a98c1 100644 --- a/src/main/java/com/healthmarketscience/jackcess/PropertyMap.java +++ b/src/main/java/com/healthmarketscience/jackcess/PropertyMap.java @@ -44,6 +44,7 @@ public interface PropertyMap extends Iterable<PropertyMap.Property> public static final String DESCRIPTION_PROP = "Description"; public static final String RESULT_TYPE_PROP = "ResultType"; public static final String EXPRESSION_PROP = "Expression"; + public static final String ALLOW_MULTI_VALUE_PROP = "AllowMultipleValues"; public String getName(); diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/ComplexColumnImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/ComplexColumnImpl.java index f143239..0e6124b 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/ComplexColumnImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/ComplexColumnImpl.java @@ -18,9 +18,13 @@ package com.healthmarketscience.jackcess.impl; import java.io.IOException; +import com.healthmarketscience.jackcess.PropertyMap; import com.healthmarketscience.jackcess.complex.ComplexColumnInfo; +import com.healthmarketscience.jackcess.complex.ComplexDataType; import com.healthmarketscience.jackcess.complex.ComplexValue; import com.healthmarketscience.jackcess.impl.complex.ComplexColumnInfoImpl; +import com.healthmarketscience.jackcess.impl.complex.MultiValueColumnInfoImpl; +import com.healthmarketscience.jackcess.impl.complex.MultiValueColumnPropertyMap; /** * ColumnImpl subclass which is used for complex data types. @@ -32,6 +36,8 @@ class ComplexColumnImpl extends ColumnImpl { /** additional information specific to complex columns */ private final ComplexColumnInfo<? extends ComplexValue> _complexInfo; + /** properties for multi-value column */ + private PropertyMap _mvProps; ComplexColumnImpl(InitArgs args) throws IOException { @@ -49,6 +55,20 @@ class ComplexColumnImpl extends ColumnImpl } @Override + public PropertyMap getProperties() throws IOException { + if(_complexInfo.getType() == ComplexDataType.MULTI_VALUE) { + if(_mvProps == null) { + PropertyMap primaryProps = super.getProperties(); + PropertyMap complexProps = ((MultiValueColumnInfoImpl)_complexInfo) + .getValueColumn().getProperties(); + _mvProps = new MultiValueColumnPropertyMap(primaryProps, complexProps); + } + return _mvProps; + } + return super.getProperties(); + } + + @Override public ComplexColumnInfo<? extends ComplexValue> getComplexInfo() { return _complexInfo; } diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/PropertyMapImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/PropertyMapImpl.java index 25bb531..619da07 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/PropertyMapImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/PropertyMapImpl.java @@ -120,14 +120,18 @@ public class PropertyMapImpl implements PropertyMap } for(Property prop : props) { - byte flag = 0; - if(prop instanceof PropertyImpl) { - flag = ((PropertyImpl)prop).getFlag(); - } - put(prop.getName(), prop.getType(), flag, prop.getValue()); + put(prop); } } + public PropertyImpl put(Property prop) { + byte flag = 0; + if(prop instanceof PropertyImpl) { + flag = ((PropertyImpl)prop).getFlag(); + } + return put(prop.getName(), prop.getType(), flag, prop.getValue()); + } + /** * Puts a property into this map with the given information. */ @@ -151,11 +155,15 @@ public class PropertyMapImpl implements PropertyMap @Override public String toString() { + return toString(this); + } + + public static String toString(PropertyMap map) { StringBuilder sb = new StringBuilder(); - sb.append(PropertyMaps.DEFAULT_NAME.equals(getName()) ? - "<DEFAULT>" : getName()) + sb.append(PropertyMaps.DEFAULT_NAME.equals(map.getName()) ? + "<DEFAULT>" : map.getName()) .append(" {"); - for(Iterator<Property> iter = iterator(); iter.hasNext(); ) { + for(Iterator<Property> iter = map.iterator(); iter.hasNext(); ) { sb.append(iter.next()); if(iter.hasNext()) { sb.append(","); @@ -163,7 +171,7 @@ public class PropertyMapImpl implements PropertyMap } sb.append("}"); return sb.toString(); - } + } public static Property createProperty(String name, DataType type, Object value) { return createProperty(name, type, (byte)0, value); diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/complex/MultiValueColumnPropertyMap.java b/src/main/java/com/healthmarketscience/jackcess/impl/complex/MultiValueColumnPropertyMap.java new file mode 100644 index 0000000..08f472c --- /dev/null +++ b/src/main/java/com/healthmarketscience/jackcess/impl/complex/MultiValueColumnPropertyMap.java @@ -0,0 +1,167 @@ +/* +Copyright (c) 2016 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.impl.complex; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import com.healthmarketscience.jackcess.DataType; +import com.healthmarketscience.jackcess.PropertyMap; +import com.healthmarketscience.jackcess.impl.PropertyMapImpl; + +/** + * PropertyMap implementation for multi-value, complex properties. The + * properties for these columns seem to be dispersed between both the primary + * column and the complex value column. The primary column only seems to have + * the simple "multi-value" property and the rest seem to be on the complex + * value column. This PropertyMap implementation combines them into one + * synthetic map. + * + * @author James Ahlborn + */ +public class MultiValueColumnPropertyMap implements PropertyMap +{ + /** properties from the primary column */ + private final PropertyMap _primary; + /** properties from the complex column */ + private final PropertyMap _complex; + + public MultiValueColumnPropertyMap(PropertyMap primary, PropertyMap complex) + { + _primary = primary; + _complex = complex; + } + + public String getName() { + return _primary.getName(); + } + + public int getSize() { + return _primary.getSize() + _complex.getSize(); + } + + public boolean isEmpty() { + return _primary.isEmpty() && _complex.isEmpty(); + } + + public Property get(String name) { + Property prop = _primary.get(name); + if(prop != null) { + return prop; + } + return _complex.get(name); + } + + public Object getValue(String name) { + return getValue(name, null); + } + + public Object getValue(String name, Object defaultValue) { + Property prop = get(name); + return ((prop != null) ? prop.getValue() : defaultValue); + } + + public Property put(String name, Object value) { + return put(name, null, value); + } + + public Property put(String name, DataType type, Object value) { + // the only property which seems to go in the "primary" is the "multi + // value" property + if(ALLOW_MULTI_VALUE_PROP.equals(name)) { + return _primary.put(name, DataType.BOOLEAN, value); + } + return _complex.put(name, value); + } + + public void putAll(Iterable<? extends Property> props) { + if(props == null) { + return; + } + + for(Property prop : props) { + if(ALLOW_MULTI_VALUE_PROP.equals(prop.getName())) { + ((PropertyMapImpl)_primary).put(prop); + } else { + ((PropertyMapImpl)_complex).put(prop); + } + } + } + + public Property remove(String name) { + if(ALLOW_MULTI_VALUE_PROP.equals(name)) { + return _primary.remove(name); + } + return _complex.remove(name); + } + + public void save() throws IOException { + _primary.save(); + _complex.save(); + } + + public Iterator<Property> iterator() { + final List<Iterator<Property>> iters = new ArrayList<Iterator<Property>>(2); + iters.add(_primary.iterator()); + iters.add(_complex.iterator()); + + return new Iterator<Property>() { + private Iterator<Property> _cur; + private Property _next = findNext(); + + private Property findNext() { + while(!iters.isEmpty()) { + _cur = iters.get(0); + if(_cur.hasNext()) { + return _cur.next(); + } + iters.remove(0); + _cur = null; + } + return null; + } + + public boolean hasNext() { + return (_next != null); + } + + public Property next() { + if(!hasNext()) { + throw new NoSuchElementException(); + } + Property prop = _next; + _next = findNext(); + return prop; + } + + public void remove() { + if(_cur != null) { + _cur.remove(); + _cur = null; + } + } + }; + } + + @Override + public String toString() { + return PropertyMapImpl.toString(this); + } +} diff --git a/src/test/java/com/healthmarketscience/jackcess/ComplexColumnTest.java b/src/test/java/com/healthmarketscience/jackcess/ComplexColumnTest.java index a2fd2eb..acecf57 100644 --- a/src/test/java/com/healthmarketscience/jackcess/ComplexColumnTest.java +++ b/src/test/java/com/healthmarketscience/jackcess/ComplexColumnTest.java @@ -302,6 +302,13 @@ public class ComplexColumnTest extends TestCase cursor.getCurrentRowValue(col); row3ValFk.deleteAllValues(); checkMultiValues(3, row3ValFk); + + // test multi-value col props + PropertyMap props = col.getProperties(); + assertEquals(Boolean.TRUE, props.getValue(PropertyMap.ALLOW_MULTI_VALUE_PROP)); + assertEquals("Value List", props.getValue("RowSourceType")); + assertEquals("\"value1\";\"value2\";\"value3\";\"value4\"", + props.getValue("RowSource")); db.close(); } |