jef.database.Condition.java Source code

Java tutorial

Introduction

Here is the source code for jef.database.Condition.java

Source

/*
 * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jef.database;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import jef.common.log.LogUtil;
import jef.database.dialect.DatabaseDialect;
import jef.database.dialect.type.ColumnMapping;
import jef.database.dialect.type.ColumnMappings;
import jef.database.jsqlparser.visitor.Expression;
import jef.database.meta.FBIField;
import jef.database.meta.Feature;
import jef.database.meta.ITableMetadata;
import jef.database.meta.TupleField;
import jef.database.query.JpqlExpression;
import jef.database.query.LazyQueryBindField;
import jef.database.query.RefField;
import jef.database.query.SqlContext;
import jef.database.query.SqlExpression;
import jef.database.wrapper.clause.SqlBuilder;
import jef.database.wrapper.variable.ConstantVariable;
import jef.database.wrapper.variable.QueryLookupVariable;
import jef.tools.ArrayUtils;
import jef.tools.Assert;
import jef.tools.StringUtils;
import jef.tools.collection.CollectionUtils;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

/**
 * ???? {@code name='John Smith'}? ?
 * ???????
 * 
 * @author Administrator
 * 
 */
public class Condition implements Serializable {
    private static final long serialVersionUID = -864876729368518762L;

    // public static final Condition AllRecordsCondition=new Condition();
    private static final Class<?>[] VALID_FIELD_TYPE_FOR_CONDITION = { FBIField.class, RefField.class };
    private static final Operator[] NULL_ABLE_VALUE = new Operator[] { Operator.IS_NULL, Operator.IS_NOT_NULL };

    protected Condition() {
    }

    public Condition(Field field2, Operator equals, Object value2) {
        this.field = field2;
        this.operator = equals;
        this.value = value2;
    }

    /**
     * ????
     */
    protected Field field;
    /**
     * ?
     */
    protected Operator operator;
    /**
     * ?
     */
    protected Object value;

    /**
     * ???
     * 
     * @param field
     * @param oper
     * @param value
     * @return
     */
    public static Condition get(Field field, Operator oper, Object value) {
        Assert.notNull(field);
        boolean valid = (field instanceof IConditionField) || (field instanceof Enum)
                || (field instanceof TupleField);
        if (!valid) {
            valid = ArrayUtils.fastContains(VALID_FIELD_TYPE_FOR_CONDITION, field.getClass());
        }
        Assert.isTrue(valid, "The field type " + field.getClass() + " is not a valid field for condition!");
        Condition c = new Condition();
        c.field = field;
        c.operator = oper;
        c.value = value;
        return c;
    }

    /**
     * ? ?/?) ?Field? FBIField.class,RefField.class
     * ?? IConditionField?
     * 
     * @return
     */
    public boolean isContainer() {
        return field instanceof IConditionField;
    }

    /**
     * ?? <li>=</li> <li>></li> <li>< ?</li> <li>>=</li> <li><= ?
     * </li> <li>!= ?</li> <li>^= ?</li> <li>$= ?</li> <li>*=
     * ???</li> <li>in in</li> <li>[] BETWEEN</li>
     */
    public enum Operator {
        EQUALS("="), GREAT(">"), LESS("<"), GREAT_EQUALS(">="), LESS_EQUALS("<="), MATCH_ANY("*=",
                " like "), MATCH_START("^=", " like "), MATCH_END("$=", " like "), IN("in", " in "), NOT_IN(
                        "not in"), NOT_EQUALS("!="), BETWEEN_L_L("[]"), IS_NULL("=NULL"), IS_NOT_NULL("!=NULL");

        Operator(String key, String oper) {
            this.key = key;
            this.oper = oper;
        }

        Operator(String key) {
            this.key = key;
            this.oper = key;
        }

        private String key;
        private String oper;

        public String getKey() {
            return key;
        }

        //
        public static Operator valueOfKey(String key) {
            for (Operator o : Operator.values()) {
                if (o.key.equals(key)) {
                    return o;
                }
            }
            if ("!=".equals(key)) {
                return Operator.NOT_EQUALS;
            }
            return null;
        }
    }

    public Field getField() {
        return field;
    }

    public void setField(Field field) {
        this.field = field;
    }

    public Operator getOperator() {
        return operator;
    }

