package jef.database.dialect.type;
import java.lang.annotation.Annotation;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import javax.persistence.Column;
import jef.accelerator.bean.BeanAccessor;
import jef.database.DbUtils;
import jef.database.Field;
import jef.database.IQueryableEntity;
import jef.database.annotation.UnsavedValue;
import jef.database.dialect.ColumnType;
import jef.database.dialect.DatabaseDialect;
import jef.database.jsqlparser.visitor.Expression;
import jef.database.meta.ITableMetadata;
import jef.database.wrapper.clause.InsertSqlClause;
import jef.tools.Assert;
import jef.tools.DateUtils;
import jef.tools.StringUtils;
import jef.tools.collection.ElementFilter;
import jef.tools.reflect.ConvertUtils;
import jef.tools.reflect.Property;
public abstract class AColumnMapping implements ColumnMapping {
/**
* 原始的ColumnName
*/
public String rawColumnName;
protected transient String cachedEscapeColumnName;
private transient String lowerColumnName;
private transient String upperColumnName;
protected ITableMetadata meta;
private String fieldName;
protected Field field;
protected ColumnType columnDef;
protected Class<?> clz;
private boolean pk;
protected transient DatabaseDialect bindedProfile;
protected Property fieldAccessor;
private boolean unsavedValueDeclared;
private ElementFilter<Object> unsavedValue;
private boolean notInsert;
private boolean notUpdate;
public AColumnMapping() {
this.clz = getDefaultJavaType();
}
abstract protected Class<?> getDefaultJavaType();
public String name() {
return fieldName;
}
public boolean isPk() {
return pk;
}
private static class ConstantFilter implements ElementFilter<Object> {
private Object object1;
ConstantFilter(Object obj) {
this.object1 = obj;
}
public boolean apply(Object object2) {
if (object1 == object2) {
return true;
}
if ((object1 == null) || (object2 == null)) {
return false;
}
return object1.equals(object2);
}
}
private static final ElementFilter<Object> Null = new ElementFilter<Object>() {
public boolean apply(Object obj) {
return obj == null;
}
};
private static final ElementFilter<Object> NullOrEmpty = new ElementFilter<Object>() {
public boolean apply(Object obj) {
if (obj == null)
return true;
return String.valueOf(obj).length() == 0;
}
};
private static final ElementFilter<Object> MinusNumber = new ElementFilter<Object>() {
public boolean apply(Object obj) {
if (obj == null)
return true;
if (obj instanceof Number) {
return ((Number) obj).longValue() < 0;
} else {
return false;
}
}
};
private static final ElementFilter<Object> ZeroAndMinus = new ElementFilter<Object>() {
public boolean apply(Object obj) {
if (obj == null)
return true;
if (obj instanceof Number) {
return ((Number) obj).longValue() <= 0;
} else {
return false;
}
}
};
public void init(Field field, String columnName, ColumnType type, ITableMetadata meta) {
this.field = field;
this.fieldName = field.name();
this.rawColumnName = columnName;
this.lowerColumnName = columnName.toLowerCase();
this.upperColumnName = columnName.toUpperCase();
this.meta = meta;
this.columnDef = type;
BeanAccessor ba = meta.getContainerAccessor();
fieldAccessor = ba.getProperty(field.name());
Assert.notNull(fieldAccessor, ba.toString() + field.toString());
Class<?> containerType = fieldAccessor.getType();
if (clz.isAssignableFrom(containerType)) {
this.clz = containerType;
}
Map<Class<?>, Annotation> map = ba.getAnnotationOnField(field.name());
UnsavedValue unsaveValue = map == null ? null : (UnsavedValue) map.get(UnsavedValue.class);
if (unsaveValue != null) {
unsavedValueDeclared = true;
unsavedValue = parseValue(containerType, unsaveValue.value());
} else if (containerType.isPrimitive()) {
unsavedValue = new ConstantFilter(ConvertUtils.defaultValueOfPrimitive(containerType));
}
Column column = map == null ? null : (Column) map.get(Column.class);
if (column != null) {
this.notInsert = !column.insertable();
this.notUpdate = !column.updatable();
}
}
public void jdbcUpdate(ResultSet rs, String columnIndex, Object value, DatabaseDialect dialect)
throws SQLException {
rs.updateObject(columnIndex, value);
}
private ElementFilter<Object> parseValue(Class<?> containerType, String value) {
// int 226
// short 215
// long 221
// boolean 222
// float 219
// double 228
// char 201
// byte 237
Object condition = null;
if (containerType.isPrimitive()) {
String s = containerType.getName();
switch (s.charAt(1) + s.charAt(2)) {
case 226:
condition = StringUtils.toInt(value, 0);
case 215:
condition = StringUtils.toInt(value, 0);
case 221:
condition = StringUtils.toLong(value, 0L);
case 222:
condition = StringUtils.toBoolean(value, false);
case 219:
condition = StringUtils.toFloat(value, 0f);
case 228:
condition = StringUtils.toDouble(value, 0d);
case 201:
if (value.length() == 0) {
condition = (char) 0;
} else {
condition = value.charAt(0);
}
case 237:
condition = (byte) StringUtils.toInt(value, 0);
}
} else if ("null".equalsIgnoreCase(value)) {
return Null;
} else if (UnsavedValue.MinusNumber.equals(value)) {
return MinusNumber;
} else if (UnsavedValue.ZeroAndMinus.equals(value)) {
return ZeroAndMinus;
} else if (UnsavedValue.NullOrEmpty.equals(value)) {
return NullOrEmpty;
} else if (String.class == containerType) {
condition = value;
} else if (Date.class == containerType) {
condition = DateUtils.autoParse(value);
}
return condition == null ? Null : new ConstantFilter(condition);
}
public String fieldName() {
return fieldName;
}
public String upperColumnName() {
return upperColumnName;
}
public String lowerColumnName() {
return lowerColumnName;
}
@Override
public String rawColumnName() {
return rawColumnName;
}
public Field field() {
return field;
}
public ITableMetadata getMeta() {
return meta;
}
public ColumnType get() {
return columnDef;
}
public Class<?> getFieldType() {
return clz;
}
public String getColumnName(DatabaseDialect profile, boolean escape) {
if (!escape) {
return profile.getColumnNameToUse(this);
}
if (bindedProfile == profile) {
return cachedEscapeColumnName;
}
String escapedColumn = DbUtils.escapeColumn(profile, profile.getColumnNameToUse(this));
rebind(escapedColumn, profile);
return escapedColumn;
}
protected void rebind(String escapedColumn, DatabaseDialect profile) {
bindedProfile = profile;
cachedEscapeColumnName = escapedColumn;
}
public void setPk(boolean b) {
this.pk = b;
}
/**
* 用单引号包围字符串,并将其中的单引号按SQL转义
*
* @param s
* @return
*/
public final static String wrapSqlStr(String s) {
StringBuilder sb = new StringBuilder(s.length() + 16);
sb.append('\'');
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '\'') {
sb.append("''");
} else {
sb.append(c);
}
}
sb.append('\'');
return sb.toString();
}
public String getSqlStr(Object value, DatabaseDialect profile) {
if (value == null) {
return "null";
} else if (value instanceof Expression) {
return value.toString();
}
return getSqlExpression(value, profile);
}
/**
* 获得SQL表达式的写法。
*
* @param value
* 不为null,不为Expression
*/
protected abstract String getSqlExpression(Object value, DatabaseDialect profile);
public void processPreparedInsert(IQueryableEntity obj, List<String> cStr, List<String> vStr,
InsertSqlClause result, boolean dynamic) throws SQLException {
if (dynamic && !obj.isUsed(field)) {
return;
}
String columnName = getColumnName(result.profile, true);
cStr.add(columnName);
vStr.add("?");
result.addField(this);
}
public boolean isLob() {
return false;
}
public boolean applyFor(int type) {
return type == getSqlType();
}
public Property getFieldAccessor() {
return fieldAccessor;
}
@Override
public String toString() {
return this.fieldName;
}
public boolean isNotInsert() {
return notInsert;
}
public boolean isNotUpdate() {
return notUpdate;
}
/**
* 用户是否通过注解配置了UnsavedValue
*
* @return
*/
public boolean isUnsavedValueDeclared() {
return unsavedValueDeclared;
}
/**
* 判断是否为UnsavedValue。 UnsavedValue是系统认为不会存入数据库的一种值。 如果显式声明 用于判断主键无效、查询条件无效等情况
*/
@Override
public boolean isUnsavedValue(Object object) {
return unsavedValue.apply(object);
}
public boolean isGenerated() {
return false;
}
}