package io.ebeaninternal.server.expression;

import io.ebean.event.BeanQueryRequest;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiExpressionValidation;
import io.ebeaninternal.server.core.BindPadding;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.id.IdBinder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

In a collection of Id values.
/** * In a collection of Id values. */
public class IdInExpression extends NonPrepareExpression { private final List<Object> idCollection; private boolean multiValueIdSupported; public IdInExpression(Collection<?> idCollection) { this.idCollection = new ArrayList<>(idCollection); }
Return the ids this expression is looking to fetch.
/** * Return the ids this expression is looking to fetch. */
public Collection<Object> idValues() { return idCollection; }
Remove Ids that where obtained from l2 cache. Don't fetch these from DB.
/** * Remove Ids that where obtained from l2 cache. Don't fetch these from DB. */
public int removeIds(Set<Object> hitIds) { idCollection.removeAll(hitIds); return idCollection.size(); } @Override public void prepareExpression(BeanQueryRequest<?> request) { multiValueIdSupported = request.isMultiValueIdSupported(); if (!multiValueIdSupported && !idCollection.isEmpty() && request.isPadInExpression()) { // pad out the ids for better hit ratio on DB query plans BindPadding.padIds(idCollection); } } @Override public String nestedPath(BeanDescriptor<?> desc) { return null; } @Override public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) { } @Override public void writeDocQuery(DocQueryContext context) throws IOException { context.writeIds(idCollection); } @Override public void validate(SpiExpressionValidation validation) { // always valid } @Override public void addBindValues(SpiExpressionRequest request) { if (idCollection.isEmpty()) { return; } // Bind the Id values including EmbeddedId and multiple Id DefaultExpressionRequest r = (DefaultExpressionRequest) request; BeanDescriptor<?> descriptor = r.getBeanDescriptor(); IdBinder idBinder = descriptor.getIdBinder(); idBinder.addIdInBindValues(request, idCollection); }
For use with deleting non attached detail beans during stateless update.
/** * For use with deleting non attached detail beans during stateless update. */
public void addSqlNoAlias(SpiExpressionRequest request) { DefaultExpressionRequest r = (DefaultExpressionRequest) request; BeanDescriptor<?> descriptor = r.getBeanDescriptor(); IdBinder idBinder = descriptor.getIdBinder(); if (idCollection.isEmpty()) { request.append(SQL_FALSE); // append false for this stage } else { request.append(descriptor.getIdBinder().getBindIdInSql(null)); String inClause = idBinder.getIdInValueExpr(false, idCollection.size()); request.append(inClause); } } @Override public void addSql(SpiExpressionRequest request) { BeanDescriptor<?> descriptor = request.getBeanDescriptor(); IdBinder idBinder = descriptor.getIdBinder(); if (idCollection.isEmpty()) { request.append(SQL_FALSE); // append false for this stage } else { if (idBinder.isComplexId()) { request.append(descriptor.getIdBinderInLHSSql()); request.append(idBinder.getIdInValueExpr(false, idCollection.size())); } else { request.append(idBinder.getBeanProperty().getName()); request.appendInExpression(false, idCollection); } } }
Incorporates the number of Id values to bind.
/** * Incorporates the number of Id values to bind. */
@Override public void queryPlanHash(StringBuilder builder) { builder.append("IdIn[?"); if (!multiValueIdSupported || idCollection.isEmpty()) { // query plan specific to the number of parameters in the IN clause builder.append(idCollection.size()); } builder.append("]"); } @Override public int queryBindHash() { return idCollection.hashCode(); } @Override public boolean isSameByBind(SpiExpression other) { IdInExpression that = (IdInExpression) other; if (this.idCollection.size() != that.idCollection.size()) { return false; } Iterator<?> it = that.idCollection.iterator(); for (Object id1 : idCollection) { Object id2 = it.next(); if (!id1.equals(id2)) { return false; } } return true; } }