package jef.database;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import jef.database.Condition.Operator;
import jef.database.dialect.DatabaseDialect;
import jef.database.meta.ITableMetadata;
import jef.database.query.Query;
import jef.database.query.SqlContext;
import jef.database.wrapper.clause.BindSql;
import jef.database.wrapper.clause.SqlBuilder;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
/**
* 用于代替Field来描述特定的复杂条件 正常情况下这些对象都容纳了若干的条件甚至查询实例。
*
* 如果不考虑IConditionField的出现,那么RefField/FBIField就构成了基本Field的所有变种。
*
* 而对于IConditionField的引入,为批操作的绑定变量增加了新的难度,虽然目前没有计划在批操作中支持IConditionField。
* 但是从模型角度来解析,每个绑定变量描述应该对应一个条件树的节点,条件树指向的根节点的产生的一个路径是匹配条件树的根本。(条件树的解析) 即——
* Level1:Join[组合查询] - DataObject[查询实例] (二叉树) Level2:DataObject[查询实例] -
* 条件集合(无序集合)-条件 (基本条件/容器条件) Level3 容器条件 - 条件集合(无序集合)-条件 (基本条件/容器条件)形成一棵条件树。层次不限
*
* @author Jiyi
* @see Or
* @see And
* @see Not
* @see Exists
* @see NotExists
*/
public interface IConditionField extends jef.database.Field {
/**
* 获得所有的条件
*
* @return 条件集合
*/
List<Condition> getConditions();
/**
* 生成非绑定变量下的SQL
*
* @param meta
* @param processor
* @param context
* @param instance
* @return sql
* @deprecated To be deleted
*/
public String toSql(ITableMetadata meta, SqlProcessor processor, SqlContext context, IQueryableEntity instance, DatabaseDialect profile, boolean batch);
/**
* 生成绑定变量的SQL,
*
* @param fields
* 输出参数,会被添加一个
* @param meta
* @param processor
* @param context
* @param instance
* @return sql
*/
public void toPrepareSql(SqlBuilder builder, ITableMetadata meta, SqlProcessor processor, SqlContext context, IQueryableEntity instance, DatabaseDialect profile, boolean batch);
static abstract class AbstractAndOr implements IConditionField {
private static final long serialVersionUID = 1L;
abstract String getName();
final List<Condition> conditions = new ArrayList<Condition>();
@Override
public int hashCode() {
HashCodeBuilder hash = new HashCodeBuilder();
hash.append(getName());
int h = 0;
for (Condition c : conditions) {
h += c.hashCode();
}
hash.append(h);
return hash.toHashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof AbstractAndOr)) {
return false;
}
AbstractAndOr rhs = (AbstractAndOr) obj;
EqualsBuilder eb = new EqualsBuilder();
eb.append(getName(), rhs.getName());
eb.append(this.conditions, rhs.conditions);
return eb.isEquals();
}
public String name() {
return new StringBuilder(getName()).append(conditions.toString()).toString();
}
public void addCondition(IConditionField field) {
conditions.add(Condition.get(field, Operator.EQUALS, null));
}
public void addCondition(Condition condition) {
conditions.add(condition);
}
public void addCondition(Field field, Operator oper, Object value) {
conditions.add(Condition.get(field, oper, value));
}
public void addCondition(Field field, Object value) {
conditions.add(Condition.get(field, Operator.EQUALS, value));
}
public String toSql(ITableMetadata meta, SqlProcessor processor, SqlContext context, IQueryableEntity instance, DatabaseDialect profile, boolean batch) {
StringBuilder sb = new StringBuilder();
for (Condition c : conditions) {
if (sb.length() > 0)
sb.append(getName());
sb.append(c.toSqlClause(meta, context, processor, instance, profile, batch));
}
return conditions.size() > 1 ? "(" + sb.toString() + ")" : sb.toString();
}
public void toPrepareSql(SqlBuilder builder, ITableMetadata meta, SqlProcessor processor, SqlContext context, IQueryableEntity instance, DatabaseDialect profile, boolean batch) {
Iterator<Condition> cond = conditions.iterator();
if (conditions.size() > 1) {
builder.append("(");
}
if (cond.hasNext()) {
cond.next().toPrepareSqlClause(builder, meta, context, processor, instance, profile, batch);
}
for (; cond.hasNext();) {
builder.append(getName());
cond.next().toPrepareSqlClause(builder, meta, context, processor, instance, profile, batch);
}
if (conditions.size() > 1) {
builder.append(")");
}
}
public List<Condition> getConditions() {
return conditions;
}
}
/**
* Or条件容器
*
* @author Administrator
*
*/
public static class Or extends AbstractAndOr {
private static final long serialVersionUID = 1L;
public Or(Condition... conditionsArg) {
for (Condition c : conditionsArg) {
conditions.add(c);
}
}
String getName() {
return " or ";
}
}
/**
* Not条件容器
*
* @author Administrator
*
*/
public static class Not implements IConditionField {
private static final long serialVersionUID = 3453370626698025387L;
Condition condition;
public Not() {
}
public Not(Condition condition) {
this.condition = condition;
}
public Not(IConditionField condition) {
this.condition = Condition.get(condition, Operator.EQUALS, null);
}
public String name() {
return new StringBuilder().append("not ").append(condition.toString()).toString();
}
public String toSql(ITableMetadata meta, SqlProcessor processor, SqlContext context, IQueryableEntity instance, DatabaseDialect profile, boolean batch) {
String sql = "not ".concat(condition.toSqlClause(meta, context, processor, instance, profile, batch));
return sql;
}
public void toPrepareSql(SqlBuilder builder, ITableMetadata meta, SqlProcessor processor, SqlContext context, IQueryableEntity instance, DatabaseDialect profile, boolean batch) {
builder.append("not ");
condition.toPrepareSqlClause(builder, meta, context, processor, instance, profile, batch);
}
public List<Condition> getConditions() {
return Arrays.asList(condition);
}
@Override
public int hashCode() {
HashCodeBuilder hash = new HashCodeBuilder();
hash.append(20000);
hash.append(condition);
return hash.toHashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Not)) {
return false;
}
Not rhs = (Not) obj;
EqualsBuilder eb = new EqualsBuilder();
eb.append(this.condition, rhs.condition);
return eb.isEquals();
}
public void set(Condition cond) {
this.condition = cond;
}
public Condition get() {
return this.condition;
}
}
/**
* And条件容器
*
* @author Administrator
*
*/
public static class And extends AbstractAndOr {
private static final long serialVersionUID = -4023661686645164036L;
public And(Condition... conditions1) {
for (Condition c : conditions1) {
conditions.add(c);
}
}
String getName() {
return " and ";
}
}
/**
* NotExists条件容器
*
* @author Administrator
*
*/
public static class NotExists implements IConditionField {
private static final long serialVersionUID = -4000282148613580766L;
Query<?> query;
public String name() {
return "not exists";
}
public NotExists(Query<?> subQuery) {
this.query = subQuery;
}
public String toSql(ITableMetadata meta, SqlProcessor processor, SqlContext context, IQueryableEntity instance, DatabaseDialect profile, boolean batch) {
StringBuilder sb = new StringBuilder();
sb.append(name()).append("(");
sb.append("select 1 from ").append(DbUtils.toTableName(query.getInstance(), null, query, processor.getPartitionSupport()));
sb.append(" et ");
sb.append(processor.toWhereClause(query, new SqlContext(context, "et", query), null, profile, batch));
sb.append(")");
return sb.toString();
}
public void toPrepareSql(SqlBuilder sb, ITableMetadata meta, SqlProcessor processor, SqlContext context, IQueryableEntity instance, DatabaseDialect profile, boolean batch) {
sb.append(name(), "(");
String table = DbUtils.toTableName(query.getInstance(), null, query, processor.getPartitionSupport()).toString();
sb.append("select 1 from ", table);
sb.append(" et ");
BindSql bind = processor.toWhereClause(query, new SqlContext(context, "et", query), null, profile, batch);
sb.append(bind.getSql());
sb.append(")");
sb.addAllBind(bind.getBind());
}
public List<Condition> getConditions() {
return Arrays.asList();
}
@Override
public int hashCode() {
HashCodeBuilder hash = new HashCodeBuilder();
hash.append(40000);
hash.append(query);
return hash.toHashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof NotExists)) {
return false;
}
NotExists rhs = (NotExists) obj;
EqualsBuilder eb = new EqualsBuilder();
eb.append(this.query, rhs.query);
return eb.isEquals();
}
}
/**
* Exists条件容器
*
* @author Administrator
*
*/
public static class Exists implements IConditionField {
private static final long serialVersionUID = 6146531660079302188L;
Query<?> query;
public String name() {
return "exists";
}
public Exists(Query<?> subQuery) {
this.query = subQuery;
}
public String toSql(ITableMetadata meta, SqlProcessor processor, SqlContext context, IQueryableEntity instance, DatabaseDialect profile, boolean batch) {
StringBuilder sb = new StringBuilder();
sb.append(name()).append("(");
sb.append("select 1 from ").append(DbUtils.toTableName(query.getInstance(), null, query, processor.getPartitionSupport()));
sb.append(" et ");
sb.append(processor.toWhereClause(query, new SqlContext(context, "et", query), null, profile, batch));
sb.append(")");
return sb.toString();
}
public void toPrepareSql(SqlBuilder sb, ITableMetadata meta, SqlProcessor processor, SqlContext context, IQueryableEntity instance, DatabaseDialect profile, boolean batch) {
sb.append(name(), "(");
String table = DbUtils.toTableName(query.getInstance(), null, query, processor.getPartitionSupport()).toString();
sb.append("select 1 from ", table);
sb.append(" et ");
BindSql bind = processor.toWhereClause(query, new SqlContext(context, "et", query), null, profile, batch);
sb.append(bind.getSql());
sb.append(")");
sb.addAllBind(bind.getBind());
}
public List<Condition> getConditions() {
return Arrays.asList();
}
@Override
public int hashCode() {
HashCodeBuilder hash = new HashCodeBuilder();
hash.append(50000);
hash.append(query);
return hash.toHashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Exists)) {
return false;
}
Exists rhs = (Exists) obj;
EqualsBuilder eb = new EqualsBuilder();
eb.append(this.query, rhs.query);
return eb.isEquals();
}
}
}