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

org.dbflute.cbean.AbstractConditionQuery 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;

import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TimeZone;

import org.dbflute.FunCustodial;
import org.dbflute.cbean.chelper.HpDerivingSubQueryInfo;
import org.dbflute.cbean.chelper.HpFixedConditionQueryResolver;
import org.dbflute.cbean.chelper.HpInvalidQueryInfo;
import org.dbflute.cbean.chelper.HpQDRFunction;
import org.dbflute.cbean.chelper.HpQDRParameter;
import org.dbflute.cbean.chelper.HpQDRSetupper;
import org.dbflute.cbean.chelper.HpSLCCustomized;
import org.dbflute.cbean.chelper.HpSLCFunction;
import org.dbflute.cbean.cipher.ColumnFunctionCipher;
import org.dbflute.cbean.cipher.GearedCipherManager;
import org.dbflute.cbean.ckey.ConditionKey;
import org.dbflute.cbean.ckey.ConditionKeyInScope;
import org.dbflute.cbean.ckey.ConditionKeyPrepareResult;
import org.dbflute.cbean.coption.ConditionOption;
import org.dbflute.cbean.coption.ConditionOptionCall;
import org.dbflute.cbean.coption.DerivedReferrerOption;
import org.dbflute.cbean.coption.DerivedReferrerOptionFactory;
import org.dbflute.cbean.coption.FromToOption;
import org.dbflute.cbean.coption.LikeSearchOption;
import org.dbflute.cbean.coption.ParameterOption;
import org.dbflute.cbean.coption.RangeOfOption;
import org.dbflute.cbean.coption.ScalarConditionOption;
import org.dbflute.cbean.cvalue.ConditionValue;
import org.dbflute.cbean.cvalue.ConditionValue.QueryModeProvider;
import org.dbflute.cbean.dream.SpecifiedColumn;
import org.dbflute.cbean.exception.ConditionBeanExceptionThrower;
import org.dbflute.cbean.garnish.datefitting.DateConditionAdjuster;
import org.dbflute.cbean.ordering.ManualOrderOption;
import org.dbflute.cbean.ordering.ManualOrderOptionCall;
import org.dbflute.cbean.scoping.SubQuery;
import org.dbflute.cbean.sqlclause.SqlClause;
import org.dbflute.cbean.sqlclause.SqlClauseMySql;
import org.dbflute.cbean.sqlclause.SqlClauseOracle;
import org.dbflute.cbean.sqlclause.join.FixedConditionLazyChecker;
import org.dbflute.cbean.sqlclause.join.FixedConditionResolver;
import org.dbflute.cbean.sqlclause.orderby.OrderByElement;
import org.dbflute.cbean.sqlclause.query.QueryClause;
import org.dbflute.cbean.sqlclause.query.QueryClauseArranger;
import org.dbflute.cbean.sqlclause.query.QueryUsedAliasInfo;
import org.dbflute.cbean.sqlclause.subquery.ExistsReferrer;
import org.dbflute.cbean.sqlclause.subquery.InScopeRelation;
import org.dbflute.cbean.sqlclause.subquery.QueryDerivedReferrer;
import org.dbflute.cbean.sqlclause.subquery.ScalarCondition;
import org.dbflute.cbean.sqlclause.subquery.ScalarCondition.PartitionByProvider;
import org.dbflute.cbean.sqlclause.subquery.SpecifyDerivedReferrer;
import org.dbflute.cbean.sqlclause.subquery.SubQueryPath;
import org.dbflute.cbean.sqlclause.union.UnionClauseProvider;
import org.dbflute.dbmeta.DBMeta;
import org.dbflute.dbmeta.DBMetaProvider;
import org.dbflute.dbmeta.info.ColumnInfo;
import org.dbflute.dbmeta.info.ForeignInfo;
import org.dbflute.dbmeta.info.PrimaryInfo;
import org.dbflute.dbmeta.info.ReferrerInfo;
import org.dbflute.dbmeta.info.RelationInfo;
import org.dbflute.dbmeta.name.ColumnRealName;
import org.dbflute.dbmeta.name.ColumnRealNameProvider;
import org.dbflute.dbmeta.name.ColumnSqlName;
import org.dbflute.dbmeta.name.ColumnSqlNameProvider;
import org.dbflute.dbway.ExtensionOperand;
import org.dbflute.dbway.WayOfMySQL;
import org.dbflute.exception.ConditionInvokingFailureException;
import org.dbflute.exception.IllegalConditionBeanOperationException;
import org.dbflute.exception.OrScopeQueryAndPartUnsupportedOperationException;
import org.dbflute.helper.beans.DfBeanDesc;
import org.dbflute.helper.beans.factory.DfBeanDescFactory;
import org.dbflute.helper.function.IndependentProcessor;
import org.dbflute.helper.message.ExceptionMessageBuilder;
import org.dbflute.jdbc.Classification;
import org.dbflute.jdbc.ShortCharHandlingMode;
import org.dbflute.system.DBFluteSystem;
import org.dbflute.twowaysql.pmbean.SimpleMapPmb;
import org.dbflute.util.DfCollectionUtil;
import org.dbflute.util.DfReflectionUtil;
import org.dbflute.util.DfReflectionUtil.ReflectionFailureException;
import org.dbflute.util.DfTypeUtil;
import org.dbflute.util.Srl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The abstract class of condition-query.
 * @author jflute
 */
public abstract class AbstractConditionQuery implements ConditionQuery {

    // ===================================================================================
    //                                                                          Definition
    //                                                                          ==========
    private static final Logger _log = LoggerFactory.getLogger(AbstractConditionQuery.class);

    protected static final ConditionKey CK_EQ = ConditionKey.CK_EQUAL;
    protected static final ConditionKey CK_NES = ConditionKey.CK_NOT_EQUAL_STANDARD;
    protected static final ConditionKey CK_NET = ConditionKey.CK_NOT_EQUAL_TRADITION;
    protected static final ConditionKey CK_GT = ConditionKey.CK_GREATER_THAN;
    protected static final ConditionKey CK_LT = ConditionKey.CK_LESS_THAN;
    protected static final ConditionKey CK_GE = ConditionKey.CK_GREATER_EQUAL;
    protected static final ConditionKey CK_LE = ConditionKey.CK_LESS_EQUAL;
    protected static final ConditionKey CK_INS = ConditionKey.CK_IN_SCOPE;
    protected static final ConditionKey CK_NINS = ConditionKey.CK_NOT_IN_SCOPE;
    protected static final ConditionKey CK_LS = ConditionKey.CK_LIKE_SEARCH;
    protected static final ConditionKey CK_NLS = ConditionKey.CK_NOT_LIKE_SEARCH;
    protected static final ConditionKey CK_ISN = ConditionKey.CK_IS_NULL;
    protected static final ConditionKey CK_ISNOE = ConditionKey.CK_IS_NULL_OR_EMPTY;
    protected static final ConditionKey CK_ISNN = ConditionKey.CK_IS_NOT_NULL;

    /** Object for DUMMY. */
    protected static final Object DOBJ = new Object();

    /** The property of condition-query. */
    protected static final String CQ_PROPERTY = "conditionQuery";

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    /** SQL clause. (NotNull) */
    protected final SqlClause _sqlClause;

    /** My alias name. (NotNull) */
    protected final String _aliasName;

    /** The nest level of relation. */
    protected final int _nestLevel;

    /** The level of subQuery. */
    protected int _subQueryLevel;

    /** The base condition-bean of this query. (NotNull: after setting, basically is set) */
    protected ConditionBean _baseCB;

    // -----------------------------------------------------
    //                                          Foreign Info
    //                                          ------------
    /** The property name of foreign. */
    protected String _foreignPropertyName;

    /** The path of relation. */
    protected String _relationPath;

    /** The referrer query. */
    protected final ConditionQuery _referrerQuery;

    // -----------------------------------------------------
    //                                                Inline
    //                                                ------
    /** Is it the in-line. */
    protected boolean _inline;

    /** Is it on-clause. */
    protected boolean _onClause;

    // -----------------------------------------------------
    //                                      Relation Keeping
    //                                      ----------------
    /** The map of query-relation condition-query to keep parameters for parameter comment. */
    protected Map _queryRelationKeepingMap;

    /** The map of sub-query condition-query to keep parameters for parameter comment. */
    protected Map> _subQueryKeepingMap;

    /** The map of sub-query parameter to keep parameters for parameter comment. */
    protected Map> _subQueryParameterKeepingMap;

    /** The map of parameter option for parameter comment. */
    protected Map _parameterOptionMap;

    // ===================================================================================
    //                                                                         Constructor
    //                                                                         ===========
    /**
     * Constructor.
     * @param referrerQuery The instance of referrer query. (NullAllowed: If null, this is base query)
     * @param sqlClause The instance of SQL clause. (NotNull)
     * @param aliasName The alias name for this query. (NotNull)
     * @param nestLevel The nest level of this query. (If zero, this is base query)
     */
    public AbstractConditionQuery(ConditionQuery referrerQuery, SqlClause sqlClause, String aliasName, int nestLevel) {
        _referrerQuery = referrerQuery;
        _sqlClause = sqlClause;
        _aliasName = aliasName;
        _nestLevel = nestLevel;
    }

    // *constructor can not be changed so set it up later

    public void xsetBaseCB(ConditionBean baseCB) {
        _baseCB = baseCB;
    }

    protected  CQ xinitRelCQ(CQ cq, ConditionBean baseCB, String foreignPropertyName,
            String nestRelationPath) {
        cq.xsetBaseCB(_baseCB);
        cq.xsetForeignPropertyName(foreignPropertyName);
        cq.xsetRelationPath(nestRelationPath);
        return cq;
    }

    // ===================================================================================
    //                                                                     DBMeta Provider
    //                                                                     ===============
    /**
     * Get the provider of DB meta.
     * @return The provider of DB meta. (NotNull)
     */
    protected abstract DBMetaProvider xgetDBMetaProvider();

    /**
     * Find the DB meta.
     * @param tableFlexibleName The table flexible name. (NotNull)
     * @return The DB meta of the table. (NotNull)
     */
    protected DBMeta findDBMeta(String tableFlexibleName) {
        return xgetDBMetaProvider().provideDBMetaChecked(tableFlexibleName);
    }

    /**
     * Get the local DB meta.
     * @return The instance of local DB meta. (NotNull)
     */
    protected DBMeta xgetLocalDBMeta() {
        return findDBMeta(asTableDbName());
    }

    // ===================================================================================
    //                                                                  Important Accessor
    //                                                                  ==================
    /**
     * {@inheritDoc}
     */
    public ConditionBean xgetBaseCB() {
        return _baseCB;
    }

    /**
     * {@inheritDoc}
     */
    public ConditionQuery xgetBaseQuery() {
        ConditionQuery currentQuery = this;
        while (true) {
            final ConditionQuery referrerQuery = currentQuery.xgetReferrerQuery();
            if (referrerQuery == null) {
                break;
            }
            currentQuery = referrerQuery;
        }
        return currentQuery;
    }

    /**
     * {@inheritDoc}
     */
    public ConditionQuery xgetReferrerQuery() {
        return _referrerQuery;
    }

    /**
     * {@inheritDoc}
     */
    public SqlClause xgetSqlClause() {
        return _sqlClause;
    }

    /**
     * {@inheritDoc}
     */
    public String xgetAliasName() {
        return _aliasName;
    }

    /**
     * {@inheritDoc}
     */
    public int xgetNestLevel() {
        return _nestLevel;
    }

    /**
     * {@inheritDoc}
     */
    public int xgetNextNestLevel() {
        return _nestLevel + 1;
    }

    protected int xgetNNLvl() { // for generated source
        return xgetNextNestLevel();
    }

    /**
     * {@inheritDoc}
     */
    public boolean isBaseQuery() {
        return (xgetReferrerQuery() == null);
    }

    // -----------------------------------------------------
    //                                             Real Name
    //                                             ---------
    /**
     * {@inheritDoc}
     */
    public ColumnRealName toColumnRealName(String columnDbName) { // with finding DBMeta
        return ColumnRealName.create(xgetAliasName(), toColumnSqlName(columnDbName));
    }

    /**
     * {@inheritDoc}
     */
    public ColumnRealName toColumnRealName(ColumnInfo columnInfo) { // without finding DBMeta
        return ColumnRealName.create(xgetAliasName(), columnInfo.getColumnSqlName());
    }

    /**
     * {@inheritDoc}
     */
    public ColumnSqlName toColumnSqlName(String columnDbName) { // with finding DBMeta
        return xgetLocalDBMeta().findColumnInfo(columnDbName).getColumnSqlName();
    }

    // -----------------------------------------------------
    //                                          Foreign Info
    //                                          ------------
    /**
     * {@inheritDoc}
     */
    public String xgetForeignPropertyName() {
        return _foreignPropertyName;
    }

    public void xsetForeignPropertyName(String foreignPropertyName) {
        this._foreignPropertyName = foreignPropertyName;
    }

    /**
     * {@inheritDoc}
     */
    public String xgetRelationPath() {
        return _relationPath;
    }

    public void xsetRelationPath(String relationPath) {
        this._relationPath = relationPath;
    }

    // -----------------------------------------------------
    //                                                Inline
    //                                                ------
    public void xsetOnClause(boolean onClause) {
        _onClause = onClause;
    }

    // -----------------------------------------------------
    //                                              Location
    //                                              --------
    /**
     * {@inheritDoc}
     */
    public String xgetLocationBase() {
        final StringBuilder sb = new StringBuilder();
        ConditionQuery query = this;
        while (true) {
            if (query.isBaseQuery()) {
                sb.insert(0, CQ_PROPERTY + ".");
                break;
            } else {
                final String foreignPropertyName = query.xgetForeignPropertyName();
                if (foreignPropertyName == null) {
                    String msg = "The foreignPropertyName of the query should not be null:";
                    msg = msg + " query=" + query;
                    throw new IllegalStateException(msg);
                }
                sb.insert(0, CQ_PROPERTY + initCap(foreignPropertyName) + ".");
            }
            query = query.xgetReferrerQuery();
        }
        return sb.toString();
    }

    /**
     * Get the location of the property.
     * @param propertyName The name of property. (NotNull)
     * @return The location of the property as path. (NotNull)
     */
    protected String xgetLocation(String propertyName) {
        return xgetLocationBase() + propertyName;
    }

