package jef.database;
import jef.database.Condition.Operator;
import jef.database.dialect.DatabaseDialect;
import jef.database.jsqlparser.visitor.Expression;
import jef.database.meta.Feature;
import jef.database.meta.ITableMetadata;
import jef.database.query.SqlContext;
import jef.database.wrapper.clause.SqlBuilder;
import jef.database.wrapper.variable.ConstantVariable;
import jef.database.wrapper.variable.QueryLookupVariable;
import jef.database.wrapper.variable.Variable;
import jef.tools.StringUtils;
public class Like implements VariableConverter {
public static final Operator[] LIKE_OPERATORS={Operator.MATCH_ANY,Operator.MATCH_END,Operator.MATCH_START};
private static final String ESCAPE_CLAUSE = " escape '/' ";
private Object value;
private Operator operator;
private boolean escape;// 仅当非绑定模式下,表示数值需要转义
private Field field;
// 转义替换列表,注意:/的替换一定要最先进行
private static final String[] replaceFrom = new String[] { "/", "%",
"_" };
private static final String[] replaceTo = new String[] { "//", "/%",
"/_" };
public String name() {
return " like ";
}
// 构造和初始化计算
public Like(Field field, Operator oper, Object value) {
this.field = field;
this.operator = oper;
this.value = value;
}
// 转义、并且根据运算符加上前后百分号
public Object process(Object data) {
if(data instanceof Expression){
return data.toString();
}
String valueStr = StringUtils.toString(data);
if (escape) {
valueStr = StringUtils.replaceEach(valueStr, replaceFrom,
replaceTo);
}
if (valueStr.length() == 0) {
return "%";
}
if (operator == Operator.MATCH_ANY) {
return new StringBuilder(valueStr.length() + 2).append('%')
.append(valueStr).append('%').toString();
} else if (operator == Operator.MATCH_END) {
return "%".concat(valueStr);
} else if (operator == Operator.MATCH_START) {
return valueStr.concat("%");
} else {
throw new RuntimeException("Operator is not a like operation:"
+ operator.name());
}
}
public void toPrepareSql(SqlBuilder builder,
ITableMetadata meta, DatabaseDialect dialect, SqlContext context,
IQueryableEntity instance,boolean batch) {
// 只要使用了绑定变量方式获取,那么一定要做转义
escape = !dialect.has(
Feature.NOT_SUPPORT_LIKE_ESCAPE);
String alias = context == null ? null : context.getCurrentAliasAndCheck(field);
String columnName = DbUtils.getColumnName(meta,field, alias,dialect);
builder.append(columnName,name(),"?");
if (escape) {
builder.append(ESCAPE_CLAUSE);
}
Variable bind;
if(batch){
bind = new QueryLookupVariable(field,operator, this);
}else{
bind = new ConstantVariable(field.name()+operator, this.process(value), meta.getColumnDef(field));
}
builder.addBind(bind);
}
public String toSql(ITableMetadata meta, DatabaseDialect dialect,
SqlContext context, IQueryableEntity instance) {
String valueStr = StringUtils.toString(value);
if(!(value instanceof Expression)){
if (valueStr.indexOf('%') > -1 || valueStr.indexOf('_') > -1) {
escape = true;
}
valueStr = (String) process(valueStr);
}
StringBuilder sb = new StringBuilder();
String alias = context == null ? null : context.getCurrentAliasAndCheck(field);
String columnName = DbUtils.toColumnName(field,dialect,alias);
sb.append(columnName).append(name());
sb.append('\'');
sb.append(valueStr);
sb.append('\'');
if (escape) {
sb.append(ESCAPE_CLAUSE);
}
return sb.toString();
}
@Override
public String toString() {
return field.name() + " " + operator.getKey();
}
}