/**
  * INTERNAL: Rebuild myself against the base, with the values of parameters supplied by the
  * context expression. This is used for transforming a standalone expression (e.g. the join
  * criteria of a mapping) into part of some larger expression. You normally would not call this
  * directly, instead calling twist See the comment there for more details"
  */
 public Expression twistedForBaseAndContext(Expression newBase, Expression context) {
   Expression twistedBase = getBaseExpression().twistedForBaseAndContext(newBase, context);
   QueryKeyExpression result = (QueryKeyExpression) twistedBase.get(getName());
   if (shouldUseOuterJoin) {
     result.doUseOuterJoin();
   }
   if (shouldQueryToManyRelationship) {
     result.doQueryToManyRelationship();
   }
   return result;
 }
  /**
   * Return an expression that allows you to treat its base as if it were a subclass of the class
   * returned by the base This can only be called on an ExpressionBuilder, the result of
   * expression.get(String), expression.getAllowingNull(String), the result of
   * expression.anyOf("String") or the result of expression.anyOfAllowingNull("String")
   *
   * <p>downcast uses Expression.type() internally to guarantee the results are of the specified
   * class.
   *
   * <p>Example:
   *
   * <pre><blockquote>
   *     Expression: employee.get("project").as(LargeProject.class).get("budget").equal(1000)
   *     Java: ((LargeProject)employee.getProjects().get(0)).getBudget() == 1000
   *     SQL: LPROJ.PROJ_ID (+)= PROJ.PROJ_ID AND L_PROJ.BUDGET = 1000 AND PROJ.TYPE = "L"
   * </blockquote></pre>
   */
  @Override
  public Expression treat(Class castClass) {
    // to be used on expressionBuilders
    QueryKeyExpression clonedExpression = new TreatAsExpression(castClass, this);
    clonedExpression.shouldQueryToManyRelationship = false;
    clonedExpression.hasQueryKey = false;
    clonedExpression.hasMapping = false;

    this.addDerivedExpression(clonedExpression);
    return clonedExpression;
  }
 /**
  * PUBLIC: Return an expression representing traversal of a 1:many or many:many relationship. This
  * allows you to query whether any of the "many" side of the relationship satisfies the remaining
  * criteria.
  *
  * <p>Example:
  *
  * <pre><blockquote>
  *     Expression: employee.anyOf("managedEmployees").get("firstName").equal("Bob")
  *     Java: no direct equivalent
  *     SQL: SELECT DISTINCT ... WHERE (t2.MGR_ID = t1.ID) AND (t2.F_NAME = 'Bob')
  * </pre>
  *
  * </blockquote>
  *
  * @parameter shouldJoinBeIndependent indicates whether a new expression should be created.
  */
 @Override
 public Expression anyOf(String attributeName, boolean shouldJoinBeIndependent) {
   QueryKeyExpression queryKey;
   if (shouldJoinBeIndependent) {
     queryKey = newDerivedExpressionNamed(attributeName);
   } else {
     queryKey = derivedExpressionNamed(attributeName);
   }
   queryKey.doQueryToManyRelationship();
   return queryKey;
 }
 /**
  * INTERNAL: Return if the expression is equal to the other. This is used to allow dynamic
  * expression's SQL to be cached.
  */
 public boolean equals(Object object) {
   if (this == object) {
     return true;
   }
   if (!super.equals(object)) {
     return false;
   }
   QueryKeyExpression expression = (QueryKeyExpression) object;
   // Return false for anyOf expressions, as equality is unknown.
   if (shouldQueryToManyRelationship() || expression.shouldQueryToManyRelationship()) {
     return false;
   }
   return ((getName() == expression.getName())
       || ((getName() != null) && getName().equals(expression.getName())));
 }
  /**
   * INTERNAL: This expression is built on a different base than the one we want. Rebuild it and
   * return the root of the new tree
   */
  public Expression rebuildOn(Expression newBase) {
    Expression newLocalBase = getBaseExpression().rebuildOn(newBase);
    QueryKeyExpression result = null;

    // For bug 3096634 rebuild outer joins correctly from the start.
    if (shouldUseOuterJoin) {
      result = (QueryKeyExpression) newLocalBase.getAllowingNull(getName());
    } else {
      result = (QueryKeyExpression) newLocalBase.get(getName());
    }
    if (shouldQueryToManyRelationship) {
      result.doQueryToManyRelationship();
    }
    result.setSelectIfOrderedBy(selectIfOrderedBy());
    return result;
  }
 public QueryKeyExpression existingDerivedExpressionNamed(String attributeName) {
   if (this.derivedExpressions == null) {
     return null;
   }
   List<Expression> derivedExpressionsCopy;
   synchronized (this) {
     derivedExpressionsCopy = new ArrayList(this.derivedExpressions);
   }
   for (Expression derivedExpression : derivedExpressionsCopy) {
     QueryKeyExpression exp = (QueryKeyExpression) derivedExpression;
     if (exp.getName().equals(attributeName)) {
       return exp;
     }
   }
   return null;
 }
 public void writeSubexpressionsTo(BufferedWriter writer, int indent) throws IOException {
   if (this.typeExpressionBase != null) {
     this.typeExpressionBase.toString(writer, indent);
   } else {
     super.writeSubexpressionsTo(writer, indent);
   }
 }
 /** INTERNAL: Return if the attribute is specified for batch reading. */
 public boolean isAttributeBatchRead(String attributeName) {
   if (!hasBatchReadAttributes()) {
     return false;
   }
   Vector batchReadAttributeExpressions = getBatchReadAttributeExpressions();
   int size = batchReadAttributeExpressions.size();
   for (int index = 0; index < size; index++) {
     QueryKeyExpression expression = (QueryKeyExpression) batchReadAttributeExpressions.get(index);
     while (!expression.getBaseExpression().isExpressionBuilder()) {
       expression = (QueryKeyExpression) expression.getBaseExpression();
     }
     if (expression.getName().equals(attributeName)) {
       return true;
     }
   }
   return false;
 }
 @Override
 protected void postCopyIn(Map alreadyDone) {
   super.postCopyIn(alreadyDone);
   this.typeExpressionBase = (ObjectExpression) typeExpressionBase.copiedVersionFrom(alreadyDone);
 }