    // ===================================================================================
    //                                                                  Nested SetupSelect
    //                                                                  ==================
    public void xdoNss(NssCall callback) { // very internal
        final String foreignPropertyName = callback.qf().xgetForeignPropertyName();
        final String foreignTableAliasName = callback.qf().xgetAliasName();
        final String localRelationPath = xgetRelationPath();
        final String foreignRelationPath = callback.qf().xgetRelationPath();
        xgetSqlClause().registerSelectedRelation(foreignTableAliasName, asTableDbName(), foreignPropertyName, localRelationPath,
                foreignRelationPath);
    }

    @FunctionalInterface
    public static interface NssCall { // very internal
        public ConditionQuery qf();
    }

    // ===================================================================================
    //                                                                          Outer Join
    //                                                                          ==========
    /**
     * Register outer-join. 
* Optional info, fixed condition and fixed in-line, are resolved in this method. * @param foreignCQ The condition-query for foreign table. (NotNull) * @param joinOnResourceMap The resource map of join condition on on-clause. (NotNull) * @param foreignPropertyName The property name of foreign relation corresponding to this join. (NotNull) */ protected void registerOuterJoin(ConditionQuery foreignCQ, Map joinOnResourceMap, String foreignPropertyName) { final DBMeta dbmeta = xgetLocalDBMeta(); final ForeignInfo foreignInfo = dbmeta.findForeignInfo(foreignPropertyName); doRegisterOuterJoin(foreignCQ, joinOnResourceMap, foreignPropertyName, foreignInfo); } protected void doRegisterOuterJoin(ConditionQuery foreignCQ, Map joinOnResourceMap, final String foreignPropertyName, ForeignInfo foreignInfo) { // translate join-on map using column real name final Map joinOnMap = newLinkedHashMap(); for (Entry entry : joinOnResourceMap.entrySet()) { final String local = entry.getKey(); final String foreign = entry.getValue(); joinOnMap.put(toColumnRealName(local), foreignCQ.toColumnRealName(foreign)); } final String foreignAlias = foreignCQ.xgetAliasName(); final String foreignTable = foreignCQ.asTableDbName(); final String localAlias = xgetAliasName(); final String localTable = asTableDbName(); final String fixedCondition = foreignInfo.getFixedCondition(); final boolean fixedInline = foreignInfo.isFixedInline(); final FixedConditionResolver resolver = createForeignFixedConditionResolver(foreignCQ); final String relationPath = foreignCQ.xgetRelationPath(); if (fixedInline) { xgetSqlClause().registerOuterJoinFixedInline(foreignAlias, foreignTable, localAlias, localTable // basic , joinOnMap, relationPath, foreignInfo // join objects , fixedCondition, resolver); // fixed condition (to in-line view) } else { // normally here xgetSqlClause().registerOuterJoin(foreignAlias, foreignTable, localAlias, localTable // basic , joinOnMap, relationPath, foreignInfo // join objects , fixedCondition, resolver); // fixed condition (to on-clause) } xprepareFixedConditionDynamicParameterLazyChecker(foreignPropertyName, foreignInfo); } protected FixedConditionResolver createForeignFixedConditionResolver(ConditionQuery foreignCQ) { return newFixedConditionResolver(this, foreignCQ, xgetDBMetaProvider()); } protected FixedConditionResolver newFixedConditionResolver(ConditionQuery localCQ, ConditionQuery foreignCQ, DBMetaProvider dbmetaProvider) { return new HpFixedConditionQueryResolver(localCQ, foreignCQ, dbmetaProvider); } protected void xprepareFixedConditionDynamicParameterLazyChecker(final String foreignPropertyName, final ForeignInfo foreignInfo) { if (!foreignInfo.hasFixedConditionDynamicParameter()) { return; } // lazy check because the following code is allowed: // e.g. ColumnQuery // cb.columnQuery(new ... { // }).lessThan(new ... { // cb.specify().specifyMemberAddressAsValid()... // no dynamic parameter // }); xgetSqlClause().registerFixedConditionLazyChecker(new FixedConditionLazyChecker() { public void check() { xcalbackAssertFixedConditionDynamicParameter(foreignPropertyName, foreignInfo); } }); } protected void xcalbackAssertFixedConditionDynamicParameter(String foreignPropertyName, ForeignInfo foreignInfo) { // cannot get dynamic parameter map directly in super classes of runtime // and does not want to add inner class in generated classes, // so this way...as a last-ditch measure final Map parameterMap = xfindFixedConditionDynamicParameterMap(foreignPropertyName); xdoAssertFixedConditionDynamicParameter(foreignPropertyName, foreignInfo, parameterMap); } protected abstract Map xfindFixedConditionDynamicParameterMap(String property); protected void xassertFCDP(String property, Map parameterMap) { // assertFixedConditionDynamicParameter() final ForeignInfo foreignInfo = xgetLocalDBMeta().findForeignInfo(property); xdoAssertFixedConditionDynamicParameter(property, foreignInfo, parameterMap); } protected void xdoAssertFixedConditionDynamicParameter(String property, ForeignInfo foreignInfo, Map parameterMap) { if (foreignInfo.isFixedConditionDynamicParameterRequired()) { // required check boolean notFound = false; if (parameterMap != null) { for (Object value : parameterMap.values()) { if (value == null) { notFound = true; break; } } } else { // null treated as not found notFound = true; } if (notFound) { final String tableDbName = asTableDbName(); final String fixedCondition = foreignInfo.getFixedCondition(); createCBExThrower().throwFixedConditionParameterNotFoundException(tableDbName, property, fixedCondition, parameterMap); } } } // =================================================================================== // Union Query // =========== /** The map parameter-bean of union query. */ protected SimpleMapPmb _unionQueryMap; /** * Get the map parameter-bean of union query. (for parameter comment) {Internal} * @return The instance of map parameter-bean. (NotNull) */ public SimpleMapPmb xdfgetInternalUnionQueryMap() { if (_unionQueryMap == null) { _unionQueryMap = xcreateUnionMapPmb(); } return _unionQueryMap; } /** * Set union query. {Internal} * @param unionQuery Union query. (NotNull) */ public void xsetUnionQuery(ConditionQuery unionQuery) { xsetupUnion(unionQuery, false, xdfgetInternalUnionQueryMap()); } /** The map parameter-bean of union all query. */ protected SimpleMapPmb _unionAllQueryMap; /** * Get the map parameter-bean of union all query. (for parameter comment) {Internal} * @return The instance of map parameter-bean. (NotNull) */ public SimpleMapPmb xdfgetInternalUnionAllQueryMap() { if (_unionAllQueryMap == null) { _unionAllQueryMap = xcreateUnionMapPmb(); } return _unionAllQueryMap; } protected SimpleMapPmb xcreateUnionMapPmb() { return new SimpleMapPmb(); } /** * Set union all query. {Internal} * @param unionAllQuery Union all query. (NotNull) */ public void xsetUnionAllQuery(ConditionQuery unionAllQuery) { xsetupUnion(unionAllQuery, true, xdfgetInternalUnionAllQueryMap()); } protected void xsetupUnion(final ConditionQuery unionQuery, boolean unionAll, SimpleMapPmb unionQueryMap) { if (unionQuery == null) { String msg = "The argument 'unionQuery' should not be null."; throw new IllegalArgumentException(msg); } // needs to reflect lazily for: // o SetupSelect(Relation) after Union (however, basically they should be called before union) // o ManualOrder with Dream Cruise using Specify(Relation) after Union final ConditionQuery selfCQ = this; xgetSqlClause().registerClauseLazyReflector(() -> { reflectRelationOnUnionQuery(selfCQ, unionQuery); }); final String key = (unionAll ? "unionAllQuery" : "unionQuery") + unionQueryMap.size(); unionQueryMap.addParameter(key, unionQuery); final String propName = "internalUnion" + (unionAll ? "All" : "") + "QueryMap." + key; registerUnionQuery(unionQuery, unionAll, propName); } /** * Reflect relation on union query. * @param baseQueryAsSuper Base query as super. (NotNull) * @param unionQueryAsSuper Union query as super. (NotNull) */ protected abstract void reflectRelationOnUnionQuery(ConditionQuery baseQueryAsSuper, ConditionQuery unionQueryAsSuper); /** * Has union query or union all query? * @return The determination, true or false. */ public boolean hasUnionQueryOrUnionAllQuery() { return (_unionQueryMap != null && !_unionQueryMap.isEmpty()) || (_unionAllQueryMap != null && !_unionAllQueryMap.isEmpty()); } // =================================================================================== // Normal Query // ============ protected void regQ(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName) { if (prepareQueryChecked(key, value, cvalue, columnDbName).newClause()) { setupConditionValueAndRegisterWhereClause(key, value, cvalue, columnDbName); } } protected void regQ(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName, ConditionOption option) { if (prepareQueryChecked(key, value, cvalue, columnDbName).newClause()) { setupConditionValueAndRegisterWhereClause(key, value, cvalue, columnDbName, option); } } /** * @param key The condition key for the query. (NotNull) * @param value The value of the condition. (NotNull) * @param cvalue The object of condition value. (NotNull) * @param columnDbName The DB name of column for the query. (NotNull) * @return The result of the preparation for the condition key. (NotNull) */ protected ConditionKeyPrepareResult prepareQueryChecked(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName) { return xdoPrepareQuery(key, value, cvalue, columnDbName, true); } /** * @param key The condition key for the query. (NotNull) * @param value The value of the condition. (NotNull) * @param cvalue The object of condition value. (NotNull) * @param columnDbName The DB name of column for the query. (NotNull) * @return The result of the preparation for the condition key. (NotNull) */ protected ConditionKeyPrepareResult prepareQueryNoCheck(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName) { return xdoPrepareQuery(key, value, cvalue, columnDbName, false); } protected ConditionKeyPrepareResult xdoPrepareQuery(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName, boolean invalidChecked) { final ConditionKeyPrepareResult result = key.prepareQuery(xcreateQueryModeProvider(), cvalue, value); if (result.overridden()) { handleOverridingQuery(key, value, cvalue, columnDbName); } if (result.duplicate()) { noticeRegistered(key, value, cvalue, columnDbName); } if (invalidChecked && result.invalid()) { handleInvalidQuery(key, value, cvalue, columnDbName); } return result; } // =================================================================================== // Overriding Query // ================ protected void handleOverridingQuery(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName) { if (isOverrideQueryAllowed(key, value, cvalue, columnDbName)) { return; } throwQueryAlreadyRegisteredException(key, value, cvalue, columnDbName); } protected boolean isOverrideQueryAllowed(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName) { return xgetSqlClause().isOverridingQueryAllowed(); } protected void noticeRegistered(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName) { if (_log.isDebugEnabled()) { _log.debug("*Found the duplicate query: target=" + columnDbName + "." + key + " value=" + value); } } // =================================================================================== // Invalid Query // ============= protected void handleInvalidQuery(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName) { final HpInvalidQueryInfo invalidQueryInfo = xcreateInvalidQueryInfo(key, value, columnDbName); xdoHandleInvalidQuery(columnDbName, invalidQueryInfo); } protected void handleInvalidQueryList(List keyList, List valueList, String columnDbName) { if (keyList.size() != valueList.size()) { String msg = "The argument 'keyList' should have the same size as 'valueList':"; msg = msg + " keyList=" + keyList + ", valueList=" + valueList; throw new IllegalArgumentException(msg); } final HpInvalidQueryInfo[] invalidQueryInfoAry = new HpInvalidQueryInfo[keyList.size()]; int index = 0; for (ConditionKey key : keyList) { final Object value = valueList.get(index); invalidQueryInfoAry[index] = xcreateInvalidQueryInfo(key, value, columnDbName); ++index; } xdoHandleInvalidQuery(columnDbName, invalidQueryInfoAry); } protected void xdoHandleInvalidQuery(String columnDbName, HpInvalidQueryInfo... invalidQueryInfoAry) { if (xgetSqlClause().isNullOrEmptyQueryChecked()) { throwInvalidQueryRegisteredException(invalidQueryInfoAry); } else { for (HpInvalidQueryInfo invalidQueryInfo : invalidQueryInfoAry) { xgetSqlClause().saveInvalidQuery(invalidQueryInfo); } } } protected HpInvalidQueryInfo xcreateInvalidQueryInfo(ConditionKey key, Object value, String columnDbName) { final String locationBase = xgetLocationBase(); final ColumnInfo targetColumn = xgetLocalDBMeta().findColumnInfo(columnDbName); final HpInvalidQueryInfo invalidQueryInfo = new HpInvalidQueryInfo(locationBase, targetColumn, key, value); if (_inline) { invalidQueryInfo.inlineView(); } else if (_onClause) { invalidQueryInfo.onClause(); } return invalidQueryInfo; } protected QueryModeProvider xcreateQueryModeProvider() { return new QueryModeProvider() { public boolean isOrScopeQuery() { return xgetSqlClause().isOrScopeQueryEffective(); } public boolean isInline() { return _inline; } public boolean isOnClause() { return _onClause; } }; } protected void throwQueryAlreadyRegisteredException(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName) { createCBExThrower().throwQueryAlreadyRegisteredException(key, value, cvalue, columnDbName); } protected void throwInvalidQueryRegisteredException(HpInvalidQueryInfo... invalidQueryInfoAry) { createCBExThrower().throwInvalidQueryRegisteredException(invalidQueryInfoAry); } // =================================================================================== // LikeSearch Query // ================ protected void regLSQ(ConditionKey key, String value, ConditionValue cvalue, String columnDbName, LikeSearchOption option) { registerLikeSearchQuery(key, value, cvalue, columnDbName, option); } protected void registerLikeSearchQuery(ConditionKey key, String value, ConditionValue cvalue, String columnDbName, LikeSearchOption option) { if (option == null) { throwLikeSearchOptionNotFoundException(columnDbName, value); return; // unreachable } if (!prepareQueryChecked(key, value, cvalue, columnDbName).newClause()) { return; } if (xsuppressEscape()) { option.notEscape(); } // basically for DBMS that has original wild-cards xgetSqlClause().adjustLikeSearchDBWay(option); if (value == null || !option.isSplit()) { if (option.canOptimizeCompoundColumnLikePrefix()) { // - - - - - - - - - - // optimized compound // - - - - - - - - - - doRegisterLikeSearchQueryCompoundOptimized(value, cvalue, columnDbName, option); } else { // - - - - - - - - - - - - - // normal or normal compound // - - - - - - - - - - - - - setupConditionValueAndRegisterWhereClause(key, value, cvalue, columnDbName, option); } return; } // - - - - - - - // splitByXxx() // - - - - - - - doRegisterLikeSearchQuerySplitBy(key, value, cvalue, columnDbName, option); } protected void doRegisterLikeSearchQueryCompoundOptimized(String value, ConditionValue cvalue, String columnDbName, LikeSearchOption option) { if (!option.isLikePrefix()) { String msg = "This optimization is only for LikePrefix: " + option; throw new IllegalStateException(msg); } // *char type only but no checked (cannot check) final List compoundColumnList = option.getCompoundColumnList(); final List sizeList = option.getCompoundColumnSizeList(); String currentValue = value; int currentLength = value.length(); String currentColumn = columnDbName; final boolean needsAndPart = isOrScopeQueryDirectlyUnder(); if (needsAndPart) { xgetSqlClause().beginOrScopeQueryAndPart(); } try { boolean shortLengthBreak = false; final Iterator compoundColumnIterator = compoundColumnList.iterator(); for (Integer columnSize : sizeList) { // should be less or equal column count (checked in option) if (currentLength >= columnSize) { // can treat current condition as equal final String equalValue = currentValue.substring(0, columnSize); invokeQueryEqual(currentColumn, equalValue); currentValue = currentValue.substring(columnSize); currentLength = currentValue.length(); final SpecifiedColumn specifiedColumn; if (compoundColumnIterator.hasNext()) { specifiedColumn = compoundColumnIterator.next(); currentColumn = specifiedColumn.getColumnDbName(); } else { // means just size currentColumn = null; // means end break; // though basically no need to break because of size loop end } } else { // short length condition value shortLengthBreak = true; break; } } if (currentValue.length() > 0 && currentColumn != null) { // double check final LikeSearchOption copyOption = option.createDeepCopy(); copyOption.clearCompoundColumn(); // also fixed sizes cleared if (!shortLengthBreak) { while (compoundColumnIterator.hasNext()) { copyOption.addCompoundColumn(compoundColumnIterator.next()); } } invokeQueryLikeSearch(currentColumn, currentValue, copyOption); } } finally { if (needsAndPart) { xgetSqlClause().endOrScopeQueryAndPart(); } } } protected void doRegisterLikeSearchQuerySplitBy(ConditionKey key, String value, ConditionValue cvalue, String columnDbName, LikeSearchOption option) { assertObjectNotNull("option(LikeSearchOption)", option); // these values should be valid only (already filtered before) // and invalid values are ignored even at the check mode // but if all elements are invalid, it is an exception final String[] strArray = option.generateSplitValueArray(value); if (strArray.length == 0) { handleInvalidQuery(key, value, cvalue, columnDbName); return; } if (!option.isAsOrSplit()) { // as 'and' condition final boolean needsAndPart = isOrScopeQueryDirectlyUnder(); if (needsAndPart) { xgetSqlClause().beginOrScopeQueryAndPart(); } try { for (int i = 0; i < strArray.length; i++) { final String currentValue = strArray[i]; setupConditionValueAndRegisterWhereClause(key, currentValue, cvalue, columnDbName, option); } } finally { if (needsAndPart) { xgetSqlClause().endOrScopeQueryAndPart(); } } } else { // as 'or' condition if (isOrScopeQueryAndPartEffective()) { // limit because of so complex String msg = "The AsOrSplit in and-part is unsupported: " + asTableDbName(); throw new OrScopeQueryAndPartUnsupportedOperationException(msg); } final boolean needsNewOrScope = !isOrScopeQueryEffective(); if (needsNewOrScope) { xgetSqlClause().beginOrScopeQuery(); } try { for (int i = 0; i < strArray.length; i++) { final String currentValue = strArray[i]; if (i == 0) { setupConditionValueAndRegisterWhereClause(key, currentValue, cvalue, columnDbName, option); } else { invokeQueryLikeSearch(columnDbName, currentValue, option); } } } finally { if (needsNewOrScope) { xgetSqlClause().endOrScopeQuery(); } } } } protected void throwLikeSearchOptionNotFoundException(String columnDbName, String value) { final DBMeta dbmeta = xgetDBMetaProvider().provideDBMeta(asTableDbName()); createCBExThrower().throwLikeSearchOptionNotFoundException(columnDbName, value, dbmeta); } protected boolean xsuppressEscape() { // for override return false; // as default } protected void invokeQueryLikeSearch(String columnFlexibleName, Object value, LikeSearchOption option) { invokeQuery(columnFlexibleName, "likeSearch", value, option); } protected boolean isOrScopeQueryDirectlyUnder() { final boolean orScopeQuery = isOrScopeQueryEffective(); final boolean orScopeQueryAndPart = isOrScopeQueryAndPartEffective(); return orScopeQuery && !orScopeQueryAndPart; } protected boolean isOrScopeQueryEffective() { return xgetSqlClause().isOrScopeQueryEffective(); } protected boolean isOrScopeQueryAndPartEffective() { return xgetSqlClause().isOrScopeQueryAndPartEffective(); } // =================================================================================== // FromTo Query // ============ protected void regFTQ(Date fromDate, Date toDate, ConditionValue cvalue, String columnDbName, FromToOption option) { assertObjectNotNull("option(FromToOption)", option); filterFromToOption(columnDbName, option); // for fixed option // this FromTo process is very similar to RangeOf process final Date filteredFromDate = option.filterFromDate(fromDate); final ConditionKey fromKey = option.getFromDateConditionKey(); final ConditionKeyPrepareResult fromResult = prepareQueryNoCheck(fromKey, filteredFromDate, cvalue, columnDbName); final Date filteredToDate = option.filterToDate(toDate); final ConditionKey toKey = option.getToDateConditionKey(); final ConditionKeyPrepareResult toResult = prepareQueryNoCheck(toKey, filteredToDate, cvalue, columnDbName); final boolean needsAndPart = isOrScopeQueryDirectlyUnder() && fromResult.newClause() && toResult.newClause(); if (needsAndPart) { xgetSqlClause().beginOrScopeQueryAndPart(); } try { if (fromResult.newClause()) { final Object registered = filterFromToRegisteredDate(option, filteredFromDate, columnDbName); setupConditionValueAndRegisterWhereClause(fromKey, registered, cvalue, columnDbName); } if (toResult.newClause()) { final Object registered = filterFromToRegisteredDate(option, filteredToDate, columnDbName); setupConditionValueAndRegisterWhereClause(toKey, registered, cvalue, columnDbName); } if (fromResult.invalid() && toResult.invalid()) { xhandleFromToBothSideInvalidQuery(fromDate, toDate, columnDbName, option, fromKey, toKey); } else if (fromResult.invalid() || toResult.invalid()) { xhandleFromToOneSideInvalidQuery(fromDate, toDate, columnDbName, option, fromKey, toKey); } } finally { if (needsAndPart) { xgetSqlClause().endOrScopeQueryAndPart(); } } } protected void filterFromToOption(String columnDbName, FromToOption option) { // do nothing as default, basically for option default } protected void xhandleFromToOneSideInvalidQuery(Date fromDate, Date toDate, String columnDbName, FromToOption option, ConditionKey fromKey, ConditionKey toKey) { if (!option.isOneSideAllowed()) { // not allowed (if both required) xdoHandleFromToInvalidQuery(fromDate, toDate, columnDbName, option, fromKey, toKey); } } protected void xhandleFromToBothSideInvalidQuery(Date fromDate, Date toDate, String columnDbName, FromToOption option, ConditionKey fromKey, ConditionKey toKey) { xdoHandleFromToInvalidQuery(fromDate, toDate, columnDbName, option, fromKey, toKey); } protected void xdoHandleFromToInvalidQuery(Date fromDate, Date toDate, String columnDbName, FromToOption option, ConditionKey fromKey, ConditionKey toKey) { final List keyList = newArrayList(fromKey, toKey); final List valueList = newArrayList(fromDate, toDate); handleInvalidQueryList(keyList, valueList, columnDbName); } // ----------------------------------------------------- // from LocalDate // -------------- // for conversion protected Date xfFTHD(Object date, String columnDbName, FromToOption option) { // filterFromToHandlingDate() final ColumnInfo columnInfo = xgetLocalDBMeta().findColumnInfo(columnDbName); if (xisNextTimeLocalDate(columnInfo.getObjectNativeType())) { return xtoFromToUtilDate(date, columnDbName, option); } else if (xisNextTimeLocalDateTime(columnInfo.getObjectNativeType())) { return xtoFromToTimestamp(date, columnDbName, option); } return xtoFromToUtilDate(date, columnDbName, option); // basically no way (generator controls it) } protected Date xtoFromToUtilDate(Object date, String columnDbName, FromToOption option) { final TimeZone realZone = xchooseFromToRealTimeZone(columnDbName, option); return DfTypeUtil.toDate(date, realZone); } protected Timestamp xtoFromToTimestamp(Object date, String columnDbName, FromToOption option) { final TimeZone realZone = xchooseFromToRealTimeZone(columnDbName, option); return DfTypeUtil.toTimestamp(date, realZone); } // ----------------------------------------------------- // to LocalDate // ------------ protected Object filterFromToRegisteredDate(FromToOption option, Date date, String columnDbName) { final ColumnInfo columnInfo = xgetLocalDBMeta().findColumnInfo(columnDbName); if (xisNextTimeLocalDate(columnInfo.getObjectNativeType())) { return xtoFromToLocalDate(date, columnDbName, option); } else if (xisNextTimeLocalDateTime(columnInfo.getObjectNativeType())) { return xtoFromToLocalDateTime(date, columnDbName, option); } return date; } protected Object xtoFromToLocalDate(Object date, String columnDbName, FromToOption option) { // #date_parade final TimeZone realZone = xchooseFromToRealTimeZone(columnDbName, option); return DfTypeUtil.toLocalDate(date, realZone); } protected Object xtoFromToLocalDateTime(Object date, String columnDbName, FromToOption option) { final TimeZone realZone = xchooseFromToRealTimeZone(columnDbName, option); return DfTypeUtil.toLocalDateTime(date, realZone); } // ----------------------------------------------------- // LocalDate Assist // ---------------- protected boolean xisNextTimeLocalDate(Class nativeType) { return LocalDate.class.isAssignableFrom(nativeType); } protected boolean xisNextTimeLocalDateTime(Class nativeType) { return LocalDateTime.class.isAssignableFrom(nativeType); } protected TimeZone xchooseFromToRealTimeZone(String columnDbName, FromToOption option) { final TimeZone opZone = option.getTimeZone(); return opZone != null ? opZone : xgetFromToConversionTimeZone(columnDbName); } protected TimeZone xgetFromToConversionTimeZone(String columnDbName) { return getDBFluteSystemFinalTimeZone(); } // =================================================================================== // RangeOf Query // ============= protected void regROO(Number minNumber, Number maxNumber, ConditionValue cvalue, String columnDbName, RangeOfOption option) { assertObjectNotNull("option(RangeOfOption)", option); if (option.hasCalculationRange()) { final ConditionBean dreamCruiseCB = xgetBaseCB().xcreateDreamCruiseCB(); option.xinitCalculationRange(xgetBaseCB(), dreamCruiseCB); } // this RangeOf process is very similar to FromTo process final ConditionKey minKey = option.getMinNumberConditionKey(); final ConditionKeyPrepareResult minResult = prepareQueryNoCheck(minKey, minNumber, cvalue, columnDbName); final ConditionKey maxKey = option.getMaxNumberConditionKey(); final ConditionKeyPrepareResult maxResult = prepareQueryNoCheck(maxKey, maxNumber, cvalue, columnDbName); final boolean needsAndPart = isOrScopeQueryDirectlyUnder() && minResult.newClause() && maxResult.newClause(); if (needsAndPart) { xgetSqlClause().beginOrScopeQueryAndPart(); } try { if (minResult.newClause()) { setupConditionValueAndRegisterWhereClause(minKey, minNumber, cvalue, columnDbName, option); } if (maxResult.newClause()) { setupConditionValueAndRegisterWhereClause(maxKey, maxNumber, cvalue, columnDbName, option); } if (minResult.invalid() && maxResult.invalid()) { xhandleRangeOfBothSideInvalidQuery(minNumber, maxNumber, columnDbName, option, minKey, maxKey); } else if (minResult.invalid() || maxResult.invalid()) { xhandleRangeOfOneSideInvalidQuery(minNumber, maxNumber, columnDbName, option, minKey, maxKey); } } finally { if (needsAndPart) { xgetSqlClause().endOrScopeQueryAndPart(); } } } protected void xhandleRangeOfOneSideInvalidQuery(Number minNumber, Number maxNumber, String columnDbName, RangeOfOption option, ConditionKey fromKey, ConditionKey toKey) { if (!option.isOneSideAllowed()) { // not allowed (if both required) xdoHandleRangeOfInvalidQuery(minNumber, maxNumber, columnDbName, option, fromKey, toKey); } } protected void xhandleRangeOfBothSideInvalidQuery(Number minNumber, Number maxNumber, String columnDbName, RangeOfOption option, ConditionKey fromKey, ConditionKey toKey) { xdoHandleRangeOfInvalidQuery(minNumber, maxNumber, columnDbName, option, fromKey, toKey); } protected void xdoHandleRangeOfInvalidQuery(Number minNumber, Number maxNumber, String columnDbName, RangeOfOption option, ConditionKey fromKey, ConditionKey toKey) { final List keyList = newArrayList(fromKey, toKey); final List valueList = newArrayList(minNumber, maxNumber); handleInvalidQueryList(keyList, valueList, columnDbName); } // =================================================================================== // InScope Query // ============= protected void regINS(ConditionKey key, List value, ConditionValue cvalue, String columnDbName) { if (!prepareQueryChecked(key, value, cvalue, columnDbName).newClause()) { return; } final int inScopeLimit = xgetSqlClause().getInScopeLimit(); if (inScopeLimit > 0 && value.size() > inScopeLimit) { // if the key is for inScope, it should be split as 'or' // (if the key is for notInScope, it should be split as 'and') final boolean orScopeQuery = xgetSqlClause().isOrScopeQueryEffective(); final boolean orScopeQueryAndPart = xgetSqlClause().isOrScopeQueryAndPartEffective(); final boolean needsAndPart = orScopeQuery && !orScopeQueryAndPart; if (isConditionKeyInScope(key)) { // if or-scope query has already been effective, create new or-scope xgetSqlClause().beginOrScopeQuery(); } else { if (needsAndPart) { xgetSqlClause().beginOrScopeQueryAndPart(); } } try { // split the condition @SuppressWarnings("unchecked") final List objectList = (List) value; final List> valueList = DfCollectionUtil.splitByLimit(objectList, inScopeLimit); for (int i = 0; i < valueList.size(); i++) { final List currentValue = valueList.get(i); if (i == 0) { setupConditionValueAndRegisterWhereClause(key, currentValue, cvalue, columnDbName); } else { invokeQuery(columnDbName, key.getConditionKey(), currentValue); } } } finally { if (isConditionKeyInScope(key)) { xgetSqlClause().endOrScopeQuery(); } else { if (needsAndPart) { xgetSqlClause().endOrScopeQueryAndPart(); } } } } else { setupConditionValueAndRegisterWhereClause(key, value, cvalue, columnDbName); } } static boolean isConditionKeyInScope(ConditionKey key) { // default scope for test return ConditionKeyInScope.class.isAssignableFrom(key.getClass()); } // =================================================================================== // In-line Query // ============= protected void regIQ(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName) { doRegIQ(key, value, cvalue, columnDbName, null); } protected void regIQ(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName, ConditionOption option) { doRegIQ(key, value, cvalue, columnDbName, option); } protected void doRegIQ(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName, ConditionOption option) { if (!prepareQueryChecked(key, value, cvalue, columnDbName).newClause()) { return; } final DBMeta dbmeta = xgetDBMetaProvider().provideDBMetaChecked(asTableDbName()); final ColumnInfo columnInfo = dbmeta.findColumnInfo(columnDbName); final String propertyName = columnInfo.getPropertyName(); final String uncapPropName = initUncap(propertyName); // If Java, it is necessary to use uncapPropName! final String location = xgetLocation(uncapPropName); key.setupConditionValue(xcreateQueryModeProvider(), cvalue, value, location, option); final ColumnSqlName columnSqlName = columnInfo.getColumnSqlName(); final ColumnFunctionCipher cipher = xgetSqlClause().findColumnFunctionCipher(columnInfo); if (isBaseQuery()) { xgetSqlClause().registerBaseTableInlineWhereClause(columnSqlName, key, cvalue, cipher, option); } else { final String aliasName = xgetAliasName(); xgetSqlClause().registerOuterJoinInlineWhereClause(aliasName, columnSqlName, key, cvalue, cipher, option, _onClause); } } // =================================================================================== // ExistsReferrer // ============== protected void registerExistsReferrer(ConditionQuery subQuery, String columnDbName, String relatedColumnDbName, String propertyName, String referrerPropertyName) { registerExistsReferrer(subQuery, columnDbName, relatedColumnDbName, propertyName, referrerPropertyName, false); } protected void registerNotExistsReferrer(ConditionQuery subQuery, String columnDbName, String relatedColumnDbName, String propertyName, String referrerPropertyName) { registerExistsReferrer(subQuery, columnDbName, relatedColumnDbName, propertyName, referrerPropertyName, true); } protected void registerExistsReferrer(final ConditionQuery subQuery, String columnDbName, String relatedColumnDbName, String propertyName, String referrerPropertyName, boolean notExists) { assertSubQueryNotNull("ExistsReferrer", relatedColumnDbName, subQuery); if (subQuery.xgetSqlClause().isUseInScopeSubQueryForExistsReferrer()) { registerInScopeRelation(subQuery, columnDbName, relatedColumnDbName, propertyName, referrerPropertyName, notExists); return; } final SubQueryPath subQueryPath = new SubQueryPath(xgetLocation(propertyName)); final GeneralColumnRealNameProvider localRealNameProvider = new GeneralColumnRealNameProvider(); final int subQueryLevel = subQuery.xgetSqlClause().getSubQueryLevel(); final SqlClause subQueryClause = subQuery.xgetSqlClause(); final String subQueryIdentity = propertyName + "[" + subQueryLevel + "]"; final ColumnSqlNameProvider subQuerySqlNameProvider = dbName -> subQuery.toColumnSqlName(dbName); final DBMeta subQueryDBMeta = findDBMeta(subQuery.asTableDbName()); final GearedCipherManager cipherManager = xgetSqlClause().getGearedCipherManager(); final ExistsReferrer existsReferrer = new ExistsReferrer(subQueryPath, localRealNameProvider, subQuerySqlNameProvider, subQueryLevel, subQueryClause, subQueryIdentity, subQueryDBMeta, cipherManager); final String correlatedFixedCondition = xbuildReferrerCorrelatedFixedCondition(subQuery, referrerPropertyName); final String existsOption = notExists ? "not" : null; final String clause = existsReferrer.buildExistsReferrer(columnDbName, relatedColumnDbName, correlatedFixedCondition, existsOption); // /= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // Exists -> possible to be inner // NotExists -> no way to be inner // // for example, the following SQL is no way to be inner // (suppose if PURCHASE refers WITHDRAWAL) // // select mb.MEMBER_ID, mb.MEMBER_NAME // , mb.MEMBER_STATUS_CODE, wd.MEMBER_ID as WD_MEMBER_ID // from MEMBER mb // left outer join MEMBER_WITHDRAWAL wd on mb.MEMBER_ID = wd.MEMBER_ID // where not exists (select pc.PURCHASE_ID // from PURCHASE pc // where pc.MEMBER_ID = wd.MEMBER_ID // ) // order by mb.MEMBER_ID // = = = = = = = = = =/ final boolean noWayInner = notExists; // but 'exists' allowed registerWhereClause(clause, noWayInner); } protected String xbuildReferrerCorrelatedFixedCondition(ConditionQuery subQuery, String referrerPropertyName) { if (referrerPropertyName == null) { return null; } final DBMeta localDBMeta = xgetLocalDBMeta(); if (!localDBMeta.hasReferrer(referrerPropertyName)) { // one-to-one referrer return null; } final ReferrerInfo referrerInfo = localDBMeta.findReferrerInfo(referrerPropertyName); return xdoBuildReferrerCorrelatedFixedCondition(subQuery, referrerInfo); } protected String xdoBuildReferrerCorrelatedFixedCondition(ConditionQuery subQuery, ReferrerInfo referrerInfo) { final RelationInfo reverseRelation = referrerInfo.getReverseRelation(); if (reverseRelation == null) { return null; } if (!(reverseRelation instanceof ForeignInfo)) { String msg = "The reverse relation (referrer's reverse) should be foreign info: " + referrerInfo; throw new IllegalStateException(msg); } final ForeignInfo foreignInfo = (ForeignInfo) reverseRelation; final String fixedCondition = foreignInfo.getFixedCondition(); if (fixedCondition == null || fixedCondition.trim().length() == 0) { return null; } final FixedConditionResolver resolver = createReferrerFixedConditionResolver(subQuery); return resolver.resolveVariable(fixedCondition, false); } protected FixedConditionResolver createReferrerFixedConditionResolver(ConditionQuery referrerCQ) { return newFixedConditionResolver(referrerCQ, this, xgetDBMetaProvider()); } // *unsupported ExistsReferrer as in-line because it's (or was) so dangerous // =================================================================================== // InScopeRelation // =============== // {Modified at DBFlute-0.7.5} protected void registerInScopeRelation(final ConditionQuery subQuery, String columnDbName, String relatedColumnDbName, String propertyName, String relationPropertyName, boolean notInScope) { assertSubQueryNotNull("InScopeRelation", columnDbName, subQuery); final SubQueryPath subQueryPath = new SubQueryPath(xgetLocation(propertyName)); final GeneralColumnRealNameProvider localRealNameProvider = new GeneralColumnRealNameProvider(); final int subQueryLevel = subQuery.xgetSqlClause().getSubQueryLevel(); final SqlClause subQueryClause = subQuery.xgetSqlClause(); final String subQueryIdentity = propertyName + "[" + subQueryLevel + "]"; final ColumnSqlNameProvider subQuerySqlNameProvider = dbName -> subQuery.toColumnSqlName(dbName); final DBMeta subQueryDBMeta = findDBMeta(subQuery.asTableDbName()); final GearedCipherManager cipherManager = xgetSqlClause().getGearedCipherManager(); final boolean suppressLocalAliasName = isInScopeRelationSuppressLocalAliasName(); final InScopeRelation inScopeRelation = new InScopeRelation(subQueryPath, localRealNameProvider, subQuerySqlNameProvider, subQueryLevel, subQueryClause, subQueryIdentity, subQueryDBMeta, cipherManager, suppressLocalAliasName); final String correlatedFixedCondition = xbuildForeignCorrelatedFixedCondition(subQuery, relationPropertyName); final String inScopeOption = notInScope ? "not" : null; final String clause = inScopeRelation.buildInScopeRelation(columnDbName, relatedColumnDbName, correlatedFixedCondition, inScopeOption); registerWhereClause(clause); } protected boolean isInScopeRelationSuppressLocalAliasName() { // no alias name at InlineView return false; // as default } protected String xbuildForeignCorrelatedFixedCondition(ConditionQuery subQuery, String relationPropertyName) { if (relationPropertyName == null) { return null; } final DBMeta localDBMeta = xgetLocalDBMeta(); final RelationInfo relationInfo = localDBMeta.findRelationInfo(relationPropertyName); if (!relationInfo.isReferrer()) { return null; } if (!(relationInfo instanceof ReferrerInfo)) { return null; } final ReferrerInfo referrerInfo = (ReferrerInfo) relationInfo; return xdoBuildReferrerCorrelatedFixedCondition(subQuery, referrerInfo); } // [DBFlute-0.7.4] // =================================================================================== // (Specify)DerivedReferrer // ======================== protected void registerSpecifyDerivedReferrer(String function, ConditionQuery subQuery, String columnDbName, String relatedColumnDbName, String propertyName, String referrerPropertyName, String aliasName, DerivedReferrerOption option) { final DerivedReferrerOption realOp = option != null ? option : newDefaultDerivedReferrerOption(); doRegisterSpecifyDerivedReferrer(function, subQuery, columnDbName, relatedColumnDbName, propertyName, referrerPropertyName, aliasName, realOp); } protected void doRegisterSpecifyDerivedReferrer(String function, final ConditionQuery subQuery, String columnDbName, String relatedColumnDbName, String propertyName, String referrerPropertyName, String aliasName, DerivedReferrerOption option) { assertFunctionNotNull("SpecifyDerivedReferrer", columnDbName, function); assertSubQueryNotNull("SpecifyDerivedReferrer", columnDbName, subQuery); option.xacceptBaseCB(xgetBaseCB()); if (isDerivedReferrerSelectAllPossible(subQuery, option)) { createCBExThrower().throwSpecifyDerivedReferrerSelectAllPossibleException(function, subQuery, aliasName); } final SubQueryPath subQueryPath = new SubQueryPath(xgetLocation(propertyName)); final GeneralColumnRealNameProvider localRealNameProvider = new GeneralColumnRealNameProvider(); final int subQueryLevel = subQuery.xgetSqlClause().getSubQueryLevel(); final SqlClause subQueryClause = subQuery.xgetSqlClause(); final String subQueryIdentity = propertyName + "[" + subQueryLevel + "]"; final ColumnSqlNameProvider subQuerySqlNameProvider = dbName -> subQuery.toColumnSqlName(dbName); final DBMeta subQueryDBMeta = findDBMeta(subQuery.asTableDbName()); final GearedCipherManager cipherManager = xgetSqlClause().getGearedCipherManager(); final String mainSubQueryIdentity = propertyName + "[" + subQueryLevel + ":subquerymain]"; final SpecifyDerivedReferrer derivedReferrer = option.createSpecifyDerivedReferrer(subQueryPath, localRealNameProvider, subQuerySqlNameProvider, subQueryLevel, subQueryClause, subQueryIdentity, subQueryDBMeta, cipherManager, mainSubQueryIdentity, aliasName); xregisterParameterOption(option); final String correlatedFixedCondition = xbuildReferrerCorrelatedFixedCondition(subQuery, referrerPropertyName); final String clause = derivedReferrer.buildDerivedReferrer(function, columnDbName, relatedColumnDbName, correlatedFixedCondition, option); final HpDerivingSubQueryInfo subQueryInfo = xcreateDerivingSubQueryInfo(function, aliasName, clause, derivedReferrer); xgetSqlClause().specifyDerivingSubQuery(subQueryInfo); } protected boolean isDerivedReferrerSelectAllPossible(final ConditionQuery subQuery, DerivedReferrerOption option) { return option.isSuppressCorrelation() && subQuery.xgetBaseCB().hasSelectAllPossible(); } protected HpDerivingSubQueryInfo xcreateDerivingSubQueryInfo(String function, String aliasName, String clause, SpecifyDerivedReferrer derivedReferrer) { return new HpDerivingSubQueryInfo(function, aliasName, clause, derivedReferrer); } protected DerivedReferrerOption newDefaultDerivedReferrerOption() { return new DerivedReferrerOption(); // both Specify and Query } // ----------------------------------------------------- // (Query)MyselfDerived // -------------------- protected void registerSpecifyMyselfDerived(String function, ConditionQuery subQuery, String columnDbName, String relatedColumnDbName, String propertyName, String referrerPropertyName, String aliasName, DerivedReferrerOption option) { doRegisterSpecifyDerivedReferrer(function, subQuery, columnDbName, relatedColumnDbName, propertyName, referrerPropertyName, aliasName, resolveMyselfDerivedReferrerOption(option)); } protected DerivedReferrerOption resolveMyselfDerivedReferrerOption(DerivedReferrerOption option) { final DerivedReferrerOption resolvedOption = option != null ? option : newDefaultDerivedReferrerOption(); resolvedOption.suppressCorrelation(); return resolvedOption; } // [DBFlute-0.8.8.1] // =================================================================================== // (Query)DerivedReferrer // ====================== protected void registerQueryDerivedReferrer(String function, ConditionQuery subQuery, String columnDbName, String relatedColumnDbName, String propertyName, String referrerPropertyName, String operand, Object value, String parameterPropertyName, DerivedReferrerOption option) { final DerivedReferrerOption realOp = option != null ? option : newDefaultDerivedReferrerOption(); doRegisterQueryDerivedReferrer(function, subQuery, columnDbName, relatedColumnDbName, propertyName, referrerPropertyName, operand, value, parameterPropertyName, realOp); } protected void doRegisterQueryDerivedReferrer(String function, final ConditionQuery subQuery, String columnDbName, String relatedColumnDbName, String propertyName, String referrerPropertyName, String operand, Object value, String parameterPropertyName, DerivedReferrerOption option) { assertFunctionNotNull("QueryDerivedReferrer", columnDbName, function); assertSubQueryNotNull("QueryDerivedReferrer", columnDbName, subQuery); option.xacceptBaseCB(xgetBaseCB()); if (isDerivedReferrerSelectAllPossible(subQuery, option)) { createCBExThrower().throwQueryDerivedReferrerSelectAllPossibleException(function, subQuery); } final SubQueryPath subQueryPath = new SubQueryPath(xgetLocation(propertyName)); final GeneralColumnRealNameProvider localRealNameProvider = new GeneralColumnRealNameProvider(); final int subQueryLevel = subQuery.xgetSqlClause().getSubQueryLevel(); final SqlClause subQueryClause = subQuery.xgetSqlClause(); final String subQueryIdentity = propertyName + "[" + subQueryLevel + "]"; final ColumnSqlNameProvider subQuerySqlNameProvider = dbName -> subQuery.toColumnSqlName(dbName); final DBMeta subQueryDBMeta = findDBMeta(subQuery.asTableDbName()); final GearedCipherManager cipherManager = xgetSqlClause().getGearedCipherManager(); final String mainSubQueryIdentity = propertyName + "[" + subQueryLevel + ":subquerymain]"; final String parameterPath = xgetLocation(parameterPropertyName); final QueryDerivedReferrer derivedReferrer = option.createQueryDerivedReferrer(subQueryPath, localRealNameProvider, subQuerySqlNameProvider, subQueryLevel, subQueryClause, subQueryIdentity, subQueryDBMeta, cipherManager, mainSubQueryIdentity, operand, value, parameterPath); xregisterParameterOption(option); final String correlatedFixedCondition = xbuildReferrerCorrelatedFixedCondition(subQuery, referrerPropertyName); final String clause = derivedReferrer.buildDerivedReferrer(function, columnDbName, relatedColumnDbName, correlatedFixedCondition, option); // /= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // is null or null-revived conversion (coalesce) -> no way to be inner // // for example, the following SQL is no way to be inner // (suppose if PURCHASE refers WITHDRAWAL) // // select mb.MEMBER_ID, mb.MEMBER_NAME // , mb.MEMBER_STATUS_CODE, wd.MEMBER_ID as WD_MEMBER_ID // from MEMBER mb // left outer join MEMBER_WITHDRAWAL wd on mb.MEMBER_ID = wd.MEMBER_ID // where (select max(pc.PURCHASE_PRICE) // from PURCHASE pc // where pc.MEMBER_ID = wd.MEMBER_ID -- may null // ) is null // order by mb.MEMBER_ID // // and using coalesce means it may select records that have null value // so using coalesce is no way in spite of operand // = = = = = = = = = =/ final boolean noWayInner = HpQDRParameter.isOperandIsNull(operand) || option.mayNullRevived(); registerWhereClause(clause, noWayInner); } protected HpQDRFunction xcQDRFunc(HpQDRSetupper setupper) { return new HpQDRFunction(setupper, createQueryDerivedReferrerOptionFactory()); } protected DerivedReferrerOptionFactory createQueryDerivedReferrerOptionFactory() { return new DerivedReferrerOptionFactory() { public DerivedReferrerOption create() { return newQueryDerivedReferrerOption(); } }; } /** * New-create the option of (query) derived-referrer as plain. * @return The new-created option of (query) derived-referrer. (NotNull) */ protected DerivedReferrerOption newQueryDerivedReferrerOption() { return new DerivedReferrerOption(); } // ----------------------------------------------------- // (Query)MyselfDerived // -------------------- protected void registerQueryMyselfDerived(String function, ConditionQuery subQuery, String columnDbName, String relatedColumnDbName, String propertyName, String referrerPropertyName, String operand, Object value, String parameterPropertyName, DerivedReferrerOption option) { doRegisterQueryDerivedReferrer(function, subQuery, columnDbName, relatedColumnDbName, propertyName, referrerPropertyName, operand, value, parameterPropertyName, resolveMyselfDerivedReferrerOption(option)); } // type argument for cast protected HpQDRFunction xcreateQDRFunctionMyselfDerived(Class cbType) { return xcQDRFunc(new HpQDRSetupper() { public void setup(String fn, SubQuery sq, String rd, Object vl, DerivedReferrerOption op) { xqderiveMyselfDerived(fn, sq, rd, vl, op); } }); } protected void xqderiveMyselfDerived(String fn, SubQuery sq, String rd, Object vl, DerivedReferrerOption op) { // overridden by sub-class (not abstract for suppressing option) } // [DBFlute-0.8.8] // =================================================================================== // ScalarCondition // =============== protected void registerScalarCondition(String function, final ConditionQuery subQuery, String propertyName, String operand, final HpSLCCustomized after, ScalarConditionOption option) { final ScalarConditionOption realOp = option != null ? option : newDefaultScalarConditionOption(); doRegisterScalarCondition(function, subQuery, propertyName, operand, after, realOp); } protected void doRegisterScalarCondition(final String function, final ConditionQuery subQuery, String propertyName, String operand, final HpSLCCustomized after, ScalarConditionOption option) { assertSubQueryNotNull("ScalarCondition", propertyName, subQuery); final SubQueryPath subQueryPath = new SubQueryPath(xgetLocation(propertyName)); final GeneralColumnRealNameProvider localRealNameProvider = new GeneralColumnRealNameProvider(); final int subQueryLevel = subQuery.xgetSqlClause().getSubQueryLevel(); final SqlClause subQueryClause = subQuery.xgetSqlClause(); final String subQueryIdentity = propertyName + "[" + subQueryLevel + "]"; final ColumnSqlNameProvider subQuerySqlNameProvider = dbName -> subQuery.toColumnSqlName(dbName); final DBMeta subQueryDBMeta = findDBMeta(subQuery.asTableDbName()); final GearedCipherManager cipherManager = xgetSqlClause().getGearedCipherManager(); final String mainSubQueryIdentity = propertyName + "[" + subQueryLevel + ":subquerymain]"; final PartitionByProvider partitionByProvider = () -> after.preparePartitionBySqlClause(); final ScalarCondition scalarCondition = new ScalarCondition(subQueryPath, localRealNameProvider, subQuerySqlNameProvider, subQueryLevel, subQueryClause, subQueryIdentity, subQueryDBMeta, cipherManager, mainSubQueryIdentity, operand, partitionByProvider); xregisterParameterOption(option); final QueryClause clause = new QueryClause() { /* lazy registration to use partition-by */ public String toString() { return scalarCondition.buildScalarCondition(function, option); } }; // no speak about inner-join because of no possible of null revival final QueryUsedAliasInfo usedAliasInfo = new QueryUsedAliasInfo(xgetAliasName(), null); registerWhereClause(clause, usedAliasInfo); } protected HpSLCFunction xcreateSLCFunction(ConditionKey ckey, Class tp) { // type for cast return xcreateSLCFunction(ckey.getOperand(), tp); // delegate to string operand, also for compatible } protected HpSLCFunction xcreateSLCFunction(final String rd, Class tp) { return new HpSLCFunction((fn, sq, cs, op) -> { xscalarCondition(fn, sq, rd, cs, op); }); } protected void xscalarCondition(String fn, SubQuery sq, String rd, HpSLCCustomized cs, ScalarConditionOption op) { // overridden by sub-class (not abstract for suppressing option) } protected ScalarConditionOption newDefaultScalarConditionOption() { return new ScalarConditionOption(); } // =================================================================================== // MyselfExists // ============ protected void registerMyselfExists(ConditionQuery subQuery, String subQueryPropertyName) { if (subQuery.xgetSqlClause().isUseInScopeSubQueryForExistsReferrer()) { registerMyselfInScope(subQuery, subQueryPropertyName); return; } final String relatedColumnDbName; { subQuery.xgetSqlClause().getSpecifiedColumnInfoAsOne(); final String specifiedDbName = subQuery.xgetSqlClause().getSpecifiedColumnDbNameAsOne(); if (specifiedDbName != null) { relatedColumnDbName = specifiedDbName; } else { // as default // this function is only allowed when only-one PK final PrimaryInfo primaryInfo = findDBMeta(subQuery.asTableDbName()).getPrimaryInfo(); final ColumnInfo primaryColumnInfo = primaryInfo.getFirstColumn(); relatedColumnDbName = primaryColumnInfo.getColumnDbName(); } } registerExistsReferrer(subQuery, relatedColumnDbName, relatedColumnDbName, subQueryPropertyName, null); } // =================================================================================== // MyselfInScope // ============= protected void registerMyselfInScope(ConditionQuery subQuery, String subQueryPropertyName) { final String relatedColumnDbName; { final String specifiedDbName = subQuery.xgetSqlClause().getSpecifiedColumnDbNameAsOne(); if (specifiedDbName != null) { relatedColumnDbName = specifiedDbName; } else { // as default // this function is only allowed when only-one PK final PrimaryInfo primaryInfo = findDBMeta(subQuery.asTableDbName()).getPrimaryInfo(); final ColumnInfo primaryColumnInfo = primaryInfo.getFirstColumn(); relatedColumnDbName = primaryColumnInfo.getColumnDbName(); } } registerInScopeRelation(subQuery, relatedColumnDbName, relatedColumnDbName, subQueryPropertyName, null, false); } // =================================================================================== // SubQuery Common // =============== protected class GeneralColumnRealNameProvider implements ColumnRealNameProvider { public ColumnRealName provide(String columnDbName) { return toColumnRealName(columnDbName); } } // these assertions are basically for internal protected void assertSubQueryNotNull(String title, String columnDbName, ConditionQuery subQuery) { if (subQuery == null) { String msg = "The condition-query for the sub-query should not be null:"; msg = msg + " " + title + "(" + columnDbName + ")"; throw new IllegalStateException(msg); } } protected void assertFunctionNotNull(String title, String columnDbName, String function) { if (function == null) { String msg = "The function for the sub-query should not be null:"; msg = msg + " " + title + "(" + columnDbName + ")"; throw new IllegalStateException(msg); } } // =================================================================================== // Where Clause // ============ protected void setupConditionValueAndRegisterWhereClause(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName) { final ConditionOption embeddedOption = createEmbeddedOption(key, value, cvalue, columnDbName); setupConditionValueAndRegisterWhereClause(key, value, cvalue, columnDbName, embeddedOption); } protected ConditionOption createEmbeddedOption(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName) { // to override (closet option) return null; } protected void setupConditionValueAndRegisterWhereClause(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName, ConditionOption option) { final DBMeta dbmeta = xgetLocalDBMeta(); final ColumnInfo columnInfo = dbmeta.findColumnInfo(columnDbName); final QueryModeProvider queryModeProvider = xcreateQueryModeProvider(); final Object filtered = filterConditionValueIfNeeds(key, value, cvalue, columnDbName, option, columnInfo); final String propertyName = columnInfo.getPropertyName(); final String uncapPropName = initUncap(propertyName); final String location = xgetLocation(uncapPropName); // if Java, it is necessary to use uncapPropName key.setupConditionValue(queryModeProvider, cvalue, filtered, location, option); final ColumnRealName columnRealName = toColumnRealName(columnDbName); final ColumnFunctionCipher cipher = xgetSqlClause().findColumnFunctionCipher(columnInfo); final String usedAliasName = xgetAliasName(); xgetSqlClause().registerWhereClause(columnRealName, key, cvalue, cipher, option, usedAliasName); } protected Object filterConditionValueIfNeeds(ConditionKey key, Object value, ConditionValue cvalue, String columnDbName, ConditionOption option, ColumnInfo columnInfo) { if (value != null && isDatetimePrecisionTruncationOfConditionEnabled(columnDbName)) { // null check, just in case return new DateConditionAdjuster().truncatePrecisionIfHasTime(columnInfo, value); } else { return value; } } protected boolean isDatetimePrecisionTruncationOfConditionEnabled(String columnDbName) { // may be overridden by option return xgetSqlClause().isDatetimePrecisionTruncationOfConditionEnabled(); } protected void registerWhereClause(String whereClause) { registerWhereClause(whereClause, false); } protected void registerWhereClause(String whereClause, boolean noWayInner) { final String usedAliasName = xgetAliasName(); xgetSqlClause().registerWhereClause(whereClause, usedAliasName, noWayInner); } protected void registerWhereClause(QueryClause whereClause, QueryUsedAliasInfo... usedAliasInfos) { xgetSqlClause().registerWhereClause(whereClause, usedAliasInfos); } protected void registerInlineWhereClause(String whereClause) { if (isBaseQuery()) { xgetSqlClause().registerBaseTableInlineWhereClause(whereClause); } else { xgetSqlClause().registerOuterJoinInlineWhereClause(xgetAliasName(), whereClause, _onClause); } } // =================================================================================== // Union Query // =========== protected void registerUnionQuery(final ConditionQuery unionQuery, boolean unionAll, final String unionQueryPropertyName) { xgetSqlClause().registerUnionQuery(new UnionClauseProvider() { public String provide() { return xgetUnionQuerySql(unionQuery, unionQueryPropertyName); } }, unionAll); } protected String xgetUnionQuerySql(ConditionQuery unionQuery, String unionQueryPropertyName) { final String fromClause = unionQuery.xgetSqlClause().getFromClause(); final String whereClause = unionQuery.xgetSqlClause().getWhereClause(); final String unionQueryClause; if (whereClause.trim().length() <= 0) { unionQueryClause = fromClause + " " + xgetSqlClause().getUnionWhereClauseMark(); } else { final int whereIndex = whereClause.indexOf("where "); if (whereIndex < 0) { String msg = "The whereClause should have 'where' string: " + whereClause; throw new IllegalStateException(msg); } final int clauseIndex = whereIndex + "where ".length(); final String front = whereClause.substring(0, clauseIndex); final String mark = xgetSqlClause().getUnionWhereFirstConditionMark(); final String rear = whereClause.substring(clauseIndex); final String markedClause = front + mark + rear; unionQueryClause = fromClause + " " + markedClause; } final String oldStr = "/*pmb.conditionQuery."; final String newStr = "/*pmb.conditionQuery." + unionQueryPropertyName + "."; return replaceString(unionQueryClause, oldStr, newStr); } // =================================================================================== // Inner Join // ========== /** * Change the join type for this relation to inner join.
* This method is for PERFORMANCE TUNING basically. */ public void innerJoin() { if (isBaseQuery()) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("The method 'innerJoin()' should be called for a relation query."); br.addItem("Advice"); br.addElement("Please confirm your program."); br.addElement("For example:"); br.addElement(" (x) - cb.query().innerJoin();"); br.addElement(" (o) - cb.query().queryMemberStatus().innerJoin();"); br.addItem("Base Table"); br.addElement(asTableDbName()); final String msg = br.buildExceptionMessage(); throw new IllegalConditionBeanOperationException(msg); } xgetSqlClause().changeToInnerJoin(xgetAliasName()); } // =================================================================================== // Order By // ======== // ----------------------------------------------------- // Basic // ----- protected void registerOrderBy(String columnDbName, boolean ascOrDesc) { final DBMeta dbmeta = xgetLocalDBMeta(); final ColumnInfo columnInfo = dbmeta.findColumnInfo(columnDbName); final ColumnRealName columnRealName = toColumnRealName(columnInfo); xgetSqlClause().registerOrderBy(columnRealName.toString(), ascOrDesc, columnInfo); } protected void regOBA(String columnDbName) { assertOrderByPurpose(columnDbName); registerOrderBy(columnDbName, true); } protected void regOBD(String columnDbName) { assertOrderByPurpose(columnDbName); registerOrderBy(columnDbName, false); } protected void assertOrderByPurpose(String columnDbName) { if (xgetSqlClause().getPurpose().isNoOrderBy()) { throwOrderByIllegalPurposeException(columnDbName); } } protected void throwOrderByIllegalPurposeException(String columnDbName) { createCBExThrower().throwOrderByIllegalPurposeException(xgetSqlClause().getPurpose(), xgetBaseCB(), asTableDbName(), columnDbName); } // ----------------------------------------------------- // Nulls First/Last // ---------------- /** * Order with the keyword 'nulls first'. *
     * MemberCB cb = new MemberCB();
     * cb.query().addOrderBy_Birthdate_Asc().withNullsFirst();
     * // order by BIRTHDATE asc nulls first
     * 
*/ public void withNullsFirst() { // is user public! xgetSqlClause().addNullsFirstToPreviousOrderBy(); } /** * Order with the keyword 'nulls last'. *
     * MemberCB cb = new MemberCB();
     * cb.query().addOrderBy_Birthdate_Asc().withNullsLast();
     * // order by BIRTHDATE asc nulls last
     * 
*/ public void withNullsLast() { // is user public! xgetSqlClause().addNullsLastToPreviousOrderBy(); } // ----------------------------------------------------- // Manual Order // ------------ protected ManualOrderOption cMOO(ManualOrderOptionCall opCall) { // createManualOrderOption() assertManualOrderOpCallNotNull(opCall); final ManualOrderOption op = newManualOrderOption(); opCall.callback(op); return op; } protected void assertManualOrderOpCallNotNull(ManualOrderOptionCall opCall) { if (opCall == null) { throw new IllegalArgumentException("The argument 'opLambda' should not be null: " + asTableDbName()); } } /** * New-create the option of manual-order as plain. * @return The new-created option of manual-order. (NotNull) */ protected ManualOrderOption newManualOrderOption() { return new ManualOrderOption(); } protected void xdoWithManualOrder(ManualOrderOption mob) { assertObjectNotNull("withManualOrder(mob)", mob); final OrderByElement lastElement = xgetSqlClause().getOrderByLastElement(); xcheckManualOrderState(mob, lastElement); xcheckManualOrderUnique(mob, lastElement); mob.bind((themeKey, orderValue) -> { return xregisterManualOrderParameterToThemeList(themeKey, orderValue); }); if (mob.hasOrderByCalculation()) { final ConditionBean dreamCruiseCB = xgetBaseCB().xcreateDreamCruiseCB(); dreamCruiseCB.overTheWaves(xcreateManualOrderSpecifiedColumn(dreamCruiseCB)); mob.xinitOrderByCalculation(xgetBaseCB(), dreamCruiseCB); } mob.validate(); xgetSqlClause().addManualOrderToPreviousOrderByElement(mob); } protected void xcheckManualOrderState(ManualOrderOption mob, final OrderByElement lastElement) { if (lastElement == null) { createCBExThrower().throwManualOrderNotFoundOrderByException(_baseCB, mob); } } protected void xcheckManualOrderUnique(ManualOrderOption mob, final OrderByElement lastElement) { final List orderByList = xgetSqlClause().getOrderByComponent().getOrderByList(); for (OrderByElement existingOrder : orderByList) { final ManualOrderOption existingMob = existingOrder.getManualOrderOption(); if (existingMob != null && existingMob.equals(mob)) { // the bean already exists createCBExThrower().throwManualOrderSameBeanAlreadyExistsException(_baseCB, existingMob, existingOrder, mob, lastElement); } } } protected SpecifiedColumn xcreateManualOrderSpecifiedColumn(ConditionBean dreamCruiseCB) { final OrderByElement orderByLastElement = xgetSqlClause().getOrderByLastElement(); final String aliasName = orderByLastElement.getAliasName(); final String columnName = orderByLastElement.getColumnName(); final ColumnInfo columnInfo = orderByLastElement.getColumnInfo(); final boolean derived = orderByLastElement.isDerivedOrderBy(); return new SpecifiedColumn(aliasName, columnInfo, dreamCruiseCB, columnName, derived); } // ----------------------------------------------------- // Specified Derived OrderBy // ------------------------- protected void registerSpecifiedDerivedOrderBy_Asc(String aliasName) { if (!xgetSqlClause().hasSpecifiedDerivingSubQuery(aliasName)) { throwSpecifiedDerivedOrderByAliasNameNotFoundException(aliasName); } xgetSqlClause().registerSpecifiedDerivedOrderBy(aliasName, true); } protected void registerSpecifiedDerivedOrderBy_Desc(String aliasName) { if (!xgetSqlClause().hasSpecifiedDerivingSubQuery(aliasName)) { throwSpecifiedDerivedOrderByAliasNameNotFoundException(aliasName); } xgetSqlClause().registerSpecifiedDerivedOrderBy(aliasName, false); } protected void throwSpecifiedDerivedOrderByAliasNameNotFoundException(String aliasName) { createCBExThrower().throwSpecifiedDerivedOrderByAliasNameNotFoundException(aliasName); } // =================================================================================== // Name Resolver // ============= /** * Resolve relation no. * @param localTableName The name of local table. (NotNull) * @param foreignPropertyName The property name of foreign relation. (NotNull) * @return The resolved relation No. */ protected String resolveNextRelationPath(String localTableName, String foreignPropertyName) { final int relationNo = xgetSqlClause().resolveRelationNo(localTableName, foreignPropertyName); String nextRelationPath = SqlClause.RELATION_PATH_DELIMITER + relationNo; final String relationPath = xgetRelationPath(); if (relationPath != null) { nextRelationPath = relationPath + nextRelationPath; } return nextRelationPath; } protected String xresolveNRP(String localTableName, String foreignPropertyName) { // for generated source return resolveNextRelationPath(localTableName, foreignPropertyName); } /** * Resolve alias name for join table. * @param relationPath Relation path. (NotNull) * @param nestLevel The nest No of condition query. * @return The resolved name. (NotNull) */ protected String resolveJoinAliasName(String relationPath, int nestLevel) { return xgetSqlClause().resolveJoinAliasName(relationPath, nestLevel); } protected String xresolveJAN(String relationPath, int nestLevel) { // for generated source return resolveJoinAliasName(relationPath, nestLevel); } // =================================================================================== // Reflection Invoking // =================== /** {@inheritDoc} */ public ConditionValue invokeValue(String columnFlexibleName) { assertStringNotNullAndNotTrimmedEmpty("columnFlexibleName", columnFlexibleName); final DBMeta dbmeta = xgetLocalDBMeta(); final String columnCapPropName = initCap(dbmeta.findColumnInfo(columnFlexibleName).getPropertyName()); final String methodName = "xdfget" + columnCapPropName; final Method method = xhelpGettingCQMethod(this, methodName, (Class[]) null); if (method == null) { throwConditionInvokingGetMethodNotFoundException(columnFlexibleName, methodName); return null; // unreachable } try { return (ConditionValue) xhelpInvokingCQMethod(this, method, (Object[]) null); } catch (ReflectionFailureException e) { throwConditionInvokingGetReflectionFailureException(columnFlexibleName, methodName, e); return null; // unreachable } } protected void throwConditionInvokingGetMethodNotFoundException(String columnFlexibleName, String methodName) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Not found the method for getting the condition."); br.addItem("columnFlexibleName"); br.addElement(columnFlexibleName); br.addItem("methodName"); br.addElement(methodName); final String msg = br.buildExceptionMessage(); throw new ConditionInvokingFailureException(msg); } protected void throwConditionInvokingGetReflectionFailureException(String columnFlexibleName, String methodName, ReflectionFailureException e) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Failed to invoke the method for getting value."); br.addItem("columnFlexibleName"); br.addElement(columnFlexibleName); br.addItem("methodName"); br.addElement(methodName); final String msg = br.buildExceptionMessage(); throw new ConditionInvokingFailureException(msg, e); } /** {@inheritDoc} */ public void invokeQuery(String columnFlexibleName, String conditionKeyName, Object conditionValue) { doInvokeQuery(columnFlexibleName, conditionKeyName, conditionValue, null); } /** {@inheritDoc} */ public void invokeQuery(String columnFlexibleName, String conditionKeyName, Object conditionValue, ConditionOption conditionOption) { assertObjectNotNull("conditionOption", conditionOption); doInvokeQuery(columnFlexibleName, conditionKeyName, conditionValue, conditionOption); } protected void doInvokeQuery(String colName, String ckey, Object value, ConditionOption option) { assertStringNotNullAndNotTrimmedEmpty("columnFlexibleName", colName); assertStringNotNullAndNotTrimmedEmpty("conditionKeyName", ckey); final boolean noArg = Srl.equalsIgnoreCase(ckey, "IsNull", "IsNotNull", "IsNullOrEmpty", "EmptyString"); if (!noArg && (value == null || "".equals(value))) { if (xgetSqlClause().isNullOrEmptyQueryChecked()) { // as default String msg = "The conditionValue is required but null or empty: column=" + colName + " value=" + value; throw new IllegalConditionBeanOperationException(msg); } else { // e.g. when cb.ignoreNullOrEmptyQuery() return; } } final PropertyNameCQContainer container = xhelpExtractingPropertyNameCQContainer(colName); final String flexibleName = container.getFlexibleName(); final ConditionQuery cq = container.getConditionQuery(); final DBMeta dbmeta = findDBMeta(cq.asTableDbName()); final ColumnInfo columnInfo; try { columnInfo = dbmeta.findColumnInfo(flexibleName); } catch (RuntimeException e) { throwConditionInvokingColumnFindFailureException(colName, ckey, value, option, e); return; // unreachable (to avoid compile error) } final String columnCapPropName = initCap(columnInfo.getPropertyName()); final boolean rangeOf = Srl.equalsIgnoreCase(ckey, "RangeOf"); final boolean fromTo = Srl.equalsIgnoreCase(ckey, "FromTo", "DateFromTo"); final boolean inScope = Srl.equalsIgnoreCase(ckey, "InScope"); if (!noArg) { try { value = columnInfo.convertToObjectNativeType(value); // convert type } catch (RuntimeException e) { throwConditionInvokingValueConvertFailureException(colName, ckey, value, option, e); } } final String methodName = xbuildQuerySetMethodName(ckey, columnCapPropName); final List> typeList = newArrayListSized(4); final Class propertyType = columnInfo.getObjectNativeType(); if (fromTo) { if (LocalDate.class.isAssignableFrom(propertyType)) { // #date_parade typeList.add(propertyType); typeList.add(propertyType); } else if (LocalDateTime.class.isAssignableFrom(propertyType)) { typeList.add(propertyType); typeList.add(propertyType); } else { // fixedly util.Date typeList.add(Date.class); typeList.add(Date.class); } } else if (rangeOf) { typeList.add(propertyType); typeList.add(propertyType); } else { if (!noArg) { final Class instanceType = value.getClass(); if (inScope && Collection.class.isAssignableFrom(instanceType)) { // double check just in case typeList.add(Collection.class); // inScope's argument is fixed type } else { typeList.add(instanceType); } } } if (option != null) { typeList.add(option.getClass()); } final List> filteredTypeList = newArrayListSized(typeList.size()); for (Class parameterType : typeList) { filteredTypeList.add(xfilterInvokeQueryParameterType(colName, ckey, parameterType)); } final Class[] parameterTypes = filteredTypeList.toArray(new Class[filteredTypeList.size()]); final Method method = xhelpGettingCQMethod(cq, methodName, parameterTypes); if (method == null) { throwConditionInvokingSetMethodNotFoundException(colName, ckey, value, option, methodName, parameterTypes); } try { final List argList = newArrayList(); if (fromTo || rangeOf) { if (!(value instanceof List)) { // check type throwConditionInvokingDateFromToValueInvalidException(colName, ckey, value, option, methodName, parameterTypes); } argList.addAll((List) value); } else { if (!noArg) { argList.add(value); } } if (option != null) { argList.add(option); } final List filteredArgList = newArrayListSized(argList.size()); for (Object arg : argList) { filteredArgList.add(xfilterInvokeQueryParameterValue(colName, ckey, arg)); } xhelpInvokingCQMethod(cq, method, filteredArgList.toArray()); } catch (ReflectionFailureException e) { throwConditionInvokingSetReflectionFailureException(colName, ckey, value, option, methodName, parameterTypes, e); } } protected String xbuildQuerySetMethodName(String ckey, String columnCapPropName) { return "set" + columnCapPropName + "_" + initCap(ckey); } protected Class xfilterInvokeQueryParameterType(String colName, String ckey, Class parameterType) { return parameterType; // no filter as default (e.g. overridden by Scala to convert to immutable list) } protected Object xfilterInvokeQueryParameterValue(String colName, String ckey, Object parameterValue) { return parameterValue; // no filter as default (e.g. overridden by Scala to convert to immutable list) } protected void throwConditionInvokingColumnFindFailureException(String columnFlexibleName, String conditionKeyName, Object conditionValue, ConditionOption conditionOption, RuntimeException cause) { final String notice = "Failed to find the column in the table."; doThrowConditionInvokingFailureException(notice, columnFlexibleName, conditionKeyName, conditionValue, conditionOption, null, null, cause); } protected void throwConditionInvokingValueConvertFailureException(String columnFlexibleName, String conditionKeyName, Object conditionValue, ConditionOption conditionOption, RuntimeException cause) { final String notice = "Failed to convert the value to property type."; doThrowConditionInvokingFailureException(notice, columnFlexibleName, conditionKeyName, conditionValue, conditionOption, null, null, cause); } protected void throwConditionInvokingSetMethodNotFoundException(String columnFlexibleName, String conditionKeyName, Object conditionValue, ConditionOption conditionOption, String methodName, Class[] parameterTypes) { final String notice = "Not found the method for setting the condition."; doThrowConditionInvokingFailureException(notice, columnFlexibleName, conditionKeyName, conditionValue, conditionOption, methodName, parameterTypes, null); } protected void throwConditionInvokingDateFromToValueInvalidException(String columnFlexibleName, String conditionKeyName, Object conditionValue, ConditionOption conditionOption, String methodName, Class[] parameterTypes) { final String notice = "The conditionValue should be List that has 2 elements, fromDate and toDate."; doThrowConditionInvokingFailureException(notice, columnFlexibleName, conditionKeyName, conditionValue, conditionOption, methodName, parameterTypes, null); } protected void throwConditionInvokingSetReflectionFailureException(String columnFlexibleName, String conditionKeyName, Object conditionValue, ConditionOption conditionOption, String methodName, Class[] parameterTypes, ReflectionFailureException cause) { final String notice = "Failed to invoke the method for setting the condition."; doThrowConditionInvokingFailureException(notice, columnFlexibleName, conditionKeyName, conditionValue, conditionOption, methodName, parameterTypes, cause); } protected void doThrowConditionInvokingFailureException(String notice, String columnFlexibleName, String conditionKeyName, Object conditionValue, ConditionOption conditionOption, String methodName, Class[] parameterTypes, RuntimeException cause) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice(notice); br.addItem("Table"); br.addElement(asTableDbName()); br.addItem("columnFlexibleName"); br.addElement(columnFlexibleName); br.addItem("conditionKeyName"); br.addElement(conditionKeyName); br.addItem("conditionValue"); br.addElement(conditionValue); br.addElement(conditionValue != null ? conditionValue.getClass() : null); br.addItem("conditionOption"); br.addElement(conditionOption); if (methodName != null) { final StringBuilder sb = new StringBuilder(); if (parameterTypes != null) { int index = 0; for (Class parameterType : parameterTypes) { if (index > 0) { sb.append(", "); } sb.append(DfTypeUtil.toClassTitle(parameterType)); ++index; } } br.addItem("Method"); br.addElement(methodName + "(" + sb.toString() + ")"); } final String msg = br.buildExceptionMessage(); if (cause != null) { throw new ConditionInvokingFailureException(msg, cause); } else { throw new ConditionInvokingFailureException(msg); } } /** {@inheritDoc} */ public void invokeQueryEqual(String columnFlexibleName, Object value) { invokeQuery(columnFlexibleName, CK_EQ.getConditionKey(), value); } /** {@inheritDoc} */ public void invokeQueryNotEqual(String columnFlexibleName, Object value) { invokeQuery(columnFlexibleName, CK_NES.getConditionKey(), value); } /** {@inheritDoc} */ public void invokeOrderBy(String columnFlexibleName, boolean isAsc) { assertStringNotNullAndNotTrimmedEmpty("columnFlexibleName", columnFlexibleName); final PropertyNameCQContainer container = xhelpExtractingPropertyNameCQContainer(columnFlexibleName); final String flexibleName = container.getFlexibleName(); final ConditionQuery cq = container.getConditionQuery(); final String ascDesc = isAsc ? "Asc" : "Desc"; final DBMeta dbmeta = findDBMeta(cq.asTableDbName()); final String columnCapPropName = initCap(dbmeta.findColumnInfo(flexibleName).getPropertyName()); final String methodName = "addOrderBy_" + columnCapPropName + "_" + ascDesc; final Method method = xhelpGettingCQMethod(cq, methodName, (Class[]) null); if (method == null) { throwConditionInvokingOrderMethodNotFoundException(columnFlexibleName, isAsc, methodName); } try { xhelpInvokingCQMethod(cq, method, (Object[]) null); } catch (ReflectionFailureException e) { throwConditionInvokingOrderReflectionFailureException(columnFlexibleName, isAsc, methodName, e); } } protected void throwConditionInvokingOrderMethodNotFoundException(String columnFlexibleName, boolean isAsc, String methodName) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Not found the method for adding the order-by condition."); br.addItem("Table"); br.addElement(asTableDbName()); br.addItem("columnFlexibleName"); br.addElement(columnFlexibleName); br.addItem("isAsc"); br.addElement(isAsc); br.addItem("Method"); br.addElement(methodName); final String msg = br.buildExceptionMessage(); throw new ConditionInvokingFailureException(msg); } protected void throwConditionInvokingOrderReflectionFailureException(String columnFlexibleName, boolean isAsc, String methodName, ReflectionFailureException cause) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Failed to invoke the method for setting the order-by condition."); br.addItem("Table"); br.addElement(asTableDbName()); br.addItem("columnFlexibleName"); br.addElement(columnFlexibleName); br.addItem("isAsc"); br.addElement(isAsc); br.addItem("Method"); br.addElement(methodName); final String msg = br.buildExceptionMessage(); throw new ConditionInvokingFailureException(msg, cause); } /** {@inheritDoc} */ public ConditionQuery invokeForeignCQ(String foreignPropertyName) { assertStringNotNullAndNotTrimmedEmpty("foreignPropertyName", foreignPropertyName); final List traceList = Srl.splitList(foreignPropertyName, "."); ConditionQuery foreignCQ = this; for (String trace : traceList) { foreignCQ = doInvokeForeignCQ(foreignCQ, trace); } return foreignCQ; } protected ConditionQuery doInvokeForeignCQ(ConditionQuery cq, String foreignPropertyName) { assertStringNotNullAndNotTrimmedEmpty("foreignPropertyName", foreignPropertyName); final String methodName = "query" + initCap(foreignPropertyName); final Method method = xhelpGettingCQMethod(cq, methodName, (Class[]) null); if (method == null) { throwConditionInvokingForeignQueryMethodNotFoundException(cq, foreignPropertyName, methodName); return null; // unreachable } try { return (ConditionQuery) xhelpInvokingCQMethod(cq, method, (Object[]) null); } catch (ReflectionFailureException e) { throwConditionInvokingForeignQueryReflectionFailureException(cq, foreignPropertyName, methodName, e); return null; // unreachable } } protected void throwConditionInvokingForeignQueryMethodNotFoundException(ConditionQuery cq, String foreignPropertyName, String methodName) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Not found the method for getting a foreign condition query."); br.addItem("Table"); br.addElement(asTableDbName()); br.addItem("foreignPropertyName"); br.addElement(foreignPropertyName); br.addItem("Method"); br.addElement(methodName); final String msg = br.buildExceptionMessage(); throw new ConditionInvokingFailureException(msg); } protected void throwConditionInvokingForeignQueryReflectionFailureException(ConditionQuery cq, String foreignPropertyName, String methodName, ReflectionFailureException cause) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Failed to invoke the method for setting a condition(query)."); br.addItem("Table"); br.addElement(asTableDbName()); br.addItem("foreignPropertyName"); br.addElement(foreignPropertyName); br.addItem("Method"); br.addElement(methodName); final String msg = br.buildExceptionMessage(); throw new ConditionInvokingFailureException(msg, cause); } /** {@inheritDoc} */ public boolean invokeHasForeignCQ(String foreignPropertyName) { assertStringNotNullAndNotTrimmedEmpty("foreignPropertyName", foreignPropertyName); final List traceList = Srl.splitList(foreignPropertyName, "."); ConditionQuery foreignCQ = this; final int splitLength = traceList.size(); int index = 0; for (String traceName : traceList) { if (!doInvokeHasForeignCQ(foreignCQ, traceName)) { return false; } if ((index + 1) < splitLength) { // last loop foreignCQ = foreignCQ.invokeForeignCQ(traceName); } ++index; } return true; } protected boolean doInvokeHasForeignCQ(ConditionQuery cq, String foreignPropertyName) { assertStringNotNullAndNotTrimmedEmpty("foreignPropertyName", foreignPropertyName); final String methodName = "hasConditionQuery" + initCap(foreignPropertyName); final Method method = xhelpGettingCQMethod(cq, methodName, (Class[]) null); if (method == null) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Not found the method for determining a foreign condition query."); br.addItem("Table"); br.addElement(cq.asTableDbName()); br.addItem("foreignPropertyName"); br.addElement(foreignPropertyName); br.addItem("methodName"); br.addElement(methodName); br.addItem("ConditionQuery"); br.addElement(DfTypeUtil.toClassTitle(cq)); final String msg = br.buildExceptionMessage(); throw new ConditionInvokingFailureException(msg); } try { return (Boolean) xhelpInvokingCQMethod(cq, method, (Object[]) null); } catch (ReflectionFailureException e) { String msg = "Failed to invoke the method for determining a condition(query):"; msg = msg + " foreignPropertyName=" + foreignPropertyName; msg = msg + " methodName=" + methodName + " table=" + asTableDbName(); throw new ConditionInvokingFailureException(msg, e); } } protected PropertyNameCQContainer xhelpExtractingPropertyNameCQContainer(String name) { final String[] strings = name.split("\\."); final int length = strings.length; String propertyName = null; ConditionQuery cq = this; int index = 0; for (String element : strings) { if (length == (index + 1)) { // at last loop! propertyName = element; break; } cq = cq.invokeForeignCQ(element); ++index; } return new PropertyNameCQContainer(propertyName, cq); } protected static class PropertyNameCQContainer { protected String _flexibleName; protected ConditionQuery _cq; public PropertyNameCQContainer(String flexibleName, ConditionQuery cq) { this._flexibleName = flexibleName; this._cq = cq; } public String getFlexibleName() { return _flexibleName; } public ConditionQuery getConditionQuery() { return _cq; } } protected Method xhelpGettingCQMethod(ConditionQuery cq, String methodName, Class[] argTypes) { final Class cqType = cq.getClass(); final DfBeanDesc beanDesc = DfBeanDescFactory.getBeanDesc(cqType); final Method found = beanDesc.getMethodNoException(methodName, argTypes); if (found != null) { return found; } // non-cache #for_now e.g. native method of classification or protected option method // (but cache of Class.class can be available) return DfReflectionUtil.getWholeMethod(cqType, methodName, argTypes); } protected Object xhelpInvokingCQMethod(ConditionQuery cq, Method method, Object[] args) { return DfReflectionUtil.invokeForcedly(method, cq, args); } // =================================================================================== // Condition Value // =============== protected ConditionValue nCV() { return newConditionValue(); } protected ConditionValue newConditionValue() { return new ConditionValue(); } // =================================================================================== // Filter Value // ============ /** * Delegate to filterRemoveEmptyString(). {Internal} * @param value The string value for query. (NullAllowed) * @return Filtered value. (NullAllowed) */ protected String fRES(String value) { return filterRemoveEmptyString(value); } /** * Filter removing an empty string as null.
* You can extend this to use an empty string value as condition. * @param value The string value for query. (NullAllowed) * @return Filtered value. (NullAllowed) */ protected String filterRemoveEmptyString(String value) { if (isEmptyStringQueryAllowed()) { return value; } return ((value != null && !"".equals(value)) ? value : null); } /** * Does it allowed an empty string to set for query? * @return The determination, true or false. */ protected boolean isEmptyStringQueryAllowed() { return xgetSqlClause().isEmptyStringQueryAllowed(); } /** * Delegate to filterConvertToPureDate(). * @param date The instance of date for query. (NullAllowed) * @return Filtered date. (NullAllowed) */ protected java.util.Date fCTPD(java.util.Date date) { return filterConvertToPureDate(date); } /** * Filter converting the date to a pure date. * @param date The instance of date for query. (NullAllowed) * @return Filtered value. (NullAllowed) */ protected java.util.Date filterConvertToPureDate(java.util.Date date) { return DfTypeUtil.toDate(date); } // =================================================================================== // Create Option // ============= // ----------------------------------------------------- // LikeSearch // ---------- protected LikeSearchOption xcLSOP(ConditionOptionCall opCall) { // called by template: createLikeSearchOption() final LikeSearchOption op = newLikeSearchOption(); opCall.callback(op); return op; } protected LikeSearchOption xcLSOPPre() { // for old style PrefixSearch return newLikeSearchOption().likePrefix(); } /** * New-create the option of like-search as plain. * @return The new-created option of like-search. (NotNull) */ protected LikeSearchOption newLikeSearchOption() { return new LikeSearchOption(); } // ----------------------------------------------------- // RangeOf // ------- protected RangeOfOption xcROOP(ConditionOptionCall opCall) { // called by template: createRangeOfOption() final RangeOfOption op = newRangeOfOption(); opCall.callback(op); return op; } /** * New-create the option of range-of as plain. * @return The new-created option of range-of. (NotNull) */ protected RangeOfOption newRangeOfOption() { return new RangeOfOption(); } // ----------------------------------------------------- // FromTo // ------ protected FromToOption xcFTOP(ConditionOptionCall opCall) { // called by template: createFromToOption() final FromToOption op = newFromToOption(); opCall.callback(op); return op; } protected FromToOption xcDFTOP() { // for old style DateFromTo return newFromToOption().compareAsDate(); } /** * New-create the option of from-to as plain. * @return The new-created option of from-to. (NotNull) */ protected FromToOption newFromToOption() { return new FromToOption(); } // =================================================================================== // Convert Value // ============= /** * @param obj The object of the property. (NullAllowed) * @param type The type instance of the property. (NullAllowed) * @param The type of property. * @return The number type result of the property. (NullAllowed: if null, returns null) */ @SuppressWarnings("unchecked") protected PROPERTY cTNum(Object obj, Class type) { // convert to number return (PROPERTY) DfTypeUtil.toNumber(obj, type); } /** * @param col The collection of the property. (NullAllowed) * @param The type of property. * @return The list of the property. (NullAllowed: if null, returns null) */ protected List cTL(Collection col) { // convert to list // though BindVariableNode (or Embedded) can accept Collection and filter it, // this process has been existed for a long time as traditional filter return xconvertToList(col); } protected List cTStrL(Collection col) { // convert to string list if (col == null) { return null; } final List list = new ArrayList(); for (Classification cls : col) { if (cls != null) { list.add(cls.code()); } } return list; } protected List cTNumL(Collection col, Class type) { // convert to number list if (col == null) { return null; } final List list = new ArrayList(); for (Classification cls : col) { if (cls != null) { @SuppressWarnings("unchecked") final PROPERTY value = (PROPERTY) DfTypeUtil.toNumber(cls.code(), type); list.add(value); } } return list; } /** * @param col The collection of property. (NullAllowed) * @param The type of property. * @return The list of the property. (NullAllowed: if null, returns null) */ protected List xconvertToList(Collection col) { if (col == null) { return null; } if (col instanceof List) { return xfilterRemoveNullOrEmptyValueFromList((List) col); } return xfilterRemoveNullOrEmptyValueFromList(new ArrayList(col)); } protected List xfilterRemoveNullOrEmptyValueFromList(List ls) { if (ls == null) { return null; } final List newList = new ArrayList(); for (Iterator ite = ls.iterator(); ite.hasNext();) { final PROPERTY_TYPE element = ite.next(); if (element == null) { continue; } if (element instanceof String) { if (((String) element).length() == 0) { continue; } } newList.add(element); } return newList; } // =================================================================================== // Short Character // =============== // handleShortChar() protected String hSC(String columnName, String value, Integer size, String modeCode) { final ShortCharHandlingMode mode = ShortCharHandlingMode.codeOf(modeCode); if (mode == null) { String msg = "The mode was not found by the code: "; msg = msg + " columnName=" + columnName + " modeCode=" + modeCode; throw new IllegalStateException(msg); } return FunCustodial.handleShortChar(columnName, value, size, mode); } // =================================================================================== // Full Text Search // ================ // ----------------------------------------------------- // MySQL // ----- protected void xdoMatchForMySQL(List textColumnList, String conditionValue, WayOfMySQL.FullTextSearchModifier modifier) { if (conditionValue == null || conditionValue.length() == 0) { return; // ignored according to condition-bean rule } final String clause = ((SqlClauseMySql) xgetSqlClause()).buildMatchCondition(textColumnList, conditionValue, modifier, asTableDbName(), xgetAliasName()); registerWhereClause(clause); } // ----------------------------------------------------- // PostgreSQL/Oracle // ----------------- protected void xdoMatchByLikeSearch(List textColumnList, String conditionValue) { if (conditionValue == null || conditionValue.length() == 0) { return; } assertObjectNotNull("textColumnList", textColumnList); if (textColumnList.isEmpty()) { String msg = "The argument 'textColumnList' should not be empty list."; throw new IllegalArgumentException(msg); } conditionValue = xescapeFullTextSearchValue(conditionValue); xgetSqlClause().beginOrScopeQuery(); try { for (ColumnInfo columnInfo : textColumnList) { if (columnInfo == null) { continue; } final String tableOfColumn = columnInfo.getDBMeta().getTableDbName(); if (!tableOfColumn.equalsIgnoreCase(asTableDbName())) { String msg = "The table of the text column should be '" + asTableDbName() + "'"; msg = msg + " but the table is '" + tableOfColumn + "': column=" + columnInfo; throw new IllegalArgumentException(msg); } if (!columnInfo.isObjectNativeTypeString()) { String msg = "The text column should be String type:"; msg = msg + " column=" + columnInfo; throw new IllegalArgumentException(msg); } invokeQueryLikeSearch(columnInfo.getColumnDbName(), conditionValue, xcreateMatchLikeSearch()); } } finally { xgetSqlClause().endOrScopeQuery(); } } protected String xescapeFullTextSearchValue(String conditionValue) { String msg = "You should override this method."; throw new UnsupportedOperationException(msg); } protected String xescapeOracleFullTextSearchValue(String conditionValue) { return ((SqlClauseOracle) xgetSqlClause()).escapeFullTextSearchValue(conditionValue); } protected LikeSearchOption xcreateMatchLikeSearch() { String msg = "You should override this method."; throw new UnsupportedOperationException(msg); } protected LikeSearchOption xcreatePostgreSQLMatchLikeSearch() { return new PostgreSQLMatchLikeSearch(); } public class PostgreSQLMatchLikeSearch extends LikeSearchOption { @Override public ExtensionOperand getExtensionOperand() { return xgetPostgreSQLMatchOperand(); } } protected ExtensionOperand xgetPostgreSQLMatchOperand() { String msg = "You should override this method."; throw new UnsupportedOperationException(msg); } protected LikeSearchOption xcreateOracleMatchLikeSearch() { return new OracleMatchLikeSearch(); } public class OracleMatchLikeSearch extends LikeSearchOption { @Override public QueryClauseArranger getWhereClauseArranger() { return ((SqlClauseOracle) xgetSqlClause()).createFullTextSearchClauseArranger(); } } // =================================================================================== // ColumnQuery Object // ================== /** * Get the condition-bean map of ColumnQuery for parameter comment. {Internal}.
* This is basically for (Specify)DerivedReferrer's bind conditions in ColumnQuery.
* The value is treated as Object type because this will be only called from parameter comment. * @return The instance of the map. (NullAllowed) */ public Map xdfgetColQyCBMap() { return xgetSqlClause().getColumnQueryObjectMap(); } protected String xregisterColumyQueryObjectToThemeList(String themeKey, Object addedValue) { return xgetSqlClause().registerColumnQueryObjectToThemeList(themeKey, addedValue); } // =================================================================================== // ManualOrder Parameter // ===================== /** * Get the parameter map of ManualOrder for parameter comment. {Internal}. * @return The instance of the map. (NullAllowed) */ public Map xdfgetMnuOdrPrmMap() { return xgetSqlClause().getManualOrderParameterMap(); } protected String xregisterManualOrderParameterToThemeList(String themeKey, Object addedValue) { return xgetSqlClause().registerManualOrderParameterToThemeList(themeKey, addedValue); } // =================================================================================== // Free Parameter // ============== /** * Get the map of free parameter for parameter comment. {Internal}. * @return The instance of the map. (NullAllowed) */ public Map xdfgetFreePrmMap() { return xgetSqlClause().getFreeParameterMap(); } // 'public' modifier for versatility // e.g. called by compound PK's LoadReferrer public String xregisterFreeParameterToThemeList(String themeKey, Object addedValue) { return xgetSqlClause().registerFreeParameterToThemeList(themeKey, addedValue); } // =================================================================================== // Relation Keeping // ================ protected boolean xhasQueRlMap(String prop) { return _queryRelationKeepingMap != null && _queryRelationKeepingMap.containsKey(prop); } @SuppressWarnings("unchecked") protected CQ xgetQueRlMap(String prop) { return _queryRelationKeepingMap != null ? (CQ) _queryRelationKeepingMap.get(prop) : null; } protected void xregQueRl(String prop, ConditionQuery cq) { if (_queryRelationKeepingMap == null) { _queryRelationKeepingMap = newLinkedHashMapSized(4); } _queryRelationKeepingMap.put(prop, cq); } protected void xregOutJo(String prop) { // should be called after registration if (_queryRelationKeepingMap == null) { // no way, just in case _queryRelationKeepingMap = newLinkedHashMapSized(4); } final ConditionQuery cq = _queryRelationKeepingMap.get(prop); if (cq == null) { // no way, just in case String msg = "Not found the condition-query for (Query)Relation: " + prop; throw new IllegalStateException(msg); } final ForeignInfo foreignInfo = xgetLocalDBMeta().findForeignInfo(prop); final Map localForeignColMap = foreignInfo.getLocalForeignColumnInfoMap(); final Map joinOnMap = newLinkedHashMapSized(localForeignColMap.size()); for (Entry entry : localForeignColMap.entrySet()) { final ColumnInfo localCol = entry.getKey(); final ColumnInfo foreignCol = entry.getValue(); joinOnMap.put(localCol.getColumnDbName(), foreignCol.getColumnDbName()); } registerOuterJoin(cq, joinOnMap, prop); } @SuppressWarnings("unchecked") protected Map xgetSQueMap(String identity) { return _subQueryKeepingMap != null ? (Map) _subQueryKeepingMap.get(identity) : null; } protected String xkeepSQue(String identity, ConditionQuery subQuery) { if (_subQueryKeepingMap == null) { _subQueryKeepingMap = newLinkedHashMapSized(4); } Map sqMap = _subQueryKeepingMap.get(identity); if (sqMap == null) { sqMap = newLinkedHashMapSized(4); _subQueryKeepingMap.put(identity, sqMap); } final String key = "subQueryKey" + (sqMap.size() + 1); sqMap.put(key, subQuery); return identity + "." + key; // [property-name] + [.] + [key] } protected Map xgetSQuePmMap(String identity) { return _subQueryParameterKeepingMap != null ? _subQueryParameterKeepingMap.get(identity) : null; } protected String xkeepSQuePm(String identity, Object paramValue) { // identity same as condition-query keeping if (_subQueryParameterKeepingMap == null) { _subQueryParameterKeepingMap = newLinkedHashMapSized(4); } Map paramMap = _subQueryParameterKeepingMap.get(identity); if (paramMap == null) { paramMap = newLinkedHashMapSized(4); _subQueryParameterKeepingMap.put(identity, paramMap); } final String key = "subQueryParameterKey" + (paramMap.size() + 1); paramMap.put(key, paramValue); return identity + "Parameter." + key; // [property-name (needs suffix 'Parameter')] + [.] + [key] } // =================================================================================== // Option Parameter // ================ public void xregisterParameterOption(ParameterOption option) { if (option == null) { return; } // don't know the option has parameter or not yet // so always prepare it when the option exists if (_parameterOptionMap == null) { _parameterOptionMap = newHashMapSized(4); } final String parameterKey = "option" + _parameterOptionMap.size(); _parameterOptionMap.put(parameterKey, option); final String parameterMapPath = xgetLocationBase() + "optionParameterMap"; option.acceptParameterKey(parameterKey, parameterMapPath); } public Map xdfgetOptionParameterMap() { // for parameter comment return _parameterOptionMap; } // =================================================================================== // Purpose Type // ============ protected void lockCall(IndependentProcessor noArgInLambda) { lock(); try { noArgInLambda.process(); } finally { unlock(); } } protected void lock() { xgetSqlClause().lock(); } protected void unlock() { xgetSqlClause().unlock(); } // =================================================================================== // Exception Helper // ================ protected ConditionBeanExceptionThrower createCBExThrower() { return new ConditionBeanExceptionThrower(); } // =================================================================================== // General Helper // ============== // ----------------------------------------------------- // String // ------ protected final String replaceString(String text, String fromText, String toText) { return Srl.replace(text, fromText, toText); } protected String initCap(String str) { return Srl.initCap(str); } protected String initUncap(String str) { return Srl.initUncap(str); } protected String ln() { return DBFluteSystem.ln(); } // ----------------------------------------------------- // Collection // ---------- protected HashMap newHashMap() { return DfCollectionUtil.newHashMap(); } protected HashMap newHashMapSized(int size) { return DfCollectionUtil.newHashMapSized(size); } protected LinkedHashMap newLinkedHashMap() { return DfCollectionUtil.newLinkedHashMap(); } protected LinkedHashMap newLinkedHashMapSized(int size) { return DfCollectionUtil.newLinkedHashMapSized(size); } protected ArrayList newArrayList() { return DfCollectionUtil.newArrayList(); } protected ArrayList newArrayListSized(int size) { return DfCollectionUtil.newArrayListSized(size); } // avoid heap warning protected List newArrayList(ELEMENT element) { return DfCollectionUtil.newArrayList(element); } protected List newArrayList(ELEMENT element1, ELEMENT element2) { return DfCollectionUtil.newArrayList(element1, element2); } protected List newArrayList(ELEMENT element1, ELEMENT element2, ELEMENT element3) { return DfCollectionUtil.newArrayList(element1, element2, element3); } protected ArrayList newArrayList(Collection collection) { return DfCollectionUtil.newArrayList(collection); } // ----------------------------------------------------- // Assert Object // ------------- /** * Assert that the object is not null. * @param variableName The check name of variable for message. (NotNull) * @param value The checked value. (NotNull) * @throws IllegalArgumentException When the argument is null. */ protected void assertObjectNotNull(String variableName, Object value) { if (variableName == null) { String msg = "The value should not be null: variableName=null value=" + value; throw new IllegalArgumentException(msg); } if (value == null) { String msg = "The value should not be null: variableName=" + variableName; throw new IllegalArgumentException(msg); } } /** * Assert that the column-name is not null and is not empty and does not contain comma. * @param columnName The checked name of column. (NotNull) * @throws IllegalArgumentException When the argument is invalid. */ protected void assertColumnName(String columnName) { if (columnName == null) { String msg = "The columnName should not be null."; throw new IllegalArgumentException(msg); } if (columnName.trim().length() == 0) { String msg = "The columnName should not be empty-string."; throw new IllegalArgumentException(msg); } if (columnName.indexOf(",") >= 0) { String msg = "The columnName should not contain comma ',': " + columnName; throw new IllegalArgumentException(msg); } } /** * Assert that the alias-name is not null and is not empty and does not contain comma. * @param aliasName The checked name for alias. (NotNull) * @throws IllegalArgumentException When the argument is invalid. */ protected void assertAliasName(String aliasName) { if (aliasName == null) { String msg = "The aliasName should not be null."; throw new IllegalArgumentException(msg); } if (aliasName.trim().length() == 0) { String msg = "The aliasName should not be empty-string."; throw new IllegalArgumentException(msg); } if (aliasName.indexOf(",") >= 0) { String msg = "The aliasName should not contain comma ',': " + aliasName; throw new IllegalArgumentException(msg); } } // ----------------------------------------------------- // Assert String // ------------- /** * Assert that the string is not null and not trimmed empty. * @param variableName The check name of variable for message. (NotNull) * @param value The checked value. (NotNull) * @throws IllegalArgumentException When the argument is null or empty. */ protected void assertStringNotNullAndNotTrimmedEmpty(String variableName, String value) { assertObjectNotNull("variableName", variableName); assertObjectNotNull("value", value); if (value.trim().length() == 0) { String msg = "The value should not be empty: variableName=" + variableName + " value=" + value; throw new IllegalArgumentException(msg); } } // ----------------------------------------------------- // Final TimeZone // -------------- protected TimeZone getDBFluteSystemFinalTimeZone() { return DBFluteSystem.getFinalTimeZone(); } // =================================================================================== // Basic Override // ============== @Override public String toString() { final String titleName = DfTypeUtil.toClassTitle(this); return titleName + ":{aliasName=" + _aliasName + ", nestLevel=" + _nestLevel + ", subQueryLevel=" + _subQueryLevel + ", foreignPropertyName=" + _foreignPropertyName + ", relationPath=" + _relationPath + ", onClauseInline=" + _onClause + "}"; } }