git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/mutateops@1023 f203690c-595d-4dc9-a70b-905162fa7fd2tags/jackcess-2.1.5
@@ -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. |
@@ -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(); |
@@ -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 | |||
{ | |||
@@ -48,6 +54,20 @@ class ComplexColumnImpl extends ColumnImpl | |||
super.postTableLoadInit(); | |||
} | |||
@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; |
@@ -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); |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} |