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

io.ebeaninternal.server.expression.InPairsExpression Maven / Gradle / Ivy

There is a newer version: 15.10.0
Show newest version
package io.ebeaninternal.server.expression;

import io.ebean.Pairs;
import io.ebean.Pairs.Entry;
import io.ebean.event.BeanQueryRequest;
import io.ebeaninternal.api.NaturalKeyQueryData;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.persist.MultiValueWrapper;

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

class InPairsExpression extends AbstractExpression {

  private final boolean not;

  private final String property0, property1;

  private List entries;

  private boolean multiValueSupported;

  private final String separator;

  private final String suffix;

  private List concatBindValues;

  InPairsExpression(Pairs pairs, boolean not) {
    super(pairs.getProperty0());
    this.property0 = pairs.getProperty0();
    this.property1 = pairs.getProperty1();
    // the entries might be modified on cache hit.
    this.entries = pairs.getEntries();
    this.not = not;
    this.separator = pairs.getConcatSeparator();
    this.suffix = pairs.getConcatSuffix();
  }

  @Override
  public boolean naturalKey(NaturalKeyQueryData data) {
    if (not) {
      return false;
    }
    List copy = data.matchInPairs(property0, property1, entries);
    if (copy == null) {
      return false;
    }
    entries = copy;
    return true;
  }

  @Override
  public void prepareExpression(BeanQueryRequest request) {
    // at this stage translating pairs into varchar via DB concat
    multiValueSupported = request.isMultiValueSupported(String.class);
  }

  @Override
  public void writeDocQuery(DocQueryContext context) throws IOException {
    throw new RuntimeException("Not supported with document query");
  }

  @Override
  public void addBindValues(SpiExpressionRequest request) {

    // Note at this point entries may have been removed when used with l2 caching
    // ... for each l2 cache hit an entry was removed
    this.concatBindValues = new ArrayList<>(entries.size());
    for (Pairs.Entry entry : entries) {
      concatBindValues.add(concat(entry.getA(), entry.getB()));
    }
    request.addBindValue(new MultiValueWrapper(concatBindValues, String.class));
  }

  /**
   * Using DB concat at this stage. Usually a DB expression index should match the concat.
   */
  private String concat(Object key, Object value) {
    StringBuilder sb = new StringBuilder(30);
    sb.append(key);
    sb.append(separator);
    sb.append(value);
    if (suffix != null) {
      sb.append(suffix);
    }
    return sb.toString();
  }

  @Override
  public void addSql(SpiExpressionRequest request) {

    if (entries.isEmpty()) {
      String expr = not ? "1=1" : "1=0";
      request.append(expr);
      return;
    }

    request.append(request.getDbPlatformHandler().concat(property0, separator, property1, suffix));
    request.appendInExpression(not, concatBindValues);
  }

  /**
   * Based on the number of values in the in clause.
   */
  @Override
  public void queryPlanHash(StringBuilder builder) {
    if (not) {
      builder.append("NotInPairs[");
    } else {
      builder.append("InPairs[");
    }
    builder.append(property0).append("-");
    builder.append(property1).append("-");
    builder.append(separator).append("-");
    builder.append(suffix).append(" ?");
    if (!multiValueSupported) {
      // query plan specific to the number of parameters in the IN clause
      builder.append(entries.size());
    }
    builder.append("]");
  }

  @Override
  public int queryBindHash() {
    int hc = 92821;
    for (Pairs.Entry entry : entries) {
      hc = 92821 * hc + entry.hashCode();
    }
    return hc;
  }

  @Override
  public boolean isSameByBind(SpiExpression other) {

    InPairsExpression that = (InPairsExpression) other;
    return this.entries.size() == that.entries.size() && entries.equals(that.entries);
  }
}