All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dbflute.cbean.ckey.ConditionKey Maven / Gradle / Ivy

/*
 * Copyright 2014-2020 the original author or authors.
 *
 * 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 org.dbflute.cbean.ckey;

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

import org.dbflute.cbean.ConditionBean;
import org.dbflute.cbean.chelper.HpCalcSpecification;
import org.dbflute.cbean.cipher.ColumnFunctionCipher;
import org.dbflute.cbean.cipher.GearedCipherManager;
import org.dbflute.cbean.coption.ConditionOption;
import org.dbflute.cbean.coption.RangeOfOption;
import org.dbflute.cbean.cvalue.ConditionValue;
import org.dbflute.cbean.cvalue.ConditionValue.CallbackProcessor;
import org.dbflute.cbean.cvalue.ConditionValue.QueryModeProvider;
import org.dbflute.cbean.dream.SpecifiedColumn;
import org.dbflute.cbean.sqlclause.query.QueryClause;
import org.dbflute.cbean.sqlclause.query.QueryClauseArranger;
import org.dbflute.cbean.sqlclause.query.StringQueryClause;
import org.dbflute.dbmeta.info.ColumnInfo;
import org.dbflute.dbmeta.name.ColumnRealName;
import org.dbflute.dbmeta.name.ColumnSqlName;
import org.dbflute.dbway.ExtensionOperand;
import org.dbflute.dbway.OnQueryStringConnector;
import org.dbflute.exception.IllegalConditionBeanOperationException;

/**
 * The abstract class of condition-key.
 * @author jflute
 * @author h-funaki modified resolveCompoundColumn() to be able to treat coalesce option.
 */
public abstract class ConditionKey implements Serializable {

    // ===================================================================================
    //                                                                          Definition
    //                                                                          ==========
    /** The serial version UID for object serialization. (Default) */
    private static final long serialVersionUID = 1L;

    // ===================================================================================
    //                                                                          Definition
    //                                                                          ==========
    // -----------------------------------------------------
    //                                         Condition Key
    //                                         -------------
    /** The condition key of equal. */
    public static final ConditionKey CK_EQUAL = new ConditionKeyEqual();

    /** The condition key of notEqual as standard. */
    public static final ConditionKey CK_NOT_EQUAL_STANDARD = new ConditionKeyNotEqualStandard();

    /** The condition key of notEqual as tradition. */
    public static final ConditionKey CK_NOT_EQUAL_TRADITION = new ConditionKeyNotEqualTradition();

    /** The condition key of greaterThan. */
    public static final ConditionKey CK_GREATER_THAN = new ConditionKeyGreaterThan();

    /** The condition key of greaterThan with orIsNull. */
    public static final ConditionKey CK_GREATER_THAN_OR_IS_NULL = new ConditionKeyGreaterThanOrIsNull();

    /** The condition key of lessThan. */
    public static final ConditionKey CK_LESS_THAN = new ConditionKeyLessThan();

    /** The condition key of lessThan with orIsNull. */
    public static final ConditionKey CK_LESS_THAN_OR_IS_NULL = new ConditionKeyLessThanOrIsNull();

    /** The condition key of greaterEqual. */
    public static final ConditionKey CK_GREATER_EQUAL = new ConditionKeyGreaterEqual();

    /** The condition key of greaterEqual with orIsNull. */
    public static final ConditionKey CK_GREATER_EQUAL_OR_IS_NULL = new ConditionKeyGreaterEqualOrIsNull();

    /** The condition key of lessEqual. */
    public static final ConditionKey CK_LESS_EQUAL = new ConditionKeyLessEqual();

    /** The condition key of lessEqual with orIsNull. */
    public static final ConditionKey CK_LESS_EQUAL_OR_IS_NULL = new ConditionKeyLessEqualOrIsNull();

    /** The condition key of inScope. */
    public static final ConditionKey CK_IN_SCOPE = new ConditionKeyInScope();

    /** The condition key of notInScope. */
    public static final ConditionKey CK_NOT_IN_SCOPE = new ConditionKeyNotInScope();

