package jef.database.dialect.type;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import jef.accelerator.bean.BeanAccessor;
import jef.accelerator.bean.FastBeanWrapperImpl;
import jef.database.Field;
import jef.database.IQueryableEntity;
import jef.database.annotation.DateGenerateType;
import jef.database.dialect.ColumnType;
import jef.database.dialect.DatabaseDialect;
import jef.database.meta.ITableMetadata;
import jef.database.query.Func;
import jef.database.query.SqlExpression;
import jef.database.wrapper.clause.InsertSqlClause;
import jef.database.wrapper.clause.UpdateClause;
import jef.database.wrapper.processor.InsertStep;
import jef.database.wrapper.processor.InsertStepAdapter;
import jef.database.wrapper.variable.ConstantVariable;
import jef.tools.reflect.Property;
abstract class AbstractTimeMapping extends AColumnMapping implements VersionSupportColumn {
private DateGenerateType generated;
private boolean version;
private Property accessor;
@Override
public void init(Field field, String columnName, ColumnType type, ITableMetadata meta) {
super.init(field, columnName, type, meta);
if (type instanceof ColumnType.TimeStamp) {
ColumnType.TimeStamp cType = (ColumnType.TimeStamp) type;
this.generated = cType.getGenerateType();
this.version = cType.isVersion();
} else if (type instanceof ColumnType.Date) {
this.generated = ((ColumnType.Date) type).getGenerateType();
}
if (generated == DateGenerateType.modified_nano) {
throw new UnsupportedOperationException("the genrator 'modified_nano' only supports java datatype long <-> number in database.");
}
// 根据缺省值修复
Object defaultValue = type.defaultValue;
if (generated == null && (defaultValue == Func.current_date || defaultValue == Func.current_time || defaultValue == Func.now)) {
generated = DateGenerateType.created;
}
if (generated == null && defaultValue != null) {
String dStr = defaultValue.toString().toLowerCase();
if (dStr.startsWith("current") || dStr.startsWith("sys")) {
generated = DateGenerateType.created;
}
}
// 修复不一致的逻辑,当该字段作为version字段时,必须每次自动更新
if (this.version) {
if (generated == null) {
generated = DateGenerateType.modified;
} else if (generated == DateGenerateType.created) {
generated = DateGenerateType.modified;
} else if (generated == DateGenerateType.created_sys) {
generated = DateGenerateType.modified_sys;
}
}
// 获得Accessor
BeanAccessor ba = FastBeanWrapperImpl.getAccessorFor(meta.getContainerType());
accessor = ba.getProperty(field.name());
}
final InsertStep STEP = new InsertStepAdapter() {
public void callBefore(List<? extends IQueryableEntity> data) throws SQLException {
for (IQueryableEntity q : data) {
accessor.set(q, getCurrentValue());
}
}
};
@Override
public boolean isGenerated() {
return generated != null;
}
@Override
public void processPreparedInsert(IQueryableEntity obj, List<String> cStr, List<String> vStr, InsertSqlClause result, boolean smart) throws SQLException {
if (!obj.isUsed(field) && generated != null) {
if (isJavaSysdate()) {
result.getCallback().addProcessor(STEP);
} else {
cStr.add(getColumnName(result.profile, true));
vStr.add(getFunctionString(result.profile));
return;
}
}
super.processPreparedInsert(obj, cStr, vStr, result, smart);
}
public Object getAutoUpdateValue(DatabaseDialect profile, Object bean) {
if (isJavaSysdate()) {
Object value = getCurrentValue();
accessor.set(bean, value);
return value;
} else {
return new SqlExpression(getFunctionString(profile));
}
}
public void processAutoUpdate(DatabaseDialect profile, UpdateClause result) {
String columnName = getColumnName(profile, true);
if (isJavaSysdate()) {
result.addEntry(columnName, new ConstantVariable(getCurrentSqlValue()));
} else {
result.addEntry(columnName, getFunctionString(profile));
}
}
public final boolean isUpdateAlways() {
return generated != null && generated.isModify;
}
public boolean isVersion() {
return version;
}
/**
* 获得数据库当前日期(或时间)的函数表达式,起到获得数据库时间的作用。 用途是拼接在SQL中,在维护数据库列时将字段写入为数据库的当前时间。
*
* @param dialect
* 数据库方言
* @return 数据库表达式
*/
public abstract String getFunctionString(DatabaseDialect dialect);
/**
* 获得当前日期的Java形式 用途是作为参数直接写入到数据库中。即在维护数据库字段时,将字段值写入为当前Java的时间。 <h3>
* 注意:要求返回的类型等同于该Java字段的类型 (#getDefaultJavaType 的类型)</h3>
*
* @return 写入大到数据库的绑定变量值
*/
public abstract Object getCurrentValue();
private final boolean isJavaSysdate() {
return generated != null && generated.isJavaTime;
}
private Object getCurrentSqlValue() {
if (this.getSqlType() == Types.TIMESTAMP) {
return new java.sql.Timestamp(System.currentTimeMillis());
} else {
return new java.sql.Date(System.currentTimeMillis());
}
}
}