    public void setOperator(Operator operator) {
        this.operator = operator;
    }

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }

    // ???where?
    public String toSqlClause(ITableMetadata meta, SqlContext context, SqlProcessor processor,
            IQueryableEntity instance, DatabaseDialect profile, boolean batch) {
        if (field == null) {
            throw new NullPointerException("Condition not complete!");
        }
        Field field = this.field;
        // Field?
        if (field instanceof IConditionField) {
            return ((IConditionField) field).toSql(meta, processor, context, instance, profile, batch);
        } else if (field instanceof RefField) {
            RefField ref = (RefField) field;
            ITableMetadata refMeta = ((RefField) field).getInstanceQuery(context).getMeta();
            SqlContext refContext = context.getContextOf(ref.getInstanceQuery(context));
            // ???
            field = ref.getField();
            meta = refMeta;
            context = refContext;
            instance = ref.getInstanceQuery(context).getInstance();
        }
        // Like?
        if (ArrayUtils.contains(Like.LIKE_OPERATORS, operator)) {
            Like like = new Like(field, operator, value);
            return like.toSql(meta, profile, context, instance);
        }
        String columnName;
        if (field instanceof JpqlExpression) {
            columnName = ((JpqlExpression) field).toSqlAndBindAttribs(context, profile);
        } else {
            columnName = DbUtils.toColumnName(field, profile,
                    context == null ? null : context.getCurrentAliasAndCheck(field));
        }
        if (operator == null) {
            return columnName;
        }
        if (profile.has(Feature.EMPTY_CHAR_IS_NULL) && value instanceof CharSequence) {
            if (((CharSequence) value).length() == 0) {
                value = null;
            }
        }
        // Field?
        if (ArrayUtils.notContains(NULL_ABLE_VALUE, operator) && value == null) {
            if (operator == Operator.EQUALS) {
                operator = Operator.IS_NULL;
            } else if (operator == Operator.NOT_EQUALS) {
                operator = Operator.IS_NOT_NULL;
            } else {
                throw new NullPointerException(
                        "Condition value can not be null: " + field.name() + " " + operator.getKey());
            }
        }

        ColumnMapping type = null;
        if (field instanceof Enum || field instanceof TupleField) {// ?
            type = meta.getColumnDef(field);
            if (type == null) {
                throw new IllegalArgumentException("There is no proper field in " + meta.getThisType().getName()
                        + " to populate a SQL condition expression:" + field.name());
            }
        }
        return toSql(columnName, operator, value, profile, context, type);
    }

    /*
     * ?Update?Where?sql? xx=?  xx is null???Field
     */
    public void toPrepareSqlClause(SqlBuilder builder, ITableMetadata meta, SqlContext context,
            SqlProcessor processor, IQueryableEntity instance, DatabaseDialect profile, boolean batch) {
        // Field?
        if (field instanceof IConditionField) {
            ((IConditionField) field).toPrepareSql(builder, meta, processor, context, instance, profile, batch);
            return;
        } else if (field instanceof LazyQueryBindField) {
            LazyQueryBindField ref = (LazyQueryBindField) field;
            ITableMetadata refMeta = ref.getInstanceQuery(context).getMeta();
            SqlContext refContext = context.getContextOf(ref.getInstanceQuery(context));
            if (ref instanceof RefField) {
                toPrepareSqlClause(builder, refMeta, refContext, processor,
                        ref.getInstanceQuery(context).getInstance(), ((RefField) ref).getField(), profile, batch);
                return;
            }
        }
        toPrepareSqlClause(builder, meta, context, processor, instance, field, profile, batch);
    }

    /**
     * ??
     * 
     * @return
     */
    private void toPrepareSqlClause(SqlBuilder builder, ITableMetadata meta, SqlContext context,
            SqlProcessor processor, IQueryableEntity instance, Field rawField, DatabaseDialect profile,
            boolean batch) {
        // valueField
        if (value instanceof jef.database.Field && value.getClass().isEnum()) {// valuefield
            value = new RefField((Field) value);
        }
        // ???
        if ((value instanceof Expression) || value instanceof RefField) {
            builder.append(toSqlClause(meta, context, processor, instance, profile, batch));
            return;
        }
        // Like?
        if (ArrayUtils.contains(Like.LIKE_OPERATORS, operator)) {
            Like like = new Like(rawField, operator, value);
            like.toPrepareSql(builder, meta, profile, context, instance, batch);
            return;
        }
        // ??
        if (operator == null || rawField == null) {
            throw new NullPointerException("Condition not complete!");
        }
        if (profile.has(Feature.EMPTY_CHAR_IS_NULL) && value instanceof CharSequence) {
            if (((CharSequence) value).length() == 0) {
                value = null;
            }
        }
        // ?is nullis not null?
        if (value == null && ArrayUtils.notContains(NULL_ABLE_VALUE, operator)) {
            if (operator == Operator.EQUALS) {
                operator = Operator.IS_NULL;
            } else if (operator == Operator.NOT_EQUALS) {
                operator = Operator.IS_NOT_NULL;
            } else {
                throw new IllegalArgumentException(
                        "The value of condition [" + field + " " + operator.getKey() + " (...)] must not be null!");
            }
        }

        String columnName;
        if (rawField instanceof JpqlExpression) {
            columnName = ((JpqlExpression) rawField).toSqlAndBindAttribs(context, profile);
        } else {
            columnName = DbUtils.toColumnName(rawField, profile,
                    context == null ? null : context.getCurrentAliasAndCheck(rawField));
        }

        if (operator == Operator.IS_NULL) {
            builder.append(columnName, " IS NULL");
            return;
        } else if (operator == Operator.IS_NOT_NULL) {
            builder.append(columnName, " IS NOT NULL");
            return;
        }
        if (getInBetweenOper(operator) != null) {
            processBetween(builder, columnName, rawField, profile, meta, context, processor, instance, batch);
            return;
        } else {
            builder.append(columnName, operator.oper, "?");
            if (batch) {
                builder.addBind(new QueryLookupVariable(rawField, operator));
            } else {
                builder.addBind(
                        new ConstantVariable(rawField.name(), operator, value, meta.getColumnDef(rawField)));
            }

        }
    }

    private void processBetween(SqlBuilder builder, String columnName, Field rawField, DatabaseDialect profile,
            ITableMetadata meta, SqlContext context, SqlProcessor processor, IQueryableEntity instance,
            boolean batch) {
        String[] spOpers = getInBetweenOper(operator);
        String oper = spOpers[0];
        String div = spOpers[1];
        String tailer = spOpers[2];
        // ?String
        if (value instanceof CharSequence) {
            String[] value1 = StringUtils.split(value.toString(), ',');
            for (int i = 0; i < value1.length; i++) {
                value1[i] = value1[i].trim();
            }
            value = value1;
        }
        if (CollectionUtils.isArrayOrCollection(value.getClass())) {
            int len = CollectionUtils.length(value);
            if (operator == Operator.BETWEEN_L_L && len != 2) {// BETWEEN?
                throw new RuntimeException("The between operator must have 2 params");
            }
            if (len == 0) {
                if (Operator.IN == operator) {// ?IN??
                    builder.append("1=2");
                } else if (Operator.NOT_IN == operator) {// ?NOT IN?
                    builder.append("1=1");
                }
            } else {
                builder.append(columnName, oper);
                int n = 0;
                for (Iterator<Object> iter = CollectionUtils.iterator(value, Object.class); iter.hasNext();) {
                    Object o = iter.next();
                    if (n > 0)
                        builder.append(div);
                    if (o instanceof Field) {
                        Condition c = get((Field) o, null, null);
                        builder.append(c.toSqlClause(meta, context, processor, instance, profile, batch));
                    } else {
                        builder.append("?");
                        if (batch) {
                            builder.addBind(new QueryLookupVariable(rawField, operator));
                        } else {

                            builder.addBind(new ConstantVariable(rawField.name(), operator, o,
                                    meta.getColumnDef(rawField)));
                        }
                    }
                    n++;
                }
                builder.append(tailer);
            }
        } else {
            throw new RuntimeException("Error param, the value of in operator must be a array or string :"
                    + value.getClass().getName());
        }

    }

    private static final String[] IN_OPER = new String[] { " in (", ", ", ")" };
    private static final String[] NOT_IN_OPER = new String[] { " not in (", ", ", ")" };
    private static final String[] BETWEEN_OPER = new String[] { " between ", " and ", "" };

    private static String[] getInBetweenOper(Operator oper) {
        if (oper == Operator.IN) {
            return IN_OPER;
        } else if (oper == Operator.BETWEEN_L_L) {
            return BETWEEN_OPER;
        } else if (oper == Operator.NOT_IN) {
            return NOT_IN_OPER;
        }
        return null;
    }

    public static String toSql(String columnName, Operator operator, Object value, DatabaseDialect profile,
            SqlContext context, ColumnMapping type) {
        if (value instanceof jef.database.Field && value.getClass().isEnum()) {// field
            value = new RefField((Field) value);
        }
        // ??SQL
        String[] spOpers;
        StringBuilder sb = new StringBuilder();
        if (operator == Operator.IS_NULL) {
            sb.append(columnName).append(" is null");
        } else if (value == Operator.IS_NOT_NULL) {
            sb.append(columnName).append(" is not null");
        } else if (value instanceof RefField) {
            RefField rf = (RefField) value;
            String alias = context == null ? "" : context.getAliasOf(rf.getInstanceQuery(context));
            if (alias != null) {
                sb.append(columnName).append(operator.oper).append(alias);
                if (alias.length() > 0)
                    sb.append('.');
                sb.append(DbUtils.toColumnName(rf.getFieldDef(), profile, null));
            } else {
                LogUtil.show("Not found Table Alias for ref-field:" + rf.toString());
                sb.append(columnName).append(operator.oper)
                        .append(DbUtils.toColumnName(rf.getFieldDef(), profile, null));
            }
        } else if ((spOpers = getInBetweenOper(operator)) != null) {
            String oper = spOpers[0];
            String div = spOpers[1];
            String tailer = spOpers[2];
            if (value instanceof CharSequence) {
                sb.append(columnName).append(oper).append('\'').append(value.toString()).append('\'')
                        .append(tailer);
            } else {
                List<String> sqlValues = new ArrayList<String>();
                Iterator<Object> iter = CollectionUtils.iterator(value, Object.class);
                Assert.notNull(iter, "Error param, the value of in operator must be a array or string :"
                        + value.getClass().getName());
                for (; iter.hasNext();) {
                    Object v = iter.next();
                    sqlValues.add(type.getSqlStr(v, profile));
                }
                if (operator == Operator.BETWEEN_L_L && sqlValues.size() != 2) {// BETWEEN?
                    throw new RuntimeException("The between operator must have 2 params");
                }
                if (sqlValues.size() == 0) {// in?
                    sb.append("1=2");
                } else {
                    sb.append(columnName).append(oper).append(StringUtils.join(sqlValues, div)).append(tailer);
                }
            }
        } else if (value instanceof SqlExpression) {
            sb.append(columnName).append(operator.oper).append(((SqlExpression) value).getText());
        } else if (value instanceof JpqlExpression) {
            JpqlExpression jpql = (JpqlExpression) value;
            sb.append(columnName).append(operator.oper).append(jpql.toSqlAndBindAttribs(context, profile));
        } else {
            sb.append(columnName).append(operator.oper).append(
                    type == null ? ColumnMappings.getSqlStr(value, profile) : type.getSqlStr(value, profile));
        }
        return sb.toString();
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        if (field != null) {
            sb.append(field.name()).append(' ');
            if (field instanceof IConditionField) {
                return sb.toString();
            }
        }
        sb.append(operator == null ? "=" : operator.getKey()).append(' ');
        if (value == null) {
            sb.append("null");
        } else if (value.getClass().isArray()) {
            sb.append(ArrayUtils.toString(value));
        } else {
            sb.append(value);
        }
        return sb.toString();
    }

    @Override
    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof Condition))
            return false;
        Condition oo = (Condition) o;
        EqualsBuilder eb = new EqualsBuilder();
        eb.append(this.field, oo.field);
        eb.append(this.operator, oo.operator);
        eb.append(this.value, oo.value);
        return eb.isEquals();
    }

    @Override
    public int hashCode() {
        HashCodeBuilder b = new HashCodeBuilder();
        // modify by mjj,value???hashcode?
        // return b.append(field).append(operator).append(value).toHashCode();
        return b.append(field).append(operator).append(value).toHashCode()
                * (value == null ? 3 : new HashCodeBuilder().append(value).toHashCode());
    }
}