    /** The condition key of likeSearch. */
    public static final ConditionKey CK_LIKE_SEARCH = new ConditionKeyLikeSearch();

    /** The condition key of notLikeSearch. */
    public static final ConditionKey CK_NOT_LIKE_SEARCH = new ConditionKeyNotLikeSearch();

    /** The condition key of isNull. */
    public static final ConditionKey CK_IS_NULL = new ConditionKeyIsNull();

    /** The condition key of isNullOrEmpty. */
    public static final ConditionKey CK_IS_NULL_OR_EMPTY = new ConditionKeyIsNullOrEmpty();

    /** The condition key of isNotNull. */
    public static final ConditionKey CK_IS_NOT_NULL = new ConditionKeyIsNotNull();

    /** Dummy-object for IsNull and IsNotNull and so on... */
    protected static final Object DUMMY_OBJECT = new Object();

    // -----------------------------------------------------
    //                                        Prepare Result
    //                                        --------------
    protected static final ConditionKeyPrepareResult RESULT_NEW_QUERY = ConditionKeyPrepareResult.NEW_QUERY;
    protected static final ConditionKeyPrepareResult RESULT_INVALID_QUERY = ConditionKeyPrepareResult.INVALID_QUERY;
    protected static final ConditionKeyPrepareResult RESULT_OVERRIDING_QUERY = ConditionKeyPrepareResult.OVERRIDING_QUERY;
    protected static final ConditionKeyPrepareResult RESULT_DUPLICATE_QUERY = ConditionKeyPrepareResult.DUPLICATE_QUERY;

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    // not final because of no time of refactoring...
    /** The key name of the condition. (NotNull: initialized in constructor of sub-class) */
    protected String _conditionKey;

    /** The string of operand, used in SQL. (NotNull: initialized in constructor of sub-class) */
    protected String _operand;

    // ===================================================================================
    //                                                                       Prepare Query
    //                                                                       =============
    /**
     * Prepare the query of the condition value to register the condition.
     * @param provider The provider of query mode. (NotNull)
     * @param cvalue The object of condition value. (NotNull)
     * @param value The value of the condition. (NotNull)
     * @return The result of the preparation for the condition key. (NotNull)
     */
    public ConditionKeyPrepareResult prepareQuery(final QueryModeProvider provider, final ConditionValue cvalue, final Object value) {
        return cvalue.process(new CallbackProcessor() {
            public ConditionKeyPrepareResult process() {
                return doPrepareQuery(cvalue, value);
            }

            public QueryModeProvider getProvider() {
                return provider;
            }
        });
    }

    protected abstract ConditionKeyPrepareResult doPrepareQuery(ConditionValue cvalue, Object value);

    // -----------------------------------------------------
    //                                         Choose Result
    //                                         -------------
    protected ConditionKeyPrepareResult chooseResultAlreadyExists(boolean equalValue) {
        return equalValue ? RESULT_DUPLICATE_QUERY : RESULT_OVERRIDING_QUERY;
    }

    protected ConditionKeyPrepareResult chooseResultNonValue(ConditionValue cvalue) {
        return needsOverrideValue(cvalue) ? RESULT_DUPLICATE_QUERY : RESULT_NEW_QUERY;
    }

    protected ConditionKeyPrepareResult chooseResultNonFixedQuery(Object value) {
        return isInvalidNonFixedQuery(value) ? RESULT_INVALID_QUERY : RESULT_NEW_QUERY;
    }

    protected boolean isInvalidNonFixedQuery(Object value) {
        return value == null;
    }

    protected ConditionKeyPrepareResult chooseResultListQuery(Object value) {
        return isInvalidListQuery(value) ? RESULT_INVALID_QUERY : RESULT_NEW_QUERY;
    }

    protected boolean isInvalidListQuery(Object value) {
        return value == null || !(value instanceof List) || ((List) value).isEmpty();
    }

    // ===================================================================================
    //                                                                      Override Check
    //                                                                      ==============
    /**
     * Does it need to override the existing value to register the value? 
* This should be called in CallbackProcessor for e.g. in-line query * @param cvalue The object of condition value. (NotNull) * @return The determination, true or false. */ protected abstract boolean needsOverrideValue(ConditionValue cvalue); // =================================================================================== // Where Clause // ============ /** * Add where clause. * @param provider The provider of query mode. (NotNull) * @param conditionList The list of condition. (NotNull) * @param columnRealName The real name of column. (NotNull) * @param cvalue The object of condition value. (NotNull) * @param cipher The cipher of column by function. (NullAllowed) * @param option The option of condition. (NullAllowed) */ public void addWhereClause(final QueryModeProvider provider, final List conditionList, final ColumnRealName columnRealName, final ConditionValue cvalue, // basic resources final ColumnFunctionCipher cipher, final ConditionOption option) { // optional resources cvalue.process(new CallbackProcessor() { public Void process() { doAddWhereClause(conditionList, columnRealName, cvalue, cipher, option); return null; } public QueryModeProvider getProvider() { return provider; } }); } /** * Do adding where clause. * @param conditionList The list of condition. (NotNull) * @param columnRealName The real name of column. (NotNull) * @param cvalue The object of condition value. (NotNull) * @param cipher The cipher of column by function. (NullAllowed) * @param option The option of condition. (NullAllowed) */ protected abstract void doAddWhereClause(List conditionList, ColumnRealName columnRealName, ConditionValue cvalue, ColumnFunctionCipher cipher, ConditionOption option); // =================================================================================== // Condition Value // =============== /** * Setup condition value. * @param provider The provider of query mode. (NotNull) * @param cvalue The object of condition value. (NotNull) * @param value The native value of condition. (NullAllowed) * @param location The location on parameter comment. (NotNull) * @param option Condition option. (NullAllowed) */ public void setupConditionValue(final QueryModeProvider provider, final ConditionValue cvalue, final Object value, final String location, final ConditionOption option) { cvalue.process(new CallbackProcessor() { public Void process() { doSetupConditionValue(cvalue, value, location, option); return null; } public QueryModeProvider getProvider() { return provider; } }); } /** * Do setting up condition value. * @param cvalue The object of condition value. (NotNull) * @param value The native value of condition. (NullAllowed) * @param location The location on parameter comment. (NotNull) * @param option The option of condition. (NullAllowed) */ protected abstract void doSetupConditionValue(ConditionValue cvalue, Object value, String location, ConditionOption option); // =================================================================================== // Bind Clause // =========== // ----------------------------------------------------- // Entry Point // ----------- /** * Build bind clause. * @param columnRealName The real name of column. (NotNull) * @param location The location on parameter comment. (NotNull) * @param cipher The cipher of column by function. (NullAllowed) * @param option The option of condition. (NullAllowed) * @return The query clause as bind clause. (NotNull) */ protected QueryClause buildBindClause(ColumnRealName columnRealName, String location, ColumnFunctionCipher cipher, ConditionOption option) { return new StringQueryClause(doBuildBindClause(columnRealName, location, cipher, option)); } /** * Build bind clause with orIsNull condition. * @param columnRealName The real name of column. (NotNull) * @param location The location on parameter comment. (NotNull) * @param cipher The cipher of column by function. (NullAllowed) * @param option The option of condition. (NullAllowed) * @return The query clause as bind clause. (NotNull) */ protected QueryClause buildBindClauseOrIsNull(ColumnRealName columnRealName, String location, ColumnFunctionCipher cipher, ConditionOption option) { final String mainQuery = doBuildBindClause(columnRealName, location, cipher, option); final String clause = "(" + mainQuery + " or " + columnRealName + " is null)"; return new StringQueryClause(clause); } protected String doBuildBindClause(ColumnRealName columnRealName, String location, ColumnFunctionCipher cipher, ConditionOption option) { final BindClauseResult result = resolveBindClause(columnRealName, location, cipher, option); return result.toBindClause(); } /** * Build clause without value. (basically for isNull, isNotNull) * @param columnRealName The real name of column. (NotNull) * @return The query clause as bind clause. (NotNull) */ protected QueryClause buildClauseWithoutValue(ColumnRealName columnRealName) { final String clause = columnRealName + " " + getOperand(); // no need to resolve cipher return new StringQueryClause(clause); } // ----------------------------------------------------- // Clause Resolver // --------------- protected BindClauseResult resolveBindClause(ColumnRealName columnRealName, String location, ColumnFunctionCipher cipher, ConditionOption option) { final String basicBindExp = buildBindVariableExp(location, option); final String bindExp; final ColumnRealName resolvedColumn; { final ColumnRealName columnExp; if (cipher != null) { final String plainColumnExp = columnRealName.toString(); final String decryptExp = cipher.decrypt(plainColumnExp); final boolean nonInvertible = plainColumnExp.equals(decryptExp); if (isBindEncryptAllowed(columnRealName, option, nonInvertible)) { bindExp = cipher.encrypt(basicBindExp); columnExp = columnRealName; } else { // needs to decrypt (invertible) bindExp = basicBindExp; columnExp = toColumnRealName(decryptExp); } } else { // mainly here bindExp = basicBindExp; columnExp = columnRealName; } resolvedColumn = resolveOptionalColumn(columnExp, option); } return createBindClauseResult(resolvedColumn, bindExp, option); } protected boolean isBindEncryptAllowed(ColumnRealName columnRealName, ConditionOption option, boolean nonInvertible) { if (isOutOfBindEncryptConditionKey()) { // e.g. LikeSearch return false; // regardless of invertible } if (nonInvertible) { // means it cannot decrypt return true; } // invertible here // basically decrypt but encrypt if it can be, for better performance final boolean possible = isPossibleBindEncryptConditionKey(); // e.g. Equal, NotEqual return possible && !hasColumnCollaboration(columnRealName, option); // means simple condition } protected String buildBindVariableExp(String location, ConditionOption option) { return "/*pmb." + location + "*/" + getBindVariableDummyValue(); } protected String getBindVariableDummyValue() { // to override return null; // as default } protected boolean isOutOfBindEncryptConditionKey() { // to override return false; // as default } protected boolean isPossibleBindEncryptConditionKey() { // to override return false; // as default } protected ColumnRealName toColumnRealName(String columnSqlName) { return ColumnRealName.create(null, new ColumnSqlName(columnSqlName)); } protected BindClauseResult createBindClauseResult(ColumnRealName columnExp, String bindExp, ConditionOption option) { final String operand = resolveOperand(option); final String rearOption = resolveRearOption(option); final BindClauseResult result = new BindClauseResult(columnExp, operand, bindExp, rearOption); result.setArranger(resolveWhereClauseArranger(option)); return result; } protected String resolveOperand(ConditionOption option) { final String operand = extractExtOperand(option); return operand != null ? operand : getOperand(); } protected String extractExtOperand(ConditionOption option) { final ExtensionOperand extOperand = option != null ? option.getExtensionOperand() : null; return extOperand != null ? extOperand.operand() : null; } protected String resolveRearOption(ConditionOption option) { return option != null ? option.getRearOption() : ""; } protected QueryClauseArranger resolveWhereClauseArranger(ConditionOption option) { return option != null ? option.getWhereClauseArranger() : null; } // ----------------------------------------------------- // Optional Column // --------------- protected ColumnRealName resolveOptionalColumn(ColumnRealName columnExp, ConditionOption option) { return resolveCalculationColumn(resolveCompoundColumn(columnExp, option), option); } protected boolean hasColumnCollaboration(ColumnRealName columnRealName, ConditionOption option) { return hasCalculationColumn(columnRealName, option) || hasCompoundColumn(columnRealName, option); } protected boolean hasCalculationColumn(ColumnRealName columnRealName, ConditionOption option) { return option != null && option instanceof RangeOfOption && ((RangeOfOption) option).hasCalculationRange(); } protected ColumnRealName resolveCalculationColumn(ColumnRealName columnRealName, ConditionOption option) { if (option == null) { return columnRealName; } if (option instanceof RangeOfOption) { final RangeOfOption rangeOfOption = (RangeOfOption) option; if (rangeOfOption.hasCalculationRange()) { final HpCalcSpecification calculationRange = rangeOfOption.getCalculationRange(); final String calculated = calculationRange.buildStatementToSpecifidName(columnRealName.toString()); return toColumnRealName(calculated); } } return columnRealName; } protected boolean hasCompoundColumn(ColumnRealName columnRealName, ConditionOption option) { return option != null && !option.hasCompoundColumn(); } protected ColumnRealName resolveCompoundColumn(ColumnRealName baseRealName, ConditionOption option) { if (option == null || !option.hasCompoundColumn()) { return baseRealName; } if (!option.hasStringConnector()) { // basically no way String msg = "The option should have string connector when compound column is specified: " + option; throw new IllegalConditionBeanOperationException(msg); } final List compoundColumnList = option.getCompoundColumnList(); final List realNameList = new ArrayList(); realNameList.add(doResolveCompoundColumnOption(option, baseRealName)); // already cipher for (SpecifiedColumn specifiedColumn : compoundColumnList) { realNameList.add(doResolveCompoundColumnOption(option, doResolveCompoundColumnCipher(option, specifiedColumn))); } final OnQueryStringConnector stringConnector = option.getStringConnector(); final String connected = stringConnector.connect(realNameList.toArray()); return ColumnRealName.create(null, new ColumnSqlName(connected)); } protected ColumnRealName doResolveCompoundColumnOption(ConditionOption option, ColumnRealName columnRealName) { if (option.isNullCompoundedAsEmpty()) { return toColumnRealName("coalesce(" + columnRealName + ",\'\')"); } return columnRealName; } protected ColumnRealName doResolveCompoundColumnCipher(ConditionOption option, SpecifiedColumn specifiedColumn) { final GearedCipherManager cipherManager = option.getGearedCipherManager(); final ColumnRealName specifiedName = specifiedColumn.toColumnRealName(); if (cipherManager != null && !specifiedColumn.isDerived()) { final ColumnInfo columnInfo = specifiedColumn.getColumnInfo(); final ColumnFunctionCipher cipher = cipherManager.findColumnFunctionCipher(columnInfo); if (cipher != null) { return toColumnRealName(cipher.decrypt(specifiedName.toString())); } else { return specifiedName; } } else { return specifiedName; } } // ----------------------------------------------------- //   Result Object // ------------- public static class BindClauseResult { protected final ColumnRealName _columnExp; protected final String _operand; protected final String _bindExp; protected final String _rearOption; protected QueryClauseArranger _arranger; public BindClauseResult(ColumnRealName columnExp, String operand, String bindExp, String rearOption) { _columnExp = columnExp; _operand = operand; _bindExp = bindExp; _rearOption = rearOption; } public String toBindClause() { final String clause; if (_arranger != null) { clause = _arranger.arrange(_columnExp, _operand, _bindExp, _rearOption); } else { clause = _columnExp + " " + _operand + " " + _bindExp + _rearOption; } return clause; } public ColumnRealName getColumnExp() { return _columnExp; } public String getOperand() { return _operand; } public String getBindExp() { return _bindExp; } public String getRearOption() { return _rearOption; } public QueryClauseArranger getArranger() { return _arranger; } public void setArranger(QueryClauseArranger arranger) { this._arranger = arranger; } } // =================================================================================== // Null-able Key // ============= /** * Is the condition key null-able? (basically for join determination) * @return The determination, true or false. */ public abstract boolean isNullaleKey(); // =================================================================================== // Basic Override // ============== /** * @return View-string of condition key information. */ @Override public String toString() { return "ConditionKey:{" + getConditionKey() + " " + getOperand() + "}"; } // =================================================================================== // Accessor // ======== /** * Get condition-key. * @return Condition-key. */ public String getConditionKey() { return _conditionKey; } /** * Get operand. * @return Operand. */ public String getOperand() { return _operand; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy