* MEDIUM
- implement (optional) foreign key enforcement
* MEDIUM
+- implement write support for properties
+ * EASY
- implement table, column, index renaming
* EASY
- implement table, column, index deletion
import java.util.Date;
/**
+ * Complex value corresponding to an attachment.
*
* @author James Ahlborn
*/
package com.healthmarketscience.jackcess.complex;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
+ * Complex column info for a column holding 0 or more attachments per row.
*
* @author James Ahlborn
*/
}
@Override
- protected List<Attachment> toValues(ComplexValueForeignKey complexValueFk,
- List<Map<String,Object>> rawValues)
- throws IOException
- {
- List<Attachment> attachments = new ArrayList<Attachment>();
- for(Map<String,Object> rawValue : rawValues) {
- attachments.add(toAttachment(complexValueFk, rawValue));
- }
- return attachments;
- }
-
- protected AttachmentImpl toAttachment(ComplexValueForeignKey complexValueFk,
- Map<String,Object> rawValue) {
+ protected AttachmentImpl toValue(ComplexValueForeignKey complexValueFk,
+ Map<String,Object> rawValue) {
int id = (Integer)getPrimaryKeyColumn().getRowValue(rawValue);
String url = (String)getFileUrlColumn().getRowValue(rawValue);
String name = (String)getFileNameColumn().getRowValue(rawValue);
// the flat table has all the "value" columns and 2 extra columns, a
// primary key for each row, and a LONG value which is essentially a
// foreign key to the main table.
- _typeCols = new ArrayList<Column>();
+ List<Column> typeCols = new ArrayList<Column>();
List<Column> otherCols = new ArrayList<Column>();
- diffFlatColumns(typeObjTable, flatTable, _typeCols, otherCols);
+ diffFlatColumns(typeObjTable, flatTable, typeCols, otherCols);
+
+ _typeCols = Collections.unmodifiableList(typeCols);
Column pkCol = null;
Column complexValFkCol = null;
return toValues(complexValueFk, rawValues);
}
+ protected List<V> toValues(ComplexValueForeignKey complexValueFk,
+ List<Map<String,Object>> rawValues)
+ throws IOException
+ {
+ List<V> values = new ArrayList<V>();
+ for(Map<String,Object> rawValue : rawValues) {
+ values.add(toValue(complexValueFk, rawValue));
+ }
+
+ return values;
+ }
+
public int addRawValue(Map<String,Object> rawValue) throws IOException {
Object[] row = _flatTable.asRow(rawValue);
_flatTable.addRow(row);
public abstract ComplexDataType getType();
- protected abstract List<V> toValues(
+ protected abstract V toValue(
ComplexValueForeignKey complexValueFk,
- List<Map<String,Object>> rawValues)
+ Map<String,Object> rawValues)
throws IOException;
protected static class ComplexValueImpl implements ComplexValue
package com.healthmarketscience.jackcess.complex;
/**
+ * Secondary type classification for the data in a complex column.
*
* @author James Ahlborn
*/
import com.healthmarketscience.jackcess.Column;
/**
+ * Base class for a value in a complex column (where there may be multiple
+ * values for a single row in the main table).
*
* @author James Ahlborn
*/
public interface ComplexValue
{
+ /**
+ * Returns the unique identifier of this complex value (this value is unique
+ * among all values in all rows of the main table).
+ *
+ * @return the current id or {@link ComplexColumnInfo#INVALID_ID} for a new,
+ * unsaved value.
+ */
public int getId();
public void setId(int newId);
+ /**
+ * Returns the foreign key identifier for this complex value (this value is
+ * the same for all values in the same row of the main table).
+ *
+ * @return the current id or {@link ComplexColumnInfo#INVALID_COMPLEX_VALUE_ID}
+ * for a new, unsaved value.
+ */
public ComplexValueForeignKey getComplexValueForeignKey();
public void setComplexValueForeignKey(ComplexValueForeignKey complexValueFk);
+ /**
+ * @return the column in the main table with which this complex value is
+ * associated
+ */
public Column getColumn();
+ /**
+ * Writes any updated data for this complex value to the database.
+ */
public void update() throws IOException;
}
import com.healthmarketscience.jackcess.Column;
/**
+ * Value which is returned for a complex column. This value corresponds to a
+ * foreign key in a secondary table which contains the actual complex data for
+ * this row (which could be 0 or more complex values for a given row). This
+ * class contains various convenience methods for interacting with the actual
+ * complex values.
+ * <p>
+ * This class will cache the associated complex values returned from one of
+ * the lookup methods. The various modification methods will clear this cache
+ * automatically. The {@link #reset} method may be called manually to clear
+ * this internal cache.
*
* @author James Ahlborn
*/
private final Column _column;
private final int _value;
- private List<? extends ComplexValue> _values;
+ private transient List<? extends ComplexValue> _values;
- public ComplexValueForeignKey(Column column, int value)
- {
+ public ComplexValueForeignKey(Column column, int value) {
_column = column;
_value = value;
}
return (MultiValueColumnInfo)getComplexInfo();
}
+ protected UnsupportedColumnInfo getUnsupportedInfo() {
+ return (UnsupportedColumnInfo)getComplexInfo();
+ }
+
public int countValues()
throws IOException
{
return value;
}
+ public UnsupportedValue addUnsupportedValue(Map<String,Object> values)
+ throws IOException
+ {
+ reset();
+ UnsupportedValue v = UnsupportedColumnInfo.newValue(this, values);
+ getUnsupportedInfo().addValue(v);
+ return v;
+ }
+
+ public UnsupportedValue updateUnsupportedValue(UnsupportedValue value)
+ throws IOException
+ {
+ reset();
+ getUnsupportedInfo().updateValue(value);
+ return value;
+ }
+
private Object writeReplace() throws ObjectStreamException {
// if we are going to serialize this ComplexValueForeignKey, convert it
// back to a normal Integer (in case it is restored outside of the context
package com.healthmarketscience.jackcess.complex;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import com.healthmarketscience.jackcess.Table;
/**
+ * Complex column info for a column holding multiple values per row.
*
* @author James Ahlborn
*/
public Column getValueColumn() {
return _valueCol;
}
-
- @Override
- protected List<SingleValue> toValues(ComplexValueForeignKey complexValueFk,
- List<Map<String,Object>> rawValues)
- throws IOException
- {
- List<SingleValue> values = new ArrayList<SingleValue>();
- for(Map<String,Object> rawValue : rawValues) {
- values.add(toSingleValue(complexValueFk, rawValue));
- }
-
- return values;
- }
- protected SingleValueImpl toSingleValue(
+ @Override
+ protected SingleValueImpl toValue(
ComplexValueForeignKey complexValueFk,
Map<String,Object> rawValue)
{
package com.healthmarketscience.jackcess.complex;
/**
+ * Complex value corresponding to an single value in a multi-value column.
*
* @author James Ahlborn
*/
package com.healthmarketscience.jackcess.complex;
import java.io.IOException;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.healthmarketscience.jackcess.Table;
/**
+ * Complex column info for an unsupported complex type.
*
* @author James Ahlborn
*/
-public class UnsupportedColumnInfo extends ComplexColumnInfo<ComplexValue>
+public class UnsupportedColumnInfo extends ComplexColumnInfo<UnsupportedValue>
{
public UnsupportedColumnInfo(Column column, int complexId, Table typeObjTable,
super(column, complexId, typeObjTable, flatTable);
}
+ public List<Column> getValueColumns() {
+ return getTypeColumns();
+ }
+
@Override
public ComplexDataType getType()
{
}
@Override
- protected List<ComplexValue> toValues(ComplexValueForeignKey complexValueFk,
- List<Map<String,Object>> rawValues)
- throws IOException
+ protected UnsupportedValueImpl toValue(
+ ComplexValueForeignKey complexValueFk,
+ Map<String,Object> rawValue)
{
- // FIXME
- return null;
+ int id = (Integer)getPrimaryKeyColumn().getRowValue(rawValue);
+
+ Map<String,Object> values = new LinkedHashMap<String,Object>(rawValue);
+ values.remove(getPrimaryKeyColumn().getName());
+
+ return new UnsupportedValueImpl(id, complexValueFk, values);
+ }
+
+ @Override
+ protected Object[] asRow(Object[] row, UnsupportedValue value) {
+ super.asRow(row, value);
+
+ Map<String,Object> values = value.getValues();
+ for(Column col : getValueColumns()) {
+ col.setRowValue(row, col.getRowValue(values));
+ }
+
+ return row;
+ }
+
+ public static UnsupportedValue newValue(Map<String,Object> values) {
+ return newValue(INVALID_COMPLEX_VALUE_ID, values);
}
- public ComplexValue newValue() {
- // FIXME
- return null;
+ public static UnsupportedValue newValue(
+ ComplexValueForeignKey complexValueFk, Map<String,Object> values) {
+ return new UnsupportedValueImpl(INVALID_ID, complexValueFk, values);
}
+ private static class UnsupportedValueImpl extends ComplexValueImpl
+ implements UnsupportedValue
+ {
+ private Map<String,Object> _values;
+
+ private UnsupportedValueImpl(int id, ComplexValueForeignKey complexValueFk,
+ Map<String,Object> values)
+ {
+ super(id, complexValueFk);
+ _values = values;
+ }
+
+ public Map<String,Object> getValues() {
+ return _values;
+ }
+
+ public Object get(String columnName) {
+ return getValues().get(columnName);
+ }
+
+ public void set(String columnName, Object value) {
+ getValues().put(columnName, value);
+ }
+
+ @Override
+ public void update() throws IOException {
+ getComplexValueForeignKey().updateUnsupportedValue(this);
+ }
+
+ @Override
+ public String toString()
+ {
+ return "UnsupportedValue(" + getComplexValueForeignKey() + "," + getId() +
+ ") " + getValues();
+ }
+ }
}
import java.util.Date;
/**
+ * Complex value corresponding to a version of a memo column.
*
* @author James Ahlborn
*/
package com.healthmarketscience.jackcess.complex;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import com.healthmarketscience.jackcess.Table;
/**
+ * Complex column info for a column which tracking the version history of an
+ * "append only" memo column.
*
* @author James Ahlborn
*/
List<Map<String,Object>> rawValues)
throws IOException
{
- List<Version> versions = new ArrayList<Version>();
- for(Map<String,Object> rawValue : rawValues) {
- versions.add(toVersion(complexValueFk, rawValue));
- }
+ List<Version> versions = super.toValues(complexValueFk, rawValues);
// order versions newest to oldest
Collections.sort(versions);
return versions;
}
- protected VersionImpl toVersion(ComplexValueForeignKey complexValueFk,
- Map<String,Object> rawValue) {
+ @Override
+ protected VersionImpl toValue(ComplexValueForeignKey complexValueFk,
+ Map<String,Object> rawValue) {
int id = (Integer)getPrimaryKeyColumn().getRowValue(rawValue);
String value = (String)getValueColumn().getRowValue(rawValue);
Date modifiedDate = (Date)getModifiedDateColumn().getRowValue(rawValue);