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.8.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.*;
import io.ebeaninternal.server.persist.MultiValueWrapper;

import java.util.ArrayList;
import java.util.List;

final 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.property0());
    this.property0 = pairs.property0();
    this.property1 = pairs.property1();
    // the entries might be modified on cache hit.
    this.entries = pairs.entries();
    this.not = not;
    this.separator = pairs.concatSeparator();
    this.suffix = pairs.concatSuffix();
  }

  @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) {
    throw new RuntimeException("Not supported with document query");
  }

  @Override
  public void addBindValues(SpiExpressionBind 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()) {
      request.append(not ? SQL_TRUE : SQL_FALSE);
      return;
    }
    request.parse(request.platformHandler().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 || entries.isEmpty()) {
      // query plan specific to the number of parameters in the IN clause
      builder.append(entries.size());
    }
    builder.append(']');
  }

  @Override
  public void queryBindKey(BindValuesKey key) {
    key.add(entries.size());
    for (Pairs.Entry entry : entries) {
      key.add(entry.getA()).add(entry.getB());
    }
  }

  @Override
  public boolean isSameByBind(SpiExpression other) {

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