package com.alvazan.orm.impl.meta.data;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import com.alvazan.orm.api.base.Indexing;
import com.alvazan.orm.api.z8spi.conv.StorageTypeEnum;
import com.alvazan.orm.api.z8spi.meta.DboColumnMeta;
import com.alvazan.orm.api.z8spi.meta.IndexData;
import com.alvazan.orm.api.z8spi.meta.InfoForIndex;
import com.alvazan.orm.api.z8spi.meta.PartitionTypeInfo;
import com.alvazan.orm.api.z8spi.meta.ReflectionUtil;
import com.alvazan.orm.api.z8spi.meta.RowToPersist;
@SuppressWarnings("unchecked")
public abstract class MetaAbstractField<OWNER> implements MetaField<OWNER> {
protected Field field;
protected String columnName;
public Field getField() {
return field;
}
public abstract DboColumnMeta getMetaDbo();
public String getColumnName() {
return columnName;
}
public final String getFieldName() {
return field.getName();
}
public void setup(Field field2, String colName) {
this.field = field2;
this.field.setAccessible(true);
this.columnName = colName;
}
protected void removeIndexInfo(InfoForIndex<OWNER> info, Object value, byte[] byteVal, StorageTypeEnum storageType) {
Map<Field, Object> fieldToValue = info.getFieldToValue();
if(!this.getMetaDbo().isIndexed())
return;
else if(storageType == StorageTypeEnum.BYTES)
throw new IllegalArgumentException("Cannot do indexing for types that are stored as bytes at this time");
else if(fieldToValue == null)
return;
addIndexRemoves(info, value, byteVal, storageType);
}
private void addIndexRemoves(InfoForIndex<OWNER> info, Object value, byte[] byteVal, StorageTypeEnum storageType) {
RowToPersist row = info.getRow();
Map<Field, Object> fieldToValue = info.getFieldToValue();
//if we are here, we are indexed, BUT if fieldToValue is null, then it is a brand new entity and not a proxy
if(valuesEqual(fieldToValue, value))
return;
Object originalValue = fieldToValue.get(field);
byte[] pk = row.getKey();
byte[] oldIndexedVal = translateValue(originalValue);
List<IndexData> indexList = row.getIndexToRemove();
addToList(info, oldIndexedVal, storageType, pk, indexList);
}
private boolean valuesEqual(Map<Field, Object> fieldToValue, Object value) {
Object originalValue = fieldToValue.get(field);
originalValue = unwrapIfNeeded(originalValue);
if(originalValue == null && value == null)
return true;
else if(originalValue == null)
return false;
else if(originalValue.equals(value))
return true;
return false;
}
protected void addToList(InfoForIndex<OWNER> info, byte[] oldIndexedVal, StorageTypeEnum storageType, byte[] pk, List<IndexData> indexList) {
//original value and current value differ so we need to remove from the index
List<PartitionTypeInfo> partitionTypes = info.getPartitions();
for(PartitionTypeInfo part : partitionTypes) {
//NOTE: Here if we partition by account and security both AND we index both of those to, we only
//want indexes of /entityCF/account/security/<securityid>
// and /entityCF/security/account/<accountid>
// It would not be useful at all to have /entityCF/account/account/<accountid> since all the account ids in that index row would be the same!!!!
if(part.getColMeta() == this)
continue; //skip indexing if this IS the partition.
IndexData data = createAddIndexData(info.getColumnFamily(), oldIndexedVal, storageType, pk, part);
indexList.add(data);
}
}
protected void removingThisEntity(InfoForIndex<OWNER> info, List<IndexData> indexRemoves, byte[] pk) {
StorageTypeEnum storageType = getMetaDbo().getStorageType();
Map<Field, Object> fieldToValue = info.getFieldToValue();
Object valueInDatabase = fieldToValue.get(field);
byte[] oldIndexedVal = translateValue(valueInDatabase);
addToList(info, oldIndexedVal, storageType, pk, indexRemoves);
}
protected void addIndexInfo(InfoForIndex<OWNER> info, Object value, byte[] byteVal, StorageTypeEnum storageType) {
OWNER entity = info.getEntity();
RowToPersist row = info.getRow();
Map<Field, Object> fieldToValue = info.getFieldToValue();
if(!this.getMetaDbo().isIndexed())
return;
else if(storageType == StorageTypeEnum.BYTES)
throw new IllegalArgumentException("Cannot do indexing for types that are stored as bytes at this time");
if(!isNeedPersist(entity, value, fieldToValue))
return;
//original value and current value differ so we need to persist new value
byte[] pk = row.getKey();
List<IndexData> indexList = row.getIndexToAdd();
addToList(info, byteVal, storageType, pk, indexList);
}
private boolean isNeedPersist(OWNER entity, Object value, Map<Field, Object> fieldToValue) {
if(!(entity instanceof NoSqlProxy))
return true;
else if(Indexing.isForcedIndexing())
return true;
else if(valuesEqual(fieldToValue, value)) //value is equal to previous value
return false;
return true;
}
private IndexData createAddIndexData(String columnFamily,
byte[] byteVal, StorageTypeEnum storageType, byte[] pk, PartitionTypeInfo info) {
IndexData data = new IndexData();
String colFamily = getMetaDbo().getIndexTableName();
data.setColumnFamilyName(colFamily);
String indexRowKey = getMetaDbo().getIndexRowKey(info.getPartitionBy(), info.getPartitionId());
data.setRowKey(indexRowKey);
data.getIndexColumn().setIndexedValue(byteVal);
data.getIndexColumn().setPrimaryKey(pk);
data.getIndexColumn().setColumnName(getColumnName());
return data;
}
@Override
public Object getFieldRawValue(OWNER entity) {
Object value = ReflectionUtil.fetchFieldValue(entity, field);
return value;
//return unwrapIfNeeded(value);
}
//unused now I think...
@Deprecated
protected abstract Object unwrapIfNeeded(Object value);
}