#566 - Refactor internals - SpiExpression, add prepareExpression() to merge queryAutoTuneHash() and queryPlanHash() - sameByPlan() & sameByBind()

This commit is contained in:
Robin Bygrave
2016-02-15 23:44:56 +13:00
parent 165d4aca92
commit 3d91a4f927
72 changed files with 3119 additions and 339 deletions
@@ -0,0 +1,14 @@
package com.avaje.ebeaninternal.api;
/**
* Key used for caching query plans for ORM and RawSql queries.
*/
public interface CQueryPlanKey {
/**
* Used by read audit such that we can log read audit entries without the full sql
* (which would make the read audit logs verbose).
*/
String getPartialKey();
}
@@ -5,32 +5,18 @@ package com.avaje.ebeaninternal.api;
*/
public class HashQuery {
private final HashQueryPlan planHash;
private final CQueryPlanKey planHash;
private final int bindHash;
/**
* Create the HashQuery.
*/
public HashQuery(HashQueryPlan planHash, int bindHash) {
public HashQuery(CQueryPlanKey planHash, int bindHash) {
this.planHash = planHash;
this.bindHash = bindHash;
}
/**
* Return the query plan hash.
*/
public HashQueryPlan getPlanHash() {
return planHash;
}
/**
* Return the bind values hash.
*/
public int getBindHash() {
return bindHash;
}
public int hashCode() {
int hc = 31 * planHash.hashCode();
hc = 31 * hc + bindHash;
@@ -9,14 +9,12 @@ public class HashQueryPlanBuilder {
private int bindCount;
private String rawSql;
public HashQueryPlanBuilder() {
this.planHash = 92821;
}
public String toString() {
return planHash+":"+bindCount+(rawSql != null ? ":r" : "");
return planHash+":"+bindCount;
}
/**
@@ -58,19 +56,24 @@ public class HashQueryPlanBuilder {
bindCount += extraBindCount;
}
/**
* Add raw sql to the hash.
*/
public void addRawSql(String rawSql) {
this.rawSql = rawSql;
public void bindIfNotNull(Object someValue) {
if (someValue != null) {
bindCount++;
}
}
/**
* Build and return the calculated HashQueryPlan.
*/
public HashQueryPlan build() {
return new HashQueryPlan(rawSql, planHash, bindCount);
public String build() {
return planHash+"_"+bindCount;
}
public int getPlanHash() {
return planHash;
}
public int getBindCount() {
return bindCount;
}
}
@@ -37,6 +37,16 @@ public interface SpiExpression extends Expression {
*/
int queryBindHash();
/**
* Return true if the expression is the same without taking into account bind values.
*/
boolean isSameByPlan(SpiExpression other);
/**
* Return true if the expression is the same with respect to bind values.
*/
boolean isSameByBind(SpiExpression other);
/**
* Add some sql to the query.
* <p>
@@ -65,4 +75,10 @@ public interface SpiExpression extends Expression {
* Validate all the properties/paths associated with this expression.
*/
void validate(SpiExpressionValidation validation);
/**
* Return a copy of the expression for use in the query plan key.
*/
SpiExpression copyForPlanKey();
}
@@ -1,16 +1,13 @@
package com.avaje.ebeaninternal.api;
import com.avaje.ebean.ExpressionFactory;
import com.avaje.ebean.ExpressionList;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import java.util.List;
/**
* Internal extension of ExpressionList.
*/
public interface SpiExpressionList<T> extends ExpressionList<T> {
public interface SpiExpressionList<T> extends ExpressionList<T>, SpiExpression {
/**
* Return the underlying list of expressions.
@@ -22,57 +19,9 @@ public interface SpiExpressionList<T> extends ExpressionList<T> {
*/
SpiExpressionList<?> trimPath(int prefixTrim);
/**
* Restore the ExpressionFactory after deserialisation.
*/
void setExpressionFactory(ExpressionFactory expr);
/**
* Process "Many" properties populating ManyWhereJoins.
* <p>
* Predicates on Many properties require an extra independent join clause.
* </p>
*/
void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoins);
/**
* Return true if this list is empty.
*/
boolean isEmpty();
/**
* Concatenate the expression sql into a String.
* <p>
* The list of expressions are evaluated in order building a sql statement
* with bind parameters.
* </p>
*/
String buildSql(SpiExpressionRequest request);
/**
* Combine the expression bind values into a list.
* <p>
* Expressions are evaluated in order and all the resulting bind values are
* returned as a List.
* </p>
*
* @return the list of all the bind values in order.
*/
List<Object> buildBindValues(SpiExpressionRequest request);
/**
* Prepare the expressions contained in the list. For example, compile sub-query expressions etc.
*/
void prepareExpression(BeanQueryRequest<?> request);
/**
* Calculate a hash based on the expressions but excluding the actual bind
* values.
*/
void queryPlanHash(HashQueryPlanBuilder builder);
/**
* Validate all the properties/paths used in this expression list.
*/
void validate(SpiExpressionValidation validation);
}
@@ -467,17 +467,13 @@ public interface SpiQuery<T> extends Query<T> {
String getName();
/**
* Identifies queries that are the same bar the bind variables.
* Prepare the query which prepares sub-query expressions and calculates
* and returns the query plan key.
* <p>
* This is used AFTER AutoTune has potentially tuned the query. This is
* used to identify and reused query plans (the final SQL string and
* associated SqlTree object).
* </p>
* <p>
* Excludes the actual bind values (as they don't effect the query plan).
* The query plan excludes actual bind values (as they don't effect the query plan).
* </p>
*/
HashQueryPlan queryPlanHash(BeanQueryRequest<?> request);
CQueryPlanKey prepare(BeanQueryRequest<?> request);
/**
* Calculate a hash based on the bind values used in the query.
@@ -1110,7 +1110,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
// the query hash after any tuning
request.calculateQueryPlanHash();
request.prepareQuery();
return request;
}
@@ -1,14 +1,11 @@
package com.avaje.ebeaninternal.server.core;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.PersistenceException;
import com.avaje.ebean.*;
import com.avaje.ebean.PersistenceContextScope;
import com.avaje.ebean.QueryEachConsumer;
import com.avaje.ebean.QueryEachWhileConsumer;
import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.RawSql;
import com.avaje.ebean.Version;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.PersistenceContext;
@@ -16,8 +13,8 @@ import com.avaje.ebean.event.BeanFindController;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.BeanIdList;
import com.avaje.ebeaninternal.api.HashQuery;
import com.avaje.ebeaninternal.api.HashQueryPlan;
import com.avaje.ebeaninternal.api.LoadContext;
import com.avaje.ebeaninternal.api.CQueryPlanKey;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.api.SpiQuery.Type;
@@ -32,6 +29,13 @@ import com.avaje.ebeaninternal.server.query.CQueryPlan;
import com.avaje.ebeaninternal.server.query.CancelableQuery;
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
import javax.persistence.PersistenceException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Wraps the objects involved in executing a Query.
*/
@@ -55,7 +59,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
private HashQuery cacheKey;
private HashQueryPlan queryPlanHash;
private CQueryPlanKey queryPlanKey;
/**
* Create the InternalQueryRequest.
@@ -126,10 +130,10 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
}
/**
* Calculate the query plan hash AFTER any potential AutoTune tuning.
* Prepare the query and calculate the query plan key.
*/
public void calculateQueryPlanHash() {
this.queryPlanHash = query.queryPlanHash(this);
public void prepareQuery() {
this.queryPlanKey = query.prepare(this);
}
public boolean isRawSql() {
@@ -355,7 +359,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
* query plan for this query exists.
*/
public CQueryPlan getQueryPlan() {
return beanDescriptor.getQueryPlan(queryPlanHash);
return beanDescriptor.getQueryPlan(queryPlanKey);
}
/**
@@ -366,15 +370,15 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
* with just the bind variables changing.
* </p>
*/
public HashQueryPlan getQueryPlanHash() {
return queryPlanHash;
public CQueryPlanKey getQueryPlanKey() {
return queryPlanKey;
}
/**
* Put the QueryPlan into the cache.
*/
public void putQueryPlan(CQueryPlan queryPlan) {
beanDescriptor.putQueryPlan(queryPlanHash, queryPlan);
beanDescriptor.putQueryPlan(queryPlanKey, queryPlan);
}
public boolean isUseBeanCache() {
@@ -401,7 +405,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
for (T bean : actualDetails) {
ids.add(beanDescriptor.getIdForJson(bean));
}
beanDescriptor.readAuditMany(queryPlanHash.getPartialKey(), "l2-query-cache", ids);
beanDescriptor.readAuditMany(queryPlanKey.getPartialKey(), "l2-query-cache", ids);
}
return cached;
@@ -29,7 +29,7 @@ import com.avaje.ebean.event.readaudit.ReadEvent;
import com.avaje.ebean.meta.MetaBeanInfo;
import com.avaje.ebean.meta.MetaQueryPlanStatistic;
import com.avaje.ebean.plugin.SpiBeanType;
import com.avaje.ebeaninternal.api.HashQueryPlan;
import com.avaje.ebeaninternal.api.CQueryPlanKey;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.api.SpiTransaction;
@@ -87,7 +87,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, SpiBeanType<T> {
private final ConcurrentHashMap<Integer, SpiUpdatePlan> updatePlanCache = new ConcurrentHashMap<Integer, SpiUpdatePlan>();
private final ConcurrentHashMap<HashQueryPlan, CQueryPlan> queryPlanCache = new ConcurrentHashMap<HashQueryPlan, CQueryPlan>();
private final ConcurrentHashMap<CQueryPlanKey, CQueryPlan> queryPlanCache = new ConcurrentHashMap<CQueryPlanKey, CQueryPlan>();
private final ConcurrentHashMap<String, ElPropertyValue> elCache = new ConcurrentHashMap<String, ElPropertyValue>();
@@ -1163,11 +1163,11 @@ public class BeanDescriptor<T> implements MetaBeanInfo, SpiBeanType<T> {
}
}
public CQueryPlan getQueryPlan(HashQueryPlan key) {
public CQueryPlan getQueryPlan(CQueryPlanKey key) {
return queryPlanCache.get(key);
}
public void putQueryPlan(HashQueryPlan key, CQueryPlan plan) {
public void putQueryPlan(CQueryPlanKey key, CQueryPlan plan) {
queryPlanCache.put(key, plan);
}
@@ -10,7 +10,7 @@ import com.avaje.ebean.SqlUpdate;
import com.avaje.ebeaninternal.api.BindParams;
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
import com.avaje.ebeaninternal.server.expression.IdInExpression;
import com.avaje.ebeaninternal.util.DefaultExpressionRequest;
import com.avaje.ebeaninternal.server.expression.DefaultExpressionRequest;
public class IntersectionRow {
@@ -63,6 +63,32 @@ public final class TableJoin {
return hc;
}
@Override
public int hashCode() {
return queryHash;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TableJoin that = (TableJoin) o;
if (!table.equals(that.table)) return false;
if (type != that.type) return false;
if (columns.length != that.columns.length) return false;
for (int i = 0; i < columns.length; i++) {
if (!columns[i].equals(that.columns[i])) {
return false;
}
}
return true;
}
/**
* Return a hash value for adding to a query plan.
*/
@@ -8,76 +8,97 @@ import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
*/
public class TableJoinColumn {
/**
* The local database column name.
*/
private final String localDbColumn;
/**
* The local database column name.
*/
private final String localDbColumn;
/**
* The foreign database column name.
*/
private final String foreignDbColumn;
/**
* The foreign database column name.
*/
private final String foreignDbColumn;
private final boolean insertable;
private final boolean updateable;
private final boolean insertable;
/**
* Hash for including in a query plan
*/
private final int queryHash;
private final boolean updateable;
/**
* Create the pair.
*/
public TableJoinColumn(DeployTableJoinColumn deploy) {
this.localDbColumn = InternString.intern(deploy.getLocalDbColumn());
this.foreignDbColumn = InternString.intern(deploy.getForeignDbColumn());
this.insertable = deploy.isInsertable();
this.updateable = deploy.isUpdateable();
this.queryHash = hashOf(localDbColumn) * 31 + hashOf(foreignDbColumn);
}
/**
* Hash for including in a query plan
*/
private final int queryHash;
private int hashOf(String value) {
return (value == null) ? 0 : value.hashCode();
}
/**
* Create the pair.
*/
public TableJoinColumn(DeployTableJoinColumn deploy) {
this.localDbColumn = InternString.intern(deploy.getLocalDbColumn());
this.foreignDbColumn = InternString.intern(deploy.getForeignDbColumn());
this.insertable = deploy.isInsertable();
this.updateable = deploy.isUpdateable();
this.queryHash = hash();
}
public String toString() {
return localDbColumn+" = "+foreignDbColumn;
}
int hash() {
int result = localDbColumn != null ? localDbColumn.hashCode() : 0;
result = 31 * result + (foreignDbColumn != null ? foreignDbColumn.hashCode() : 0);
result = 31 * result + (insertable ? 1 : 0);
result = 31 * result + (updateable ? 1 : 0);
return result;
}
/**
* Return a hash for including in a query plan.
*/
public int queryHash() {
return queryHash;
}
@Override
public int hashCode() {
return queryHash;
}
/**
* Return the foreign database column name.
*/
public String getForeignDbColumn() {
return foreignDbColumn;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
/**
* Return the local database column name.
*/
public String getLocalDbColumn() {
return localDbColumn;
}
TableJoinColumn that = (TableJoinColumn) o;
if (insertable != that.insertable) return false;
if (updateable != that.updateable) return false;
if (!localDbColumn.equals(that.localDbColumn)) return false;
return foreignDbColumn.equals(that.foreignDbColumn);
}
/**
* Return true if this column should be insertable.
*/
public boolean isInsertable() {
return insertable;
}
public String toString() {
return localDbColumn + " = " + foreignDbColumn;
}
/**
* Return true if this column should be updateable.
*/
public boolean isUpdateable() {
return updateable;
}
/**
* Return a hash for including in a query plan.
*/
public int queryHash() {
return queryHash;
}
/**
* Return the foreign database column name.
*/
public String getForeignDbColumn() {
return foreignDbColumn;
}
/**
* Return the local database column name.
*/
public String getLocalDbColumn() {
return localDbColumn;
}
/**
* Return true if this column should be insertable.
*/
public boolean isInsertable() {
return insertable;
}
/**
* Return true if this column should be updateable.
*/
public boolean isUpdateable() {
return updateable;
}
}
@@ -22,19 +22,20 @@ public abstract class AbstractExpression implements SpiExpression {
this.propName = propName;
}
public String getPropertyName() {
return propName;
@Override
public SpiExpression copyForPlanKey() {
return this;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
String propertyName = getPropertyName();
if (propertyName != null) {
ElPropertyDeploy elProp = desc.getElPropertyDeploy(propertyName);
if (propName != null) {
ElPropertyDeploy elProp = desc.getElPropertyDeploy(propName);
if (elProp != null) {
if (elProp.containsFormulaWithJoin()) {
// for findRowCount query select clause
manyWhereJoin.addFormulaWithJoin(propertyName);
manyWhereJoin.addFormulaWithJoin(propName);
}
if (elProp.containsMany()) {
// for findRowCount we join to a many property
@@ -51,12 +52,11 @@ public abstract class AbstractExpression implements SpiExpression {
@Override
public void validate(SpiExpressionValidation validation) {
validation.validate(getPropertyName());
validation.validate(propName);
}
protected ElPropertyValue getElProp(SpiExpressionRequest request) {
protected final ElPropertyValue getElProp(SpiExpressionRequest request) {
String propertyName = getPropertyName();
return request.getBeanDescriptor().getElGetValue(propertyName);
return request.getBeanDescriptor().getElGetValue(propName);
}
}
@@ -2,11 +2,13 @@ package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.ManyWhereJoins;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
@@ -102,7 +104,7 @@ class AllEqualsExpression extends NonPrepareExpression {
Object value = entry.getValue();
String propName = entry.getKey();
builder.add(propName).add(value == null ? 0 : 1);
builder.bind(value == null ? 0 : 1);
builder.bindIfNotNull(value);
}
}
@@ -116,4 +118,48 @@ class AllEqualsExpression extends NonPrepareExpression {
return hc;
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof AllEqualsExpression)) {
return false;
}
AllEqualsExpression that = (AllEqualsExpression) other;
return isSameByValue(that, false);
}
@Override
public boolean isSameByBind(SpiExpression other) {
if (!(other instanceof AllEqualsExpression)) {
return false;
}
AllEqualsExpression that = (AllEqualsExpression) other;
return isSameByValue(that, true);
}
private boolean isSameByValue(AllEqualsExpression that, boolean byValue) {
if (propMap.size() != that.propMap.size()) {
return false;
}
Iterator<Entry<String, Object>> thisIt = propMap.entrySet().iterator();
Iterator<Entry<String, Object>> thatIt = that.propMap.entrySet().iterator();
while (thisIt.hasNext() && thatIt.hasNext()) {
Entry<String, Object> thisNext = thisIt.next();
Entry<String, Object> thatNext = thatIt.next();
if (!thisNext.getKey().equals(thatNext.getKey())) {
return false;
}
if (!Same.sameBy(byValue, thisNext.getValue(), thatNext.getValue())) {
return false;
}
}
return true;
}
}
@@ -1,10 +1,9 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
class BetweenExpression extends AbstractExpression {
private static final long serialVersionUID = 2078918165221454910L;
@@ -30,7 +29,7 @@ class BetweenExpression extends AbstractExpression {
@Override
public void addSql(SpiExpressionRequest request) {
request.append(getPropertyName()).append(BETWEEN).append(" ? and ? ");
request.append(propName).append(BETWEEN).append(" ? and ? ");
}
@Override
@@ -45,4 +44,21 @@ class BetweenExpression extends AbstractExpression {
hc = hc * 31 + valueHigh.hashCode();
return hc;
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof BetweenExpression)) {
return false;
}
BetweenExpression that = (BetweenExpression) other;
return this.propName.equals(that.propName);
}
@Override
public boolean isSameByBind(SpiExpression other) {
BetweenExpression that = (BetweenExpression) other;
return valueLow.equals(that.valueLow)
&& valueHigh.equals(that.valueHigh);
}
}
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.ManyWhereJoins;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
@@ -50,6 +51,7 @@ class BetweenPropertyExpression extends NonPrepareExpression {
validation.validate(highProperty);
}
@Override
public void addBindValues(SpiExpressionRequest request) {
request.addBindValue(value);
}
@@ -70,4 +72,21 @@ class BetweenPropertyExpression extends NonPrepareExpression {
public int queryBindHash() {
return value.hashCode();
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof BetweenPropertyExpression)) {
return false;
}
BetweenPropertyExpression that = (BetweenPropertyExpression) other;
return lowProperty.equals(that.lowProperty)
&& highProperty.equals(that.highProperty);
}
@Override
public boolean isSameByBind(SpiExpression other) {
BetweenPropertyExpression that = (BetweenPropertyExpression) other;
return value.equals(that.value);
}
}
@@ -1,7 +1,7 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
@@ -16,6 +16,7 @@ class CaseInsensitiveEqualExpression extends AbstractExpression {
this.value = value.toLowerCase();
}
@Override
public void addBindValues(SpiExpressionRequest request) {
ElPropertyValue prop = getElProp(request);
@@ -28,14 +29,13 @@ class CaseInsensitiveEqualExpression extends AbstractExpression {
request.addBindValue(value);
}
@Override
public void addSql(SpiExpressionRequest request) {
String propertyName = getPropertyName();
String pname = propertyName;
String pname = propName;
ElPropertyValue prop = getElProp(request);
if (prop != null && prop.isDbEncrypted()) {
pname = prop.getBeanProperty().getDecryptProperty(propertyName);
pname = prop.getBeanProperty().getDecryptProperty(propName);
}
request.append("lower(").append(pname).append(") =? ");
@@ -51,4 +51,20 @@ class CaseInsensitiveEqualExpression extends AbstractExpression {
public int queryBindHash() {
return value.hashCode();
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof CaseInsensitiveEqualExpression)) {
return false;
}
CaseInsensitiveEqualExpression that = (CaseInsensitiveEqualExpression) other;
return this.propName.equals(that.propName);
}
@Override
public boolean isSameByBind(SpiExpression other) {
CaseInsensitiveEqualExpression that = (CaseInsensitiveEqualExpression) other;
return value.equals(that.value);
}
}
@@ -86,6 +86,19 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
this.likeType = likeType;
}
DefaultExampleExpression(ArrayList<SpiExpression> source) {
this.entity = null;
this.list = new ArrayList<SpiExpression>(source.size());
for (SpiExpression expression : source) {
list.add(expression.copyForPlanKey());
}
}
@Override
public SpiExpression copyForPlanKey() {
return new DefaultExampleExpression(list);
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins whereManyJoins) {
if (list != null) {
@@ -201,6 +214,38 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
return hc;
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof DefaultExampleExpression)) {
return false;
}
DefaultExampleExpression that = (DefaultExampleExpression) other;
if (this.list.size() != that.list.size()) {
return false;
}
for (int i = 0; i < list.size(); i++) {
if (!list.get(i).isSameByPlan(that.list.get(i))) {
return false;
}
}
return true;
}
@Override
public boolean isSameByBind(SpiExpression other) {
DefaultExampleExpression that = (DefaultExampleExpression) other;
if (this.list.size() != that.list.size()) {
return false;
}
for (int i = 0; i < list.size(); i++) {
if (!list.get(i).isSameByBind(that.list.get(i))) {
return false;
}
}
return true;
}
/**
* Build the List of expressions.
*/
@@ -1,4 +1,4 @@
package com.avaje.ebeaninternal.util;
package com.avaje.ebeaninternal.server.expression;
import java.sql.Timestamp;
import java.util.ArrayList;
@@ -56,6 +56,10 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
this.listAndJoin = " and ";
}
private DefaultExpressionList() {
this(null, null, null, new ArrayList<SpiExpression>());
}
@Override
public SpiExpressionList<?> trimPath(int prefixTrim) {
throw new RuntimeException("Only allowed on FilterExpressionList");
@@ -65,17 +69,6 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return list;
}
/**
* Set the ExpressionFactory.
* <p>
* After deserialisation so that it can be further modified.
* </p>
*/
@Override
public void setExpressionFactory(ExpressionFactory expr) {
this.expr = expr;
}
/**
* Return a copy of the expression list.
* <p>
@@ -88,6 +81,14 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return copy;
}
public DefaultExpressionList<T> copyForPlanKey() {
DefaultExpressionList<T> copy = new DefaultExpressionList<T>();
for (int i = 0; i < list.size(); i++) {
copy.list.add(list.get(i).copyForPlanKey());
}
return copy;
}
/**
* Return true if one of the expressions is related to a Many property.
*/
@@ -325,7 +326,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
}
@Override
public String buildSql(SpiExpressionRequest request) {
public void addSql(SpiExpressionRequest request) {
request.append(listAndStart);
for (int i = 0, size = list.size(); i < size; i++) {
@@ -336,17 +337,13 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
expression.addSql(request);
}
request.append(listAndEnd);
return request.getSql();
}
@Override
public List<Object> buildBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionRequest request) {
for (int i = 0, size = list.size(); i < size; i++) {
SpiExpression expression = list.get(i);
expression.addBindValues(request);
list.get(i).addBindValues(request);
}
return request.getBindValues();
}
@Override
@@ -371,6 +368,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
/**
* Calculate a hash based on the expressions.
*/
@Override
public int queryBindHash() {
int hash = DefaultExpressionList.class.getName().hashCode();
for (int i = 0, size = list.size(); i < size; i++) {
@@ -379,6 +377,38 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return hash;
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof DefaultExpressionList)) {
return false;
}
DefaultExpressionList<?> that = (DefaultExpressionList<?>)other;
if (list.size() != that.list.size()) {
return false;
}
for (int i = 0, size = list.size(); i < size; i++) {
if (!list.get(i).isSameByPlan(that.list.get(i))) {
return false;
}
}
return true;
}
@Override
public boolean isSameByBind(SpiExpression other) {
DefaultExpressionList<?> that = (DefaultExpressionList<?>)other;
if (list.size() != that.list.size()) {
return false;
}
for (int i = 0, size = list.size(); i < size; i++) {
if (!list.get(i).isSameByBind(that.list.get(i))) {
return false;
}
}
return true;
}
/**
* Path exists - for the given path in a JSON document.
*/
@@ -1,4 +1,4 @@
package com.avaje.ebeaninternal.util;
package com.avaje.ebeaninternal.server.expression;
import java.sql.SQLException;
import java.util.ArrayList;
@@ -40,7 +40,7 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
this.binder = binder;
this.expressionList = expressionList;
// immediately build the list of bind values (callback style)
expressionList.buildBindValues(this);
expressionList.addBindValues(this);
}
public DefaultExpressionRequest(BeanDescriptor<?> beanDescriptor) {
@@ -55,7 +55,8 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
* Build sql for the underlying expression list.
*/
public String buildSql() {
return expressionList.buildSql(this);
expressionList.addSql(this);
return sql.toString();
}
/**
@@ -71,10 +72,12 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
}
}
@Override
public JsonExpressionHandler getJsonHandler() {
return binder.getJsonExpressionHandler();
}
@Override
public String parseDeploy(String logicalProp) {
String s = deployParser.getDeployWord(logicalProp);
@@ -94,14 +97,17 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
/**
* Increments the parameter index and returns that value.
*/
@Override
public int nextParameter() {
return ++paramIndex;
}
@Override
public BeanDescriptor<?> getBeanDescriptor() {
return beanDescriptor;
}
@Override
public SpiOrmQueryRequest<?> getQueryRequest() {
return queryRequest;
}
@@ -109,16 +115,19 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
/**
* Append text the underlying sql expression.
*/
@Override
public SpiExpressionRequest append(String sqlExpression) {
sql.append(sqlExpression);
return this;
}
@Override
public void addBindEncryptKey(Object bindValue) {
bindValues.add(bindValue);
bindLog("****");
}
@Override
public void addBindValue(Object bindValue) {
bindValues.add(bindValue);
bindLog(bindValue);
@@ -137,10 +146,12 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
return bindLog == null ? "" : bindLog.toString();
}
@Override
public String getSql() {
return sql.toString();
}
@Override
public List<Object> getBindValues() {
return bindValues;
}
@@ -17,19 +17,26 @@ public class ExistsExpression implements SpiExpression {
private static final long serialVersionUID = 666990277309851644L;
private final boolean not;
protected final boolean not;
private final SpiQuery<?> subQuery;
protected final SpiQuery<?> subQuery;
private List<Object> bindParams;
protected List<Object> bindParams;
private String sql;
protected String sql;
public ExistsExpression(SpiQuery<?> subQuery, boolean not) {
this.subQuery = subQuery;
this.not = not;
}
ExistsExpression(boolean not, String sql , List<Object> bindParams) {
this.not = not;
this.sql = sql;
this.bindParams = bindParams;
this.subQuery = null;
}
@Override
public void prepareExpression(BeanQueryRequest<?> request) {
@@ -38,10 +45,15 @@ public class ExistsExpression implements SpiExpression {
this.sql = subQuery.getGeneratedSql().replace('\n', ' ');
}
@Override
public SpiExpression copyForPlanKey() {
return this;
}
/**
* Compile/build the sub query.
*/
private CQuery<?> compileSubQuery(BeanQueryRequest<?> queryRequest) {
protected CQuery<?> compileSubQuery(BeanQueryRequest<?> queryRequest) {
SpiEbeanServer ebeanServer = (SpiEbeanServer) queryRequest.getEbeanServer();
return ebeanServer.compileQuery(subQuery, queryRequest.getTransaction());
}
@@ -76,6 +88,32 @@ public class ExistsExpression implements SpiExpression {
}
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof ExistsExpression)) {
return false;
}
ExistsExpression that = (ExistsExpression) other;
return this.sql.equals(that.sql)
&& this.not == that.not
&& this.bindParams.size() == that.bindParams.size();
}
@Override
public boolean isSameByBind(SpiExpression other) {
ExistsExpression that = (ExistsExpression) other;
if (this.bindParams.size() != that.bindParams.size()) {
return false;
}
for (int i = 0; i < bindParams.size(); i++) {
if (!bindParams.get(i).equals(that.bindParams.get(i))) {
return false;
}
}
return true;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins whereManyJoins) {
// Nothing to do for exists expression
@@ -1,8 +1,7 @@
package com.avaje.ebeaninternal.util;
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.*;
import com.avaje.ebeaninternal.api.SpiExpressionList;
import com.avaje.ebeaninternal.server.expression.FilterExprPath;
import javax.persistence.PersistenceException;
import java.util.List;
@@ -6,7 +6,6 @@ import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.util.DefaultExpressionRequest;
/**
* Slightly redundant as Query.setId() ultimately also does the same job.
@@ -69,4 +68,14 @@ class IdExpression extends NonPrepareExpression implements SpiExpression {
return value.hashCode();
}
@Override
public boolean isSameByPlan(SpiExpression other) {
return other instanceof IdExpression;
}
@Override
public boolean isSameByBind(SpiExpression other) {
IdExpression that = (IdExpression) other;
return value.equals(that.value);
}
}
@@ -2,11 +2,11 @@ package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.ManyWhereJoins;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
import com.avaje.ebeaninternal.util.DefaultExpressionRequest;
import java.util.List;
@@ -86,4 +86,27 @@ public class IdInExpression extends NonPrepareExpression {
return idList.hashCode();
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof IdInExpression)) {
return false;
}
IdInExpression that = (IdInExpression) other;
return this.idList.size() == that.idList.size();
}
@Override
public boolean isSameByBind(SpiExpression other) {
IdInExpression that = (IdInExpression) other;
if (this.idList.size() != that.idList.size()) {
return false;
}
for (int i = 0; i < idList.size(); i++) {
if (!idList.get(i).equals(that.idList.get(i))) {
return false;
}
}
return true;
}
}
@@ -1,8 +1,8 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
@@ -61,20 +61,18 @@ class InExpression extends AbstractExpression {
return;
}
String propertyName = getPropertyName();
ElPropertyValue prop = getElProp(request);
if (prop != null && !prop.isAssocId()) {
prop = null;
}
if (prop != null) {
request.append(prop.getAssocIdInExpr(propertyName));
request.append(prop.getAssocIdInExpr(propName));
String inClause = prop.getAssocIdInValueExpr(values.length);
request.append(inClause);
} else {
request.append(propertyName);
request.append(propName);
if (not) {
request.append(" not");
}
@@ -105,4 +103,29 @@ class InExpression extends AbstractExpression {
return hc;
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof InExpression)) {
return false;
}
InExpression that = (InExpression) other;
return propName.equals(that.propName)
&& not == that.not
&& values.length == that.values.length;
}
@Override
public boolean isSameByBind(SpiExpression other) {
InExpression that = (InExpression) other;
if (this.values.length != that.values.length) {
return false;
}
for (int i = 0; i < values.length; i++) {
if (!values[i].equals(that.values[i])) {
return false;
}
}
return true;
}
}
@@ -1,14 +1,15 @@
package com.avaje.ebeaninternal.server.expression;
import java.util.List;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.server.query.CQuery;
import java.util.List;
/**
* In expression using a sub query.
*/
@@ -24,12 +25,20 @@ class InQueryExpression extends AbstractExpression {
private String sql;
public InQueryExpression(String propertyName, SpiQuery<?> subQuery, boolean not) {
InQueryExpression(String propertyName, SpiQuery<?> subQuery, boolean not) {
super(propertyName);
this.subQuery = subQuery;
this.not = not;
}
InQueryExpression(String propertyName, boolean not, String sql, List<Object> bindParams) {
super(propertyName);
this.subQuery = null;
this.not = not;
this.sql = sql;
this.bindParams = bindParams;
}
@Override
public void prepareExpression(BeanQueryRequest<?> request) {
@@ -61,7 +70,7 @@ class InQueryExpression extends AbstractExpression {
@Override
public void addSql(SpiExpressionRequest request) {
request.append(" (").append(getPropertyName()).append(")");
request.append(" (").append(propName).append(")");
if (not) {
request.append(" not");
}
@@ -77,4 +86,31 @@ class InQueryExpression extends AbstractExpression {
request.addBindValue(bindParams.get(i));
}
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof InQueryExpression)) {
return false;
}
InQueryExpression that = (InQueryExpression) other;
return propName.equals(that.propName)
&& sql.equals(that.sql)
&& not == that.not
&& bindParams.size() == that.bindParams.size();
}
@Override
public boolean isSameByBind(SpiExpression other) {
InQueryExpression that = (InQueryExpression) other;
if (this.bindParams.size() != that.bindParams.size()) {
return false;
}
for (int i = 0; i < bindParams.size(); i++) {
if (!bindParams.get(i).equals(that.bindParams.get(i))) {
return false;
}
}
return true;
}
}
@@ -1,7 +1,7 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
/**
@@ -60,6 +60,8 @@ class JsonPathExpression extends AbstractExpression {
@Override
public void queryPlanHash(HashQueryPlanBuilder builder) {
builder.add(JsonPathExpression.class).add(propName).add(path).add(operator);
builder.bindIfNotNull(value);
builder.bindIfNotNull(upperValue);
}
@Override
@@ -69,6 +71,27 @@ class JsonPathExpression extends AbstractExpression {
return hc;
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof JsonPathExpression)) {
return false;
}
JsonPathExpression that = (JsonPathExpression) other;
return propName.equals(that.propName)
&& operator == that.operator
&& Same.sameByValue(path, that.path)
&& Same.sameByNull(value, that.value)
&& Same.sameByNull(upperValue, that.upperValue);
}
@Override
public boolean isSameByBind(SpiExpression other) {
JsonPathExpression that = (JsonPathExpression) other;
if (value != null ? !value.equals(that.value) : that.value != null) return false;
return upperValue != null ? upperValue.equals(that.upperValue) : that.upperValue == null;
}
@Override
public void addSql(SpiExpressionRequest request) {
@@ -15,7 +15,6 @@ import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.util.DefaultExpressionList;
/**
* Junction implementation.
@@ -35,6 +34,14 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
Conjunction(com.avaje.ebean.Query<T> query, ExpressionList<T> parent) {
super(false, AND, query, parent);
}
Conjunction(DefaultExpressionList<T> expressionList) {
super(false, AND, expressionList);
}
@Override
public SpiExpression copyForPlanKey() {
return new Conjunction<T>(exprList.copyForPlanKey());
}
}
static class Disjunction<T> extends JunctionExpression<T> {
@@ -44,9 +51,18 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
Disjunction(com.avaje.ebean.Query<T> query, ExpressionList<T> parent) {
super(true, OR, query, parent);
}
Disjunction(DefaultExpressionList<T> expressionList) {
super(true, OR, expressionList);
}
@Override
public SpiExpression copyForPlanKey() {
return new Disjunction<T>(exprList.copyForPlanKey());
}
}
private final DefaultExpressionList<T> exprList;
protected final DefaultExpressionList<T> exprList;
private final String joinType;
@@ -61,6 +77,15 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
this.exprList = new DefaultExpressionList<T>(query, parent);
}
/**
* Construct for copyForPlanKey.
*/
JunctionExpression(boolean disjunction, String joinType, DefaultExpressionList<T> exprList) {
this.disjunction = disjunction;
this.joinType = joinType;
this.exprList = exprList;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
@@ -163,6 +188,25 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
return hc;
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof JunctionExpression)) {
return false;
}
JunctionExpression that = (JunctionExpression) other;
return joinType.equals(that.joinType)
&& exprList.isSameByPlan(that.exprList);
}
@Override
public boolean isSameByBind(SpiExpression other) {
JunctionExpression that = (JunctionExpression) other;
return joinType.equals(that.joinType)
&& exprList.isSameByBind(that.exprList);
}
@Override
public ExpressionList<T> endJunction() {
return exprList.endJunction();
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.LikeType;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
@@ -22,6 +23,7 @@ class LikeExpression extends AbstractExpression {
this.val = value;
}
@Override
public void addBindValues(SpiExpressionRequest request) {
ElPropertyValue prop = getElProp(request);
@@ -35,14 +37,13 @@ class LikeExpression extends AbstractExpression {
request.addBindValue(bindValue);
}
@Override
public void addSql(SpiExpressionRequest request) {
String propertyName = getPropertyName();
String pname = propertyName;
String pname = propName;
ElPropertyValue prop = getElProp(request);
if (prop != null && prop.isDbEncrypted()) {
pname = prop.getBeanProperty().getDecryptProperty(propertyName);
pname = prop.getBeanProperty().getDecryptProperty(propName);
}
if (caseInsensitive) {
request.append("lower(").append(pname).append(")");
@@ -71,6 +72,24 @@ class LikeExpression extends AbstractExpression {
return val.hashCode();
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof LikeExpression)) {
return false;
}
LikeExpression that = (LikeExpression) other;
return this.propName.equals(that.propName)
&& this.caseInsensitive == that.caseInsensitive
&& this.type == that.type;
}
@Override
public boolean isSameByBind(SpiExpression other) {
LikeExpression that = (LikeExpression) other;
return val.equals(that.val);
}
private static String getValue(String value, boolean caseInsensitive, LikeType type) {
if (caseInsensitive) {
value = value.toLowerCase();
@@ -26,6 +26,12 @@ abstract class LogicExpression implements SpiExpression {
And(Expression expOne, Expression expTwo) {
super(AND, expOne, expTwo);
}
@Override
public SpiExpression copyForPlanKey() {
return new And(expOne.copyForPlanKey(), expTwo.copyForPlanKey());
}
}
static class Or extends LogicExpression {
@@ -35,11 +41,16 @@ abstract class LogicExpression implements SpiExpression {
Or(Expression expOne, Expression expTwo) {
super(OR, expOne, expTwo);
}
@Override
public SpiExpression copyForPlanKey() {
return new Or(expOne.copyForPlanKey(), expTwo.copyForPlanKey());
}
}
private final SpiExpression expOne;
protected final SpiExpression expOne;
private final SpiExpression expTwo;
protected final SpiExpression expTwo;
private final String joinType;
@@ -49,6 +60,7 @@ abstract class LogicExpression implements SpiExpression {
this.expTwo = (SpiExpression) expTwo;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
expOne.containsMany(desc, manyWhereJoin);
expTwo.containsMany(desc, manyWhereJoin);
@@ -60,11 +72,13 @@ abstract class LogicExpression implements SpiExpression {
expTwo.validate(validation);
}
@Override
public void addBindValues(SpiExpressionRequest request) {
expOne.addBindValues(request);
expTwo.addBindValues(request);
}
@Override
public void addSql(SpiExpressionRequest request) {
request.append("(");
@@ -83,16 +97,38 @@ abstract class LogicExpression implements SpiExpression {
/**
* Based on the joinType plus the two expressions.
*/
@Override
public void queryPlanHash(HashQueryPlanBuilder builder) {
builder.add(LogicExpression.class).add(joinType);
expOne.queryPlanHash(builder);
expTwo.queryPlanHash(builder);
}
@Override
public int queryBindHash() {
int hc = expOne.queryBindHash();
hc = hc * 31 + expTwo.queryBindHash();
return hc;
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof LogicExpression)) {
return false;
}
LogicExpression that = (LogicExpression) other;
return this.joinType.equals(that.joinType)
&& this.expOne.isSameByPlan(that.expOne)
&& this.expTwo.isSameByPlan(that.expTwo);
}
@Override
public boolean isSameByBind(SpiExpression other) {
LogicExpression that = (LogicExpression) other;
return this.expOne.isSameByBind(that.expOne)
&& this.expTwo.isSameByBind(that.expTwo);
}
}
@@ -12,4 +12,9 @@ abstract class NonPrepareExpression implements SpiExpression {
public void prepareExpression(BeanQueryRequest<?> request) {
// do nothing
}
@Override
public SpiExpression copyForPlanKey() {
return this;
}
}
@@ -15,6 +15,11 @@ class NoopExpression implements SpiExpression {
protected static final NoopExpression INSTANCE = new NoopExpression();
@Override
public SpiExpression copyForPlanKey() {
return this;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins whereManyJoins) {
// nothing to do
@@ -50,4 +55,14 @@ class NoopExpression implements SpiExpression {
public void addBindValues(SpiExpressionRequest request) {
// nothing to do
}
@Override
public boolean isSameByPlan(SpiExpression other) {
return other instanceof NoopExpression;
}
@Override
public boolean isSameByBind(SpiExpression other) {
return true;
}
}
@@ -13,7 +13,8 @@ final class NotExpression implements SpiExpression {
private static final long serialVersionUID = 5648926732402355781L;
private static final String NOT = "not (";
private static final String NOT_START = "not (";
private static final String NOT_END = ") ";
private final SpiExpression exp;
@@ -21,6 +22,12 @@ final class NotExpression implements SpiExpression {
this.exp = (SpiExpression) exp;
}
@Override
public SpiExpression copyForPlanKey() {
return new NotExpression(exp.copyForPlanKey());
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
exp.containsMany(desc, manyWhereJoin);
}
@@ -30,14 +37,16 @@ final class NotExpression implements SpiExpression {
exp.validate(validation);
}
@Override
public void addBindValues(SpiExpressionRequest request) {
exp.addBindValues(request);
}
@Override
public void addSql(SpiExpressionRequest request) {
request.append(NOT);
request.append(NOT_START);
exp.addSql(request);
request.append(") ");
request.append(NOT_END);
}
@Override
@@ -54,8 +63,23 @@ final class NotExpression implements SpiExpression {
exp.queryPlanHash(builder);
}
@Override
public int queryBindHash() {
return exp.queryBindHash();
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof NotExpression)) {
return false;
}
NotExpression that = (NotExpression) other;
return exp.isSameByPlan(that.exp);
}
@Override
public boolean isSameByBind(SpiExpression other) {
NotExpression that = (NotExpression) other;
return exp.isSameByBind(that.exp);
}
}
@@ -1,7 +1,7 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
@@ -28,7 +28,7 @@ class NullExpression extends AbstractExpression {
@Override
public void addSql(SpiExpressionRequest request) {
String propertyName = getPropertyName();
String propertyName = propName;
String nullExpr = notNull ? " is not null " : " is null ";
@@ -41,6 +41,23 @@ class NullExpression extends AbstractExpression {
request.append(propertyName).append(nullExpr);
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof NullExpression)) {
return false;
}
NullExpression that = (NullExpression) other;
return this.propName.equals(that.propName)
&& this.notNull == that.notNull;
}
@Override
public boolean isSameByBind(SpiExpression other) {
// no bind values so always true
return true;
}
/**
* Based on notNull flag and the propertyName.
*/
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.ManyWhereJoins;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
@@ -55,4 +56,31 @@ class RawExpression extends NonPrepareExpression {
public int queryBindHash() {
return sql.hashCode();
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof RawExpression)) {
return false;
}
RawExpression that = (RawExpression) other;
return sql.equals(that.sql);
}
@Override
public boolean isSameByBind(SpiExpression other) {
if (!(other instanceof RawExpression)) {
return false;
}
RawExpression that = (RawExpression) other;
if (values.length != that.values.length) {
return false;
}
for (int i = 0; i < values.length; i++) {
if (!Same.sameByValue(values[i], that.values[i])) {
return false;
}
}
return true;
}
}
@@ -0,0 +1,33 @@
package com.avaje.ebeaninternal.server.expression;
/**
* Utility to help isSame methods.
*/
public class Same {
/**
* Return true if both values are null or both an not null.
*/
public static boolean sameByNull(Object v1, Object v2) {
return v1 == null ? v2 == null : v2 != null;
}
/**
* Null safe equals check.
*/
public static boolean sameByValue(Object v1, Object v2) {
return v1 == null ? v2 == null : v1.equals(v2);
}
/**
* Null safe check by sameByValue or sameByNull based on byValue.
*/
public static boolean sameBy(boolean byValue, Object value, Object value1) {
if (byValue) {
return sameByValue(value, value1);
} else {
return sameByNull(value, value1);
}
}
}
@@ -1,8 +1,8 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
@@ -20,17 +20,25 @@ public class SimpleExpression extends AbstractExpression {
this.value = value;
}
public final String getPropName() {
return propName;
}
public boolean isOpEquals() {
return Op.EQ.equals(type);
}
public Object getValue() {
return value;
}
@Override
public void addBindValues(SpiExpressionRequest request) {
ElPropertyValue prop = getElProp(request);
if (prop != null) {
if (prop.isAssocId()) {
Object[] ids = prop.getAssocOneIdValues((EntityBean)value);
Object[] ids = prop.getAssocOneIdValues((EntityBean) value);
if (ids != null) {
for (int i = 0; i < ids.length; i++) {
request.addBindValue(ids[i]);
@@ -54,12 +62,10 @@ public class SimpleExpression extends AbstractExpression {
@Override
public void addSql(SpiExpressionRequest request) {
String propertyName = getPropertyName();
ElPropertyValue prop = getElProp(request);
if (prop != null) {
if (prop.isAssocId()) {
request.append(prop.getAssocOneIdExpr(propertyName, type.bind()));
request.append(prop.getAssocOneIdExpr(propName, type.bind()));
return;
}
if (prop.isDbEncrypted()) {
@@ -68,7 +74,7 @@ public class SimpleExpression extends AbstractExpression {
return;
}
}
request.append(propertyName).append(type.bind());
request.append(propName).append(type.bind());
}
/**
@@ -85,8 +91,20 @@ public class SimpleExpression extends AbstractExpression {
return value.hashCode();
}
public Object getValue() {
return value;
@Override
public boolean isSameByPlan(SpiExpression other) {
if (!(other instanceof SimpleExpression)) {
return false;
}
SimpleExpression that = (SimpleExpression) other;
return this.propName.equals(that.propName)
&& this.type == that.type;
}
@Override
public boolean isSameByBind(SpiExpression other) {
SimpleExpression that = (SimpleExpression) other;
return value.equals(that.value);
}
}
@@ -1,13 +1,8 @@
package com.avaje.ebeaninternal.server.query;
import java.security.MessageDigest;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.avaje.ebean.bean.ObjectGraphNode;
import com.avaje.ebean.config.dbplatform.SqlLimitResponse;
import com.avaje.ebeaninternal.api.HashQueryPlan;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.CQueryPlanKey;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
@@ -18,6 +13,10 @@ import com.avaje.ebeaninternal.server.type.RsetDataReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.MessageDigest;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Represents a query for a given SQL statement.
* <p>
@@ -45,7 +44,7 @@ public class CQueryPlan {
private final boolean autoTuned;
private final HashQueryPlan hash;
private final CQueryPlanKey planKey;
private final boolean rawSql;
@@ -79,7 +78,7 @@ public class CQueryPlan {
this.server = request.getServer();
this.beanType = request.getBeanDescriptor().getBeanType();
this.stats = new CQueryPlanStats(this, server.isCollectQueryOrigins());
this.hash = request.getQueryPlanHash();
this.planKey = request.getQueryPlanKey();
this.autoTuned = request.getQuery().isAutoTuned();
if (sqlRes != null) {
this.sql = sqlRes.getSql();
@@ -103,7 +102,7 @@ public class CQueryPlan {
this.server = request.getServer();
this.beanType = request.getBeanDescriptor().getBeanType();
this.stats = new CQueryPlanStats(this, server.isCollectQueryOrigins());
this.hash = buildHash(sql, rawSql, rowNumberIncluded, logWhereSql);
this.planKey = buildPlanKey(sql, rawSql, rowNumberIncluded, logWhereSql);
this.autoTuned = false;
this.sql = sql;
this.sqlTree = sqlTree;
@@ -114,15 +113,13 @@ public class CQueryPlan {
}
private HashQueryPlan buildHash(String sql, boolean rawSql, boolean rowNumberIncluded, String logWhereSql) {
HashQueryPlanBuilder builder = new HashQueryPlanBuilder();
builder.add(sql).add(rawSql).add(rowNumberIncluded).add(logWhereSql);
builder.addRawSql(sql);
return builder.build();
private CQueryPlanKey buildPlanKey(String sql, boolean rawSql, boolean rowNumberIncluded, String logWhereSql) {
return new RawSqlQueryPlanKey(sql, rawSql, rowNumberIncluded, logWhereSql);
}
public String toString() {
return beanType + " hash:" + hash;
return beanType + " hash:" + planKey;
}
public Class<?> getBeanType() {
@@ -147,8 +144,8 @@ public class CQueryPlan {
return autoTuned;
}
public HashQueryPlan getHash() {
return hash;
public CQueryPlanKey getPlanKey() {
return planKey;
}
/**
@@ -164,7 +161,7 @@ public class CQueryPlan {
private String calcAuditQueryKey() {
// rawSql needs to include the MD5 hash of the sql
return rawSql ? hash.getPartialKey() + "_" + getSqlMd5Hash() : hash.getPartialKey();
return rawSql ? planKey.getPartialKey() + "_" + getSqlMd5Hash() : planKey.getPartialKey();
}
/**
@@ -233,7 +233,7 @@ public final class CQueryPlanStats {
@Override
public String getQueryPlanHash() {
return queryPlan.getHash().toString();
return queryPlan.getPlanKey().toString();
}
@Override
@@ -13,7 +13,7 @@ import com.avaje.ebeaninternal.server.persist.Binder;
import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
import com.avaje.ebeaninternal.server.type.DataBind;
import com.avaje.ebeaninternal.server.util.BindParamsParser;
import com.avaje.ebeaninternal.util.DefaultExpressionRequest;
import com.avaje.ebeaninternal.server.expression.DefaultExpressionRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -0,0 +1,56 @@
package com.avaje.ebeaninternal.server.query;
import com.avaje.ebeaninternal.api.CQueryPlanKey;
/**
* QueryPlanKey for RawSql queries.
*/
public class RawSqlQueryPlanKey implements CQueryPlanKey {
private final String sql;
private final boolean rawSql;
private final boolean rowNumberIncluded;
private final String logWhereSql;
public RawSqlQueryPlanKey(String sql, boolean rawSql, boolean rowNumberIncluded, String logWhereSql) {
this.sql = sql;
this.rawSql = rawSql;
this.rowNumberIncluded = rowNumberIncluded;
this.logWhereSql = logWhereSql;
}
public String toString() {
return getPartialKey() + ":r";
}
/**
* Return as a partial key. For rawSql hash the sql is part of the key and as such
* needs to be included in order to have a complete key. Typically the MD5 of the sql
* can be used as a short form proxy for the actual sql.
*/
public String getPartialKey() {
return hashCode() + "_0";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RawSqlQueryPlanKey that = (RawSqlQueryPlanKey) o;
if (rawSql != that.rawSql) return false;
if (rowNumberIncluded != that.rowNumberIncluded) return false;
if (!sql.equals(that.sql)) return false;
return logWhereSql != null ? logWhereSql.equals(that.logWhereSql) : that.logWhereSql == null;
}
@Override
public int hashCode() {
int result = sql.hashCode();
result = 31 * result + (rawSql ? 1 : 0);
result = 31 * result + (rowNumberIncluded ? 1 : 0);
result = 31 * result + logWhereSql.hashCode();
return result;
}
}
@@ -13,9 +13,8 @@ import com.avaje.ebean.plugin.SpiBeanType;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebeaninternal.api.BindParams;
import com.avaje.ebeaninternal.api.HashQuery;
import com.avaje.ebeaninternal.api.HashQueryPlan;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.ManyWhereJoins;
import com.avaje.ebeaninternal.api.CQueryPlanKey;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionList;
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
@@ -28,7 +27,7 @@ import com.avaje.ebeaninternal.server.deploy.DeployNamedQuery;
import com.avaje.ebeaninternal.server.deploy.TableJoin;
import com.avaje.ebeaninternal.server.expression.SimpleExpression;
import com.avaje.ebeaninternal.server.query.CancelableQuery;
import com.avaje.ebeaninternal.util.DefaultExpressionList;
import com.avaje.ebeaninternal.server.expression.DefaultExpressionList;
import javax.persistence.PersistenceException;
import java.sql.Timestamp;
@@ -234,7 +233,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
/**
* Hash of final query after AutoTune tuning.
*/
private HashQueryPlan queryPlanHash;
private CQueryPlanKey queryPlanKey;
private transient PersistenceContext persistenceContext;
@@ -493,7 +492,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
if (se instanceof SimpleExpression) {
SimpleExpression e = (SimpleExpression) se;
if (e.isOpEquals()) {
return new NaturalKeyBindParam(e.getPropertyName(), e.getValue());
return new NaturalKeyBindParam(e.getPropName(), e.getValue());
}
}
}
@@ -759,55 +758,34 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
/**
* Calculate the query hash for either AutoTune query tuning or Query Plan caching.
*/
HashQueryPlan calculateQueryPlanHash() {
// exclude bind values and things unrelated to the sql being generated
HashQueryPlanBuilder builder = new HashQueryPlanBuilder();
builder.add((type == null ? 0 : type.ordinal() + 1));
builder.add(autoTuned).add(distinct).add(sqlDistinct).add(query);
builder.add(firstRow).add(maxRows).add(orderBy).add(forUpdate);
builder.add(rawWhereClause).add(additionalWhere).add(additionalHaving);
builder.add(mapKey);
builder.add(disableLazyLoading);
builder.add(id != null);
builder.add(temporalMode);
builder.add(rawSql == null ? 0 : rawSql.queryHash());
builder.add(includeTableJoin != null ? includeTableJoin.queryHash() : 0);
builder.add(rootTableAlias);
if (detail != null) {
detail.queryPlanHash(builder);
}
if (bindParams != null) {
bindParams.buildQueryPlanHash(builder);
}
CQueryPlanKey createQueryPlanKey() {
DefaultExpressionList<T> where = null;
DefaultExpressionList<T> having = null;
if (whereExpressions != null) {
whereExpressions.queryPlanHash(builder);
where = whereExpressions.copyForPlanKey();
}
if (havingExpressions != null) {
havingExpressions.queryPlanHash(builder);
having = havingExpressions.copyForPlanKey();
}
return builder.build();
queryPlanKey = new OrmQueryPlanKey(includeTableJoin, type, detail, maxRows, firstRow,
disableLazyLoading, rawWhereClause, orderBy, query, additionalWhere, additionalHaving,
distinct, sqlDistinct, mapKey, id, bindParams, where, having,
temporalMode, forUpdate, rootTableAlias, rawSql);
return queryPlanKey;
}
/**
* Calculate a hash that should be unique for the generated SQL across a given bean type.
* <p>
* This can used to enable the caching and reuse of a 'query plan'.
* </p>
* <p>
* This is calculated AFTER AutoTune query tuning has occurred.
* </p>
* Prepare the query which prepares any expressions (sub-query expressions etc) and calculates the query plan key.
*/
public HashQueryPlan queryPlanHash(BeanQueryRequest<?> request) {
public CQueryPlanKey prepare(BeanQueryRequest<?> request) {
prepareExpressions(request);
queryPlanHash = calculateQueryPlanHash();
return queryPlanHash;
queryPlanKey = createQueryPlanKey();
return queryPlanKey;
}
/**
@@ -852,7 +830,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
// so queryPlanHash is calculated well before this method is called
int hc = queryBindHash();
return new HashQuery(queryPlanHash, hc);
return new HashQuery(queryPlanKey, hc);
}
/**
@@ -0,0 +1,149 @@
package com.avaje.ebeaninternal.server.querydefn;
import com.avaje.ebean.OrderBy;
import com.avaje.ebean.RawSql;
import com.avaje.ebeaninternal.api.BindParams;
import com.avaje.ebeaninternal.api.CQueryPlanKey;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.server.deploy.TableJoin;
/**
* Query plan key for ORM queries.
*/
public class OrmQueryPlanKey implements CQueryPlanKey {
private final TableJoin includeTableJoin;
private final String orderByAsSting;
private final OrmQueryDetail detail;
private final BindParams bindParams;
private final SpiExpression whereExpressions;
private final SpiExpression havingExpressions;
private final RawSql rawSql;
private final boolean hasIdValue;
private final SpiQuery.Type type;
private final int maxRows;
private final int firstRow;
private final boolean disableLazyLoading;
private final String rawWhereClause;
private final String query;
private final String additionalWhere;
private final String additionalHaving;
private final boolean distinct;
private final boolean sqlDistinct;
private final String mapKey;
private final SpiQuery.TemporalMode temporalMode;
private final boolean forUpdate;
private final String rootTableAlias;
private final int planHash;
private final int bindCount;
public OrmQueryPlanKey(TableJoin includeTableJoin, SpiQuery.Type type, OrmQueryDetail detail, int maxRows, int firstRow, boolean disableLazyLoading, String rawWhereClause, OrderBy<?> orderBy, String query, String additionalWhere, String additionalHaving, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams, SpiExpression whereExpressions, SpiExpression havingExpressions, SpiQuery.TemporalMode temporalMode, boolean forUpdate, String rootTableAlias, RawSql rawSql) {
this.includeTableJoin = includeTableJoin;
this.type = type;
this.detail = detail;
this.maxRows = maxRows;
this.firstRow = firstRow;
this.disableLazyLoading = disableLazyLoading;
this.rawWhereClause = rawWhereClause;
this.orderByAsSting = (orderBy == null) ? null : orderBy.toStringFormat();
this.query = query;
this.additionalWhere = additionalWhere;
this.additionalHaving = additionalHaving;
this.distinct = distinct;
this.sqlDistinct = sqlDistinct;
this.mapKey = mapKey;
this.hasIdValue = (id != null);
this.bindParams = bindParams;
this.whereExpressions = whereExpressions;
this.havingExpressions = havingExpressions;
this.temporalMode = temporalMode;
this.forUpdate = forUpdate;
this.rootTableAlias = rootTableAlias;
this.rawSql = rawSql;
// exclude bind values and things unrelated to the sql being generated
HashQueryPlanBuilder builder = new HashQueryPlanBuilder();
builder.add((type == null ? 0 : type.ordinal() + 1));
builder.add(distinct).add(sqlDistinct).add(query);
builder.add(firstRow).add(maxRows);
builder.add(orderBy).add(forUpdate);
builder.add(rawWhereClause).add(additionalWhere).add(additionalHaving);
builder.add(mapKey);
builder.add(disableLazyLoading);
builder.add(hasIdValue);
builder.add(temporalMode);
builder.add(rawSql == null ? 0 : rawSql.queryHash());
builder.add(includeTableJoin != null ? includeTableJoin.queryHash() : 0);
builder.add(rootTableAlias);
if (detail != null) {
detail.queryPlanHash(builder);
}
if (bindParams != null) {
bindParams.buildQueryPlanHash(builder);
}
if (whereExpressions != null) {
whereExpressions.queryPlanHash(builder);
}
if (havingExpressions != null) {
havingExpressions.queryPlanHash(builder);
}
this.planHash = builder.getPlanHash();
this.bindCount = builder.getBindCount();
}
@Override
public String getPartialKey() {
return planHash + "_" + bindCount;
}
@Override
public int hashCode() {
return planHash;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OrmQueryPlanKey that = (OrmQueryPlanKey) o;
if (planHash != that.planHash) return false;
if (bindCount != that.bindCount) return false;
if (maxRows != that.maxRows) return false;
if (firstRow != that.firstRow) return false;
if (disableLazyLoading != that.disableLazyLoading) return false;
if (distinct != that.distinct) return false;
if (sqlDistinct != that.sqlDistinct) return false;
if (forUpdate != that.forUpdate) return false;
if (hasIdValue != that.hasIdValue) return false;
if (type != that.type) return false;
if (temporalMode != that.temporalMode) return false;
if (includeTableJoin != null ? !includeTableJoin.equals(that.includeTableJoin) : that.includeTableJoin != null) return false;
if (orderByAsSting != null ? !orderByAsSting.equals(that.orderByAsSting) : that.orderByAsSting != null) return false;
if (whereExpressions != null ? !whereExpressions.isSameByPlan(that.whereExpressions) : that.whereExpressions != null) return false;
if (havingExpressions != null ? !havingExpressions.isSameByPlan(that.havingExpressions) : that.havingExpressions != null) return false;
// if (detail != null ? !detail.equals(that.detail) : that.detail != null) return false;
// if (bindParams != null ? !bindParams.equals(that.bindParams) : that.bindParams != null) return false;
// if (rawSql != null ? !rawSql.equals(that.rawSql) : that.rawSql != null) return false;
if (rawWhereClause != null ? !rawWhereClause.equals(that.rawWhereClause) : that.rawWhereClause != null) return false;
if (query != null ? !query.equals(that.query) : that.query != null) return false;
if (additionalWhere != null ? !additionalWhere.equals(that.additionalWhere) : that.additionalWhere != null) return false;
if (additionalHaving != null ? !additionalHaving.equals(that.additionalHaving) : that.additionalHaving != null) return false;
if (mapKey != null ? !mapKey.equals(that.mapKey) : that.mapKey != null) return false;
return rootTableAlias != null ? rootTableAlias.equals(that.rootTableAlias) : that.rootTableAlias == null;
}
}
@@ -12,7 +12,7 @@ import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.server.expression.FilterExprPath;
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
import com.avaje.ebeaninternal.server.query.SplitName;
import com.avaje.ebeaninternal.util.FilterExpressionList;
import com.avaje.ebeaninternal.server.expression.FilterExpressionList;
import java.io.Serializable;
import java.util.ArrayList;
@@ -1,6 +1,7 @@
package com.avaje.ebean;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import org.avaje.agentloader.AgentLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -29,4 +30,16 @@ public class BaseTestCase {
SpiEbeanServer spi = (SpiEbeanServer)Ebean.getDefaultServer();
return spi.getDatabasePlatform().getName().equals("h2");
}
protected <T> BeanDescriptor<T> getBeanDescriptor(Class<T> cls) {
return spiEbeanServer().getBeanDescriptor(cls);
}
protected SpiEbeanServer spiEbeanServer() {
return (SpiEbeanServer) Ebean.getDefaultServer();
}
protected EbeanServer server() {
return Ebean.getDefaultServer();
}
}
@@ -0,0 +1,49 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class TableJoinColumnTest {
TableJoinColumn col(String localDbColumn, String foreignDbColumn, boolean insertable, boolean updateable) {
DeployTableJoinColumn column = new DeployTableJoinColumn(localDbColumn, foreignDbColumn, insertable, updateable);
return new TableJoinColumn(column);
}
@Test
public void equals_when_same() {
assertSame(col("a", "b", true, true), col("a", "b", true, true));
}
@Test
public void equals_when_diffFirstCol() {
assertDifferent(col("a", "b", true, true), col("c", "b", true, true));
}
@Test
public void equals_when_diffSecondCol() {
assertDifferent(col("a", "b", true, true), col("a", "c", true, true));
}
@Test
public void equals_when_diffInsertable() {
assertDifferent(col("a", "b", true, true), col("a", "b", false, true));
}
@Test
public void equals_when_diffUpdateable() {
assertDifferent(col("a", "b", true, true), col("a", "b", true, false));
}
private void assertDifferent(TableJoinColumn col, TableJoinColumn col2) {
assertThat(col).isNotEqualTo(col2);
assertThat(col.hashCode()).isNotEqualTo(col2.hashCode());
}
private void assertSame(TableJoinColumn col, TableJoinColumn col2) {
assertThat(col).isEqualTo(col2);
assertThat(col.hashCode()).isEqualTo(col2.hashCode());
}
}
@@ -0,0 +1,67 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class TableJoinTest {
DeployTableJoinColumn col(String localDbColumn, String foreignDbColumn, boolean insertable, boolean updateable) {
return new DeployTableJoinColumn(localDbColumn, foreignDbColumn, insertable, updateable);
}
TableJoin table(String tableName, String col1, String col2) {
DeployTableJoin deploy = new DeployTableJoin();
deploy.setTable(tableName);
deploy.addJoinColumn(col(col1, col2, true, true));
return new TableJoin(deploy);
}
TableJoin table(String tableName, String col1, String col2, String col3, String col4) {
DeployTableJoin deploy = new DeployTableJoin();
deploy.setTable(tableName);
deploy.addJoinColumn(col(col1, col2, true, true));
deploy.addJoinColumn(col(col3, col4, true, true));
return new TableJoin(deploy);
}
@Test
public void equals_when_same() {
assertSame(table("myTable", "a", "b"), table("myTable", "a", "b"));
}
@Test
public void equals_when_diffTable() {
assertDifferent(table("myTable", "a", "b"), table("diffTable", "a", "b"));
}
@Test
public void equals_when_diffColumn() {
assertDifferent(table("myTable", "a", "b"), table("myTable", "c", "b"));
}
@Test
public void equals_when_moreColumns() {
assertDifferent(table("myTable", "a", "b"), table("myTable", "a", "b", "c", "d"));
}
@Test
public void equals_when_lessColumns() {
assertDifferent(table("myTable", "a", "b", "c", "d"), table("myTable", "a", "b"));
}
void assertSame(TableJoin join1, TableJoin join2) {
assertThat(join1).isEqualTo(join1);
assertThat(join1.hashCode()).isEqualTo(join1.hashCode());
}
void assertDifferent(TableJoin join1, TableJoin join2) {
assertThat(join1).isNotEqualTo(join2);
assertThat(join1.hashCode()).isNotEqualTo(join2.hashCode());
}
}
@@ -0,0 +1,118 @@
package com.avaje.ebeaninternal.server.expression;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.util.LinkedHashMap;
import java.util.Map;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class AllEqualsExpressionTest {
@Test
public void isSameByPlan_when_same() {
assertThat(exp("a", 10).isSameByPlan(exp("a", 10))).isTrue();
}
@Test
public void isSameByBind_when_sameMultiple() {
assertThat(exp("a", 10, "b", "23").isSameByBind(exp("a", 10, "b", "23"))).isTrue();
}
@Test
public void isSameByPlan_when_diffBindValue() {
assertThat(exp("a", 10).isSameByPlan(exp("a", 20))).isTrue();
}
@Test
public void isSameByPlan_when_multiple() {
assertThat(exp("a", 10, "b", 20, "c", 30).isSameByPlan(exp("a", 10, "b", 20, "c", 30))).isTrue();
}
@Test
public void isSameByPlan_when_less() {
assertThat(exp("a", 10, "b", 20, "c", 30).isSameByPlan(exp("a", 10, "b", 20))).isFalse();
}
@Test
public void isSameByPlan_when_more() {
assertThat(exp("a", 10, "b", 20).isSameByPlan(exp("a", 10, "b", 20, "c", 30))).isFalse();
}
@Test
public void isSameByPlan_when_diffProperty_diff() {
assertThat(exp("a", 10).isSameByPlan(exp("b", 10))).isFalse();
}
@Test
public void isSameByPlan_when_diffType_diff() {
assertThat(exp("a", 10).isSameByPlan(new NoopExpression())).isFalse();
}
@Test
public void isSameByPlan_when_diffBindByNull_last() {
assertThat(exp("a", 10).isSameByPlan(exp("a", null))).isFalse();
}
@Test
public void isSameByPlan_when_diffBindByNull_first() {
assertThat(exp("a", null).isSameByPlan(exp("a", 10))).isFalse();
}
@Test
public void isSameByPlan_when_differentExpressionType() {
assertThat(exp("a", null).isSameByPlan(new NoopExpression())).isFalse();
}
@Test
public void isSameByBind_when_diffBindByNull_last() {
assertThat(exp("a", 10).isSameByBind(exp("a", null))).isFalse();
}
@Test
public void isSameByBind_when_diffBindByNull_first() {
assertThat(exp("a", null).isSameByBind(exp("a", 10))).isFalse();
}
@NotNull
private AllEqualsExpression exp(Map<String, Object> propMap) {
return new AllEqualsExpression(propMap);
}
AllEqualsExpression exp(String key0, Object val1) {
LinkedHashMap<String,Object> map = new LinkedHashMap<String,Object>();
map.put(key0, val1);
return exp(map);
}
AllEqualsExpression exp(String key0, Object val1, String key2, Object val2) {
LinkedHashMap<String,Object> map = new LinkedHashMap<String,Object>();
map.put(key0, val1);
map.put(key2, val2);
return exp(map);
}
AllEqualsExpression exp(String key0, Object val1, String key2, Object val2, String key3, Object val3) {
LinkedHashMap<String,Object> map = new LinkedHashMap<String,Object>();
map.put(key0, val1);
map.put(key2, val2);
map.put(key3, val3);
return exp(map);
}
}
@@ -0,0 +1,13 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.tests.model.basic.Order;
public abstract class BaseExpressionTest extends BaseTestCase {
protected DefaultExpressionRequest newExpressionRequest() {
BeanDescriptor<Order> desc = getBeanDescriptor(Order.class);
return new DefaultExpressionRequest(desc);
}
}
@@ -0,0 +1,69 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebeaninternal.api.SpiExpression;
import org.junit.Test;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class BetweenExpressionTest extends BaseExpressionTest {
@Test
public void addSql() throws Exception {
DefaultExpressionRequest expReq = newExpressionRequest();
BetweenExpression exp = new BetweenExpression("startDate", 1, 2);
exp.addSql(expReq);
assertThat(expReq.getSql()).isEqualTo("startDate between ? and ? ");
}
@Test
public void copyForPlanKey_isSameInstance() throws Exception {
BetweenExpression exp = new BetweenExpression("startDate", 1, 2);
SpiExpression other = exp.copyForPlanKey();
assertThat(exp).isSameAs(other);
}
@Test
public void isSameByPlan_when_properties_match() throws Exception {
BetweenExpression exp0 = new BetweenExpression("startDate", 1, 2);
BetweenExpression exp1 = new BetweenExpression("startDate", 3, 4);
assertThat(exp0.isSameByPlan(exp1)).isTrue();
assertThat(exp1.isSameByPlan(exp0)).isTrue();
}
@Test
public void isSameByPlan_when_properties_do_not_match() throws Exception {
BetweenExpression exp0 = new BetweenExpression("startDate", 1, 2);
BetweenExpression exp1 = new BetweenExpression("endDate", 1, 2);
assertThat(exp0.isSameByPlan(exp1)).isFalse();
assertThat(exp1.isSameByPlan(exp0)).isFalse();
}
@Test
public void isSameByBind_when_values_do_not_match() throws Exception {
BetweenExpression exp0 = new BetweenExpression("startDate", 1, 2);
BetweenExpression exp1 = new BetweenExpression("startDate", 1, 3);
assertThat(exp0.isSameByBind(exp1)).isFalse();
assertThat(exp1.isSameByBind(exp0)).isFalse();
}
@Test
public void isSameByBind_when_values_match() throws Exception {
BetweenExpression exp0 = new BetweenExpression("startDate", 1, 2);
BetweenExpression exp1 = new BetweenExpression("startDate", 1, 2);
assertThat(exp0.isSameByBind(exp1)).isTrue();
assertThat(exp1.isSameByBind(exp0)).isTrue();
}
}
@@ -0,0 +1,45 @@
package com.avaje.ebeaninternal.server.expression;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class BetweenPropertyExpressionTest {
@NotNull
private BetweenPropertyExpression exp(String lowProperty, String highProperty, Object value) {
return new BetweenPropertyExpression(lowProperty, highProperty, value);
}
@Test
public void isSameByPlan_when_same() {
assertThat(exp("a", "b", 10).isSameByPlan(exp("a", "b", 10))).isTrue();
}
@Test
public void isSameByPlan_when_diffValue() {
assertThat(exp("a", "b", 10).isSameByPlan(exp("a", "b", 20))).isTrue();
}
@Test
public void isSameByPlan_when_diffProperty() {
assertThat(exp("a", "b", 10).isSameByPlan(exp("a", "c", 10))).isFalse();
}
@Test
public void isSameByPlan_when_diffExpressionType() {
assertThat(exp("a", "b", 10).isSameByPlan(new NoopExpression())).isFalse();
}
@Test
public void isSameByBind_when_same() {
assertThat(exp("a", "b", 10).isSameByBind(exp("a", "b", 10))).isTrue();
}
@Test
public void isSameByBind_when_diff() {
assertThat(exp("a", "b", 10).isSameByBind(exp("a", "b", 20))).isFalse();
}
}
@@ -0,0 +1,50 @@
package com.avaje.ebeaninternal.server.expression;
import org.junit.Test;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class CaseInsensitiveEqualExpressionTest {
CaseInsensitiveEqualExpression exp(String propName, String value) {
return new CaseInsensitiveEqualExpression(propName, value);
}
@Test
public void isSameByPlan_when_same() {
assertThat(exp("a", "10").isSameByPlan(exp("a", "10"))).isTrue();
}
@Test
public void isSameByPlan_when_diffBind_same() {
assertThat(exp("a", "10").isSameByPlan(exp("a", "20"))).isTrue();
}
@Test
public void isSameByPlan_when_diffProperty_diff() {
assertThat(exp("a", "10").isSameByPlan(exp("b", "10"))).isFalse();
}
@Test
public void isSameByPlan_when_diffType_diff() {
assertThat(exp("a", "10").isSameByPlan(new NoopExpression())).isFalse();
}
@Test
public void isSameByBind_when_sameBindValues() {
assertThat(exp("a", "10").isSameByBind(exp("b", "10"))).isTrue();
}
@Test
public void isSameByBind_when_diffBindValues() {
assertThat(exp("a", "10").isSameByBind(exp("b", "20"))).isFalse();
}
}
@@ -1,13 +1,11 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.LikeType;
import com.avaje.ebean.Query;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
@@ -22,42 +20,68 @@ import static org.assertj.core.api.Assertions.assertThat;
public class DefaultExampleExpressionTest extends BaseTestCase {
@Test
public void test() {
SpiEbeanServer server = (SpiEbeanServer)Ebean.getDefaultServer();
BeanDescriptor<Customer> desc = server.getBeanDescriptor(Customer.class);
SpiQuery<Customer> query = (SpiQuery<Customer>)server.find(Customer.class);
Customer customer() {
Address address = new Address();
address.setCity("billingAddress.city");
Customer customer = new Customer();
customer.setName("name");
customer.setBillingAddress(address);
return customer;
}
DefaultExampleExpression exp() {
Customer customer = customer();
return new DefaultExampleExpression((EntityBean)customer, false, LikeType.EQUAL_TO);
}
DefaultExampleExpression expr = new DefaultExampleExpression((EntityBean)customer, false, LikeType.EQUAL_TO);
DefaultExampleExpression expExtra() {
Customer customer = customer();
customer.setSmallnote("smallNote");
return new DefaultExampleExpression((EntityBean)customer, false, LikeType.EQUAL_TO);
}
DefaultExampleExpression expDiffName() {
Customer customer = customer();
customer.setName("otherName");
return new DefaultExampleExpression((EntityBean)customer, false, LikeType.EQUAL_TO);
}
BeanQueryRequest<?> request = create(query, desc);
BeanDescriptor<Customer> customerBeanDescriptor() {
return getBeanDescriptor(Customer.class);
}
DefaultExampleExpression prepare(DefaultExampleExpression expr) {
SpiQuery<Customer> query = (SpiQuery<Customer>)spiEbeanServer().find(Customer.class);
BeanQueryRequest<?> request = create(query, customerBeanDescriptor());
expr.prepareExpression(request);
return expr;
}
@Test
public void test() {
DefaultExampleExpression expr = exp();
prepare(expr);
HashQueryPlanBuilder builder = new HashQueryPlanBuilder();
expr.queryPlanHash(builder);
TDSpiExpressionRequest req = new TDSpiExpressionRequest(desc);
TDSpiExpressionRequest req = new TDSpiExpressionRequest(customerBeanDescriptor());
expr.addBindValues(req);
assertThat(req.bindValues).contains("name", "billingAddress.city");
address.setCity("Auckland");
Customer customer = customer();
customer.setName("Rob");
customer.getBillingAddress().setCity("Auckland");
ResetBasicData.reset();
Query<Customer> query1 = server.find(Customer.class)
Query<Customer> query1 = server().find(Customer.class)
.where().exampleLike(customer)
.query();
@@ -72,4 +96,28 @@ public class DefaultExampleExpressionTest extends BaseTestCase {
return new OrmQueryRequest<T>(null, null, query, desc, null);
}
@Test
public void isSameByPlan_whenSame() {
assertThat(prepare(exp()).isSameByPlan(prepare(exp()))).isTrue();
}
@Test
public void isSameByPlan_when_diffBindValue_stillSame() {
assertThat(prepare(exp()).isSameByPlan(prepare(expDiffName()))).isTrue();
}
@Test
public void isSameByPlan_when_extraExpression_then_different() {
assertThat(prepare(exp()).isSameByPlan(prepare(expExtra()))).isFalse();
}
@Test
public void isSameByPlan_when_lessExpression_then_different() {
assertThat(prepare(expExtra()).isSameByPlan(prepare(exp()))).isFalse();
}
}
@@ -0,0 +1,98 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.ExpressionList;
import org.junit.Test;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class DefaultExpressionListTest {
DefaultExpressionList exp() {
return new DefaultExpressionList<Object>(null, new DefaultExpressionFactory(true), null);
}
DefaultExpressionList spi(ExpressionList list) {
return (DefaultExpressionList)list;
}
@Test
public void isSameByPlan_when_same() {
assertThat(spi(exp().eq("a", 10).eq("b", 20))
.isSameByPlan(spi(exp().eq("a", 10).eq("b", 20)))).isTrue();
}
@Test
public void isSameByPlan_when_diffExpressionType() {
assertThat(spi(exp().eq("a", 10).eq("b", 20))
.isSameByPlan(new NoopExpression())).isFalse();
}
@Test
public void isSameByPlan_when_less() {
assertThat(spi(exp().eq("a", 10).eq("b", 20))
.isSameByPlan(spi(exp().eq("a", 10)))).isFalse();
}
@Test
public void isSameByPlan_when_lessEmptyLast() {
assertThat(spi(exp().eq("a", 10).eq("b", 20))
.isSameByPlan(spi(exp()))).isFalse();
}
@Test
public void isSameByPlan_when_lessEmptyFirst() {
assertThat(spi(exp())
.isSameByPlan(spi(exp().eq("a", 10)))).isFalse();
}
@Test
public void isSameByPlan_when_more() {
assertThat(spi(exp().eq("a", 10).eq("b", 20))
.isSameByPlan(spi(exp().eq("a", 10).eq("b", 20).eq("c", 30)))).isFalse();
}
@Test
public void isSameByPlan_when_diffProperties() {
assertThat(spi(exp().eq("a", 10).eq("b", 20))
.isSameByPlan(spi(exp().eq("c", 10).eq("b", 20)))).isFalse();
}
@Test
public void isSameByBind_when_same() {
assertThat(spi(exp().eq("a", 10).eq("b", 20))
.isSameByBind(spi(exp().eq("a", 10).eq("b", 20)))).isTrue();
}
@Test
public void isSameByBind_when_diffValues() {
assertThat(spi(exp().eq("a", 10).eq("b", 20))
.isSameByBind(spi(exp().eq("a", 10).eq("b", 30)))).isFalse();
}
@Test
public void isSameByBind_when_less() {
assertThat(spi(exp().eq("a", 10))
.isSameByBind(spi(exp().eq("a", 10).eq("b", 20)))).isFalse();
}
@Test
public void isSameByBind_when_more() {
assertThat(spi(exp().eq("a", 10))
.isSameByBind(spi(exp().eq("a", 10).eq("b", 20)))).isFalse();
}
}
@@ -0,0 +1,85 @@
package com.avaje.ebeaninternal.server.expression;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.util.Arrays;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class ExistsExpressionTest {
@NotNull
private ExistsExpression exp(boolean not, String sql, Object... bindValues) {
return new ExistsExpression(not, sql, Arrays.asList(bindValues));
}
@Test
public void isSameByPlan_when_same() {
assertThat(exp(true,"a", 10).isSameByPlan(exp(true,"a", 10))).isTrue();
}
@Test
public void isSameByPlan_when_diffBind_same() {
assertThat(exp(true,"a", 10).isSameByPlan(exp(true,"a", 20))).isTrue();
}
@Test
public void isSameByPlan_when_diffNot() {
assertThat(exp(true,"a", 10).isSameByPlan(exp(false,"a", 10))).isFalse();
}
@Test
public void isSameByPlan_when_diffSql() {
assertThat(exp(true,"a", 10).isSameByPlan(exp(true,"b", 10))).isFalse();
}
@Test
public void isSameByBind_when_sameBindValues() {
assertThat(exp(true,"a", 10).isSameByBind(exp(true,"a", 10))).isTrue();
}
@Test
public void isSameByBind_when_sameMultipleBindValues() {
assertThat(exp(true,"a", 10, "ABC", 20).isSameByBind(exp(true,"a", 10, "ABC", 20))).isTrue();
}
@Test
public void isSameByBind_when_diffMultipleBindValues() {
assertThat(exp(true,"a", 10, "ABC", 20).isSameByBind(exp(true,"a", 10, "ABC", 21))).isFalse();
}
@Test
public void isSameByBind_when_diffMultipleBindValuesByOrder() {
assertThat(exp(true,"a", 10, "ABC", 20).isSameByBind(exp(true,"a", 10, 20, "ABC"))).isFalse();
}
@Test
public void isSameByBind_when_diffBindValues() {
assertThat(exp(true,"a", 10).isSameByBind(exp(true,"a", 20))).isFalse();
}
@Test
public void isSameByBind_when_lessBindValues() {
assertThat(exp(true,"a", 10, 20).isSameByBind(exp(true,"a", 20))).isFalse();
}
@Test
public void isSameByBind_when_moreBindValues() {
assertThat(exp(true,"a", 10).isSameByBind(exp(true,"a", 10, 20))).isFalse();
}
}
@@ -0,0 +1,41 @@
package com.avaje.ebeaninternal.server.expression;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class IdExpressionTest {
@NotNull
private IdExpression exp(Object value) {
return new IdExpression(value);
}
@Test
public void isSameByPlan_when_same() {
assertThat(exp(10).isSameByPlan(exp(10))).isTrue();
}
@Test
public void isSameByPlan_when_diffBind_same() {
assertThat(exp(10).isSameByPlan(exp(20))).isTrue();
}
@Test
public void isSameByBind_when_sameBindValues() {
assertThat(exp(10).isSameByBind(exp(10))).isTrue();
}
@Test
public void isSameByBind_when_diffBindValues() {
assertThat(exp(10).isSameByBind(exp(20))).isFalse();
assertThat(exp(10).isSameByBind(exp("junk"))).isFalse();
}
}
@@ -0,0 +1,67 @@
package com.avaje.ebeaninternal.server.expression;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.util.Arrays;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class IdInExpressionTest {
@NotNull
private IdInExpression exp(Object... values) {
return new IdInExpression(Arrays.asList(values));
}
@Test
public void isSameByPlan_when_same() {
assertThat(exp(10).isSameByPlan(exp(10))).isTrue();
}
@Test
public void isSameByPlan_when_diffBind_same() {
assertThat(exp(10).isSameByPlan(exp(20))).isTrue();
}
@Test
public void isSameByPlan_when_diffBindCount() {
assertThat(exp(10).isSameByPlan(exp(10, 20))).isFalse();
}
@Test
public void isSameByBind_when_sameBindValues() {
assertThat(exp(10).isSameByBind(exp(10))).isTrue();
}
@Test
public void isSameByBind_when_mulitpleSameBindValues() {
assertThat(exp(10,"ABC", 20).isSameByBind(exp(10, "ABC", 20))).isTrue();
}
@Test
public void isSameByBind_when_diffBindValues() {
assertThat(exp(10).isSameByBind(exp("junk"))).isFalse();
}
@Test
public void isSameByBind_when_lessBindValues() {
assertThat(exp(10,"ABC", 20).isSameByBind(exp(10, "ABC"))).isFalse();
}
@Test
public void isSameByBind_when_moreBindValues() {
assertThat(exp(10,"ABC").isSameByBind(exp(10, "ABC", 30))).isFalse();
}
}
@@ -1,12 +1,16 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.*;
import static org.assertj.core.api.StrictAssertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
public class InExpressionTest {
@@ -87,4 +91,70 @@ public class InExpressionTest {
}
return list;
}
@NotNull
private InExpression exp(String propName, boolean not, Object... values) {
return new InExpression(propName, Arrays.asList(values), not);
}
@Test
public void isSameByPlan_when_same() {
assertThat(exp("a", false, 10).isSameByPlan(exp("a", false, 10))).isTrue();
}
@Test
public void isSameByPlan_when_diffPropertyName() {
assertThat(exp("a", false, 10).isSameByPlan(exp("b", false, 10))).isFalse();
}
@Test
public void isSameByPlan_when_diffNot() {
assertThat(exp("a", false, 10).isSameByPlan(exp("a", true, 10))).isFalse();
}
@Test
public void isSameByPlan_when_diffBind_same() {
assertThat(exp("a", false, 10).isSameByPlan(exp("a", false, 10, 20))).isFalse();
}
@Test
public void isSameByPlan_when_diffBindCount() {
assertThat(exp("a", false, 10).isSameByPlan(exp("a", false, 10, 20))).isFalse();
}
@Test
public void isSameByBind_when_sameBindValues() {
assertThat(exp("a", false, 10).isSameByBind(exp("a", false, 10))).isTrue();
}
@Test
public void isSameByBind_when_sameMultipleBindValues() {
assertThat(exp("a", false, 10, "ABC", 20).isSameByBind(exp("a", false, 10, "ABC", 20))).isTrue();
}
@Test
public void isSameByBind_when_diffBindValues() {
assertThat(exp("a", false, 10).isSameByBind(exp("a", false, "foo"))).isFalse();
}
@Test
public void isSameByBind_when_lessBindValues() {
assertThat(exp("a", false, 10, "ABC", 20).isSameByBind(exp("a", false, 10, "ABC"))).isFalse();
}
@Test
public void isSameByBind_when_moreBindValues() {
assertThat(exp("a", false, 10, "ABC").isSameByBind(exp("a", false, 10, "ABC", 30))).isFalse();
}
}
@@ -0,0 +1,89 @@
package com.avaje.ebeaninternal.server.expression;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.util.Arrays;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class InQueryExpressionTest {
@NotNull
private InQueryExpression exp(String propertyName, boolean not, String sql, Object... bindValues) {
return new InQueryExpression(propertyName, not, sql, Arrays.asList(bindValues));
}
@Test
public void isSameByPlan_when_same() {
assertThat(exp("name",true,"sql", 10).isSameByPlan(exp("name",true,"sql", 10))).isTrue();
}
@Test
public void isSameByPlan_when_diffBind_same() {
assertThat(exp("name",true,"sql", 10).isSameByPlan(exp("name",true,"sql", 20))).isTrue();
}
@Test
public void isSameByPlan_when_diffNPropertyName() {
assertThat(exp("name",true,"sql", 10).isSameByPlan(exp("nameDiff",true,"sql", 10))).isFalse();
}
@Test
public void isSameByPlan_when_diffNot() {
assertThat(exp("name",true,"sql", 10).isSameByPlan(exp("name",false,"sql", 10))).isFalse();
}
@Test
public void isSameByPlan_when_diffSql() {
assertThat(exp("name",true,"sql", 10).isSameByPlan(exp("name",true,"sqlDiff", 10))).isFalse();
}
@Test
public void isSameByBind_when_sameBindValues() {
assertThat(exp("name",true,"sql", 10).isSameByBind(exp("name",true,"sql", 10))).isTrue();
}
@Test
public void isSameByBind_when_sameMultipleBindValues() {
assertThat(exp("name",true,"sql", 10, "ABC", 20).isSameByBind(exp("name",true,"sql", 10, "ABC", 20))).isTrue();
}
@Test
public void isSameByBind_when_diffMultipleBindValues() {
assertThat(exp("name",true,"sql", 10, "ABC", 20).isSameByBind(exp("name",true,"sql", 10, "ABC", 21))).isFalse();
}
@Test
public void isSameByBind_when_diffMultipleBindValuesByOrder() {
assertThat(exp("name",true,"sql", 10, "ABC", 20).isSameByBind(exp("name",true,"sql", 10, 20, "ABC"))).isFalse();
}
@Test
public void isSameByBind_when_diffBindValues() {
assertThat(exp("name",true,"sql", 10).isSameByBind(exp("name",true,"sql", 20))).isFalse();
}
@Test
public void isSameByBind_when_lessBindValues() {
assertThat(exp("name",true,"sql", 10, 20).isSameByBind(exp("name",true,"sql", 20))).isFalse();
}
@Test
public void isSameByBind_when_moreBindValues() {
assertThat(exp("name",true,"sql", 10).isSameByBind(exp("name",true,"sql", 10, 20))).isFalse();
}
}
@@ -0,0 +1,81 @@
package com.avaje.ebeaninternal.server.expression;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class JsonPathExpressionTest {
@NotNull
private JsonPathExpression exp(String propertyName, String path, Op operator, Object value) {
return new JsonPathExpression(propertyName, path, operator, value);
}
@Test
public void isSameByPlan_when_same() {
assertThat(exp("a", "path", Op.EQ, 10).isSameByPlan(exp("a", "path", Op.EQ, 10))).isTrue();
}
@Test
public void isSameByPlan_when_diffBind_same() {
assertThat(exp("a", "path", Op.EQ, 10).isSameByPlan(exp("a", "path", Op.EQ, 20))).isTrue();
}
@Test
public void isSameByPlan_when_diffPath() {
assertThat(exp("a", "path", Op.EQ, 10).isSameByPlan(exp("a", "pathDiff", Op.EQ, 10))).isFalse();
}
@Test
public void isSameByPlan_when_diffProperty_diff() {
assertThat(exp("a", "path", Op.EQ, 10).isSameByPlan(exp("b", "path", Op.EQ, 10))).isFalse();
}
@Test
public void isSameByPlan_when_diffOperator_diff() {
assertThat(exp("a", "path", Op.EQ, 10).isSameByPlan(exp("a", "path", Op.LT, 10))).isFalse();
}
@Test
public void isSameByPlan_when_diffType_diff() {
assertThat(exp("a", "path", Op.EQ, 10).isSameByPlan(new NoopExpression())).isFalse();
}
@Test
public void isSameByBind_when_sameBindValues() {
assertThat(exp("a", "path", Op.EQ, 10).isSameByBind(exp("a", "path", Op.LT, 10))).isTrue();
}
@Test
public void isSameByBind_when_sameNullBindValues() {
assertThat(exp("a", "path", Op.EQ, null).isSameByBind(exp("a", "path", Op.LT, null))).isTrue();
}
@Test
public void isSameByBind_when_diffBindValues() {
assertThat(exp("a", "path", Op.EQ, 10).isSameByBind(exp("a", "path", Op.EQ, "junk"))).isFalse();
}
@Test
public void isSameByBind_when_diffFirstNullBindValues() {
assertThat(exp("a", "path", Op.EQ, null).isSameByBind(exp("a", "path", Op.LT, 10))).isFalse();
}
@Test
public void isSameByBind_when_diffLastNullBindValues() {
assertThat(exp("a", "path", Op.EQ, 10).isSameByBind(exp("a", "path", Op.LT, null))).isFalse();
}
}
@@ -0,0 +1,60 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.Expr;
import com.avaje.ebean.Expression;
import org.junit.Test;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class JunctionExpressionTest {
Expression eq(String propName, int value) {
return Expr.eq(propName, value);
}
DefaultExpressionList<?> exp(Expression... expressions) {
DefaultExpressionList<Object> list = new DefaultExpressionList<Object>(null, new DefaultExpressionFactory(true), null);
for (Expression ex : expressions) {
list.add(ex);
}
return list;
}
<T> JunctionExpression and(DefaultExpressionList<T> list) {
return new JunctionExpression.Conjunction<T>(list);
}
<T> JunctionExpression or(DefaultExpressionList<T> list) {
return new JunctionExpression.Disjunction<T>(list);
}
@Test
public void isSameByPlan_when_same() {
assertThat(and(exp(eq("a", 10), eq("b", 10)))
.isSameByPlan(and(exp(eq("a", 10), eq("b", 10))))).isTrue();
}
@Test
public void copyForPlanKey_isSameByPlan_when_same() {
assertThat(and(exp(eq("a", 10), eq("b", 10)).copyForPlanKey())
.isSameByPlan(and(exp(eq("a", 10), eq("b", 10))))).isTrue();
}
@Test
public void copyForPlanKey_isSameByPlan_when_diff() {
assertThat(and(exp(eq("a", 10), eq("b", 10)).copyForPlanKey())
.isSameByPlan(and(exp(eq("a", 10), eq("c", 10))))).isFalse();
}
@Test
public void isSameByPlan_when_diffType() {
assertThat(and(exp(eq("a", 10), eq("b", 10)))
.isSameByPlan(or(exp(eq("a", 10), eq("b", 10))))).isFalse();
}
}
@@ -0,0 +1,66 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.LikeType;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class LikeExpressionTest extends BaseExpressionTest {
@NotNull
private LikeExpression exp(String propertyName, String value, boolean caseInsensitive, LikeType type) {
return new LikeExpression(propertyName, value, caseInsensitive, type);
}
@Test
public void isSameByPlan_when_same() {
assertThat(exp("a", "rob", true, LikeType.STARTS_WITH)
.isSameByPlan(exp("a", "rob", true, LikeType.STARTS_WITH))).isTrue();
}
@Test
public void isSameByPlan_when_diffBind_then_stillSame() {
assertThat(exp("a", "rob", true, LikeType.STARTS_WITH)
.isSameByPlan(exp("a", "bor", true, LikeType.STARTS_WITH))).isTrue();
}
@Test
public void isSameByPlan_when_diffCaseInsensitive() {
assertThat(exp("a", "rob", true, LikeType.STARTS_WITH)
.isSameByPlan(exp("a", "rob", false, LikeType.STARTS_WITH))).isFalse();
}
@Test
public void isSameByPlan_when_diffLikeType() {
assertThat(exp("a", "rob", true, LikeType.STARTS_WITH)
.isSameByPlan(exp("a", "rob", true, LikeType.ENDS_WITH))).isFalse();
}
@Test
public void isSameByPlan_when_diffProperty() {
assertThat(exp("a", "rob", true, LikeType.STARTS_WITH)
.isSameByPlan(exp("b", "rob", true, LikeType.STARTS_WITH))).isFalse();
}
@Test
public void isSameByBind_when_sameBindValues() {
assertThat(exp("a", "rob", true, LikeType.STARTS_WITH)
.isSameByBind(exp("a", "rob", true, LikeType.STARTS_WITH))).isTrue();
}
@Test
public void isSameByBind_when_diffBindValues() {
assertThat(exp("a", "rob", true, LikeType.STARTS_WITH)
.isSameByBind(exp("a", "bor", true, LikeType.STARTS_WITH))).isFalse();
}
}
@@ -0,0 +1,78 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.Expr;
import com.avaje.ebean.Expression;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class LogicExpressionTest extends BaseExpressionTest {
Expression eq(String propName, int value) {
return Expr.eq(propName, value);
}
LogicExpression and(Expression a, Expression b) {
return new LogicExpression.And(a, b);
}
LogicExpression or(Expression a, Expression b) {
return new LogicExpression.Or(a, b);
}
@Test
public void isSameByPlan_when_same() {
assertThat(and(eq("a", 10), eq("b", 10))
.isSameByPlan(and(eq("a", 10), eq("b", 10)))).isTrue();
}
@Test
public void isSameByPlan_when_diffBind_then_stillSame() {
assertThat(and(eq("a", 10), eq("b", 10))
.isSameByPlan(and(eq("a", 20), eq("b", 20)))).isTrue();
}
@Test
public void isSameByPlan_when_diffExp1_then_diff() {
assertThat(and(eq("a", 10), eq("b", 10))
.isSameByPlan(and(eq("c", 10), eq("b", 10)))).isFalse();
}
@Test
public void isSameByPlan_when_diffExp2_then_diff() {
assertThat(and(eq("a", 10), eq("b", 10))
.isSameByPlan(and(eq("a", 10), eq("c", 10)))).isFalse();
}
@Test
public void isSameByPlan_when_diffType_then_diff() {
assertThat(or(eq("a", 10), eq("b", 10))
.isSameByPlan(and(eq("a", 10), eq("c", 10)))).isFalse();
}
@Test
public void isSameByPlan_when_diffExpressionType() {
assertThat(or(eq("a", 10), eq("b", 10))
.isSameByPlan(new NoopExpression())).isFalse();
}
@Test
public void isSameByBind_when_sameBindValues() {
assertThat(and(eq("a", 10), eq("b", 10))
.isSameByBind(and(eq("a", 10), eq("c", 10)))).isTrue();
}
@Test
public void isSameByBind_when_diffBindValues() {
assertThat(and(eq("a", 10), eq("b", 10))
.isSameByBind(and(eq("a", 10), eq("c", 20)))).isFalse();
}
}
@@ -8,7 +8,8 @@ import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class NoopExpressionQueryTest extends BaseTestCase {
public class NoopExpressionTest extends BaseTestCase {
@Test
public void test() {
@@ -39,4 +40,29 @@ public class NoopExpressionQueryTest extends BaseTestCase {
assertThat(generatedSql).contains("select t0.id c0 from o_customer t0 where t0.name is null and 1=1 and t0.status is not null");
}
@Test
public void isSameByPlan_when_same() {
assertThat(new NoopExpression().isSameByPlan(new NoopExpression())).isTrue();
}
@Test
public void isSameByPlan_when_diffExpressionType() {
assertThat(new NoopExpression().isSameByPlan(null)).isFalse();
}
@Test
public void isSameByBind_when_same() {
assertThat(new NoopExpression().isSameByBind(new NoopExpression())).isTrue();
}
@Test
public void isSameByBind_when_diffExpressionType() {
assertThat(new NoopExpression().isSameByBind(null)).isTrue();
}
}
@@ -0,0 +1,58 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.Expression;
import org.junit.Test;
import static com.avaje.ebean.Expr.eq;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class NotExpressionTest {
NotExpression not(Expression expression) {
return new NotExpression(expression);
}
@Test
public void isSameByPlan_when_same() {
assertThat(not(eq("a", 10))
.isSameByPlan(not(eq("a", 10)))).isTrue();
}
@Test
public void isSameByPlan_when_sameByPlan() {
assertThat(not(eq("a", 10))
.isSameByPlan(not(eq("a", 20)))).isTrue();
}
@Test
public void isSameByPlan_when_different() {
assertThat(not(eq("a", 10))
.isSameByPlan(not(eq("b", 10)))).isFalse();
}
@Test
public void isSameByPlan_when_differentExpressionType() {
assertThat(not(eq("a", 10))
.isSameByPlan(new NoopExpression())).isFalse();
}
@Test
public void isSameByBind_when_same() {
assertThat(not(eq("a", 10))
.isSameByBind(not(eq("b", 10)))).isTrue();
}
@Test
public void isSameByBind_when_different() {
assertThat(not(eq("a", 10))
.isSameByBind(not(eq("a", 20)))).isFalse();
}
}
@@ -0,0 +1,91 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebeaninternal.api.SpiExpression;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class NullExpressionTest extends BaseExpressionTest {
NullExpression nullExp(String propertyName, boolean notNull) {
return new NullExpression(propertyName, notNull);
}
@Test
public void addSql_when_notNull() throws Exception {
DefaultExpressionRequest expReq = newExpressionRequest();
nullExp("id", true).addSql(expReq);
assertThat(expReq.getSql()).isEqualTo("id is not null ");
}
@Test
public void addSql_when_null() throws Exception {
DefaultExpressionRequest expReq = newExpressionRequest();
nullExp("id", false).addSql(expReq);
assertThat(expReq.getSql()).isEqualTo("id is null ");
}
@Test
public void addSql_when_notNull_and_assocOne() throws Exception {
DefaultExpressionRequest expReq = newExpressionRequest();
nullExp("customer", true).addSql(expReq);
assertThat(expReq.getSql()).isEqualTo("customer.id is not null ");
}
@Test
public void addSql_when_null_and_assocOne() throws Exception {
DefaultExpressionRequest expReq = newExpressionRequest();
nullExp("customer", false).addSql(expReq);
assertThat(expReq.getSql()).isEqualTo("customer.id is null ");
}
@Test
public void copyForPlanKey_isSameInstance() throws Exception {
NullExpression exp = nullExp("customer.name", false);
SpiExpression other = exp.copyForPlanKey();
assertThat(exp).isSameAs(other);
}
@Test
public void isSameByBind_true() throws Exception {
assertThat(nullExp("customer.name", false)
.isSameByBind(nullExp("customer.name", false))).isTrue();
}
@Test
public void isSameByPlan_true() throws Exception {
assertThat(nullExp("customer.name", false)
.isSameByPlan(nullExp("customer.name", false))).isTrue();
}
@Test
public void isSameByPlan_false_when_notNullDiff() throws Exception {
assertThat(new NullExpression("customer.name", false)
.isSameByPlan(new NullExpression("customer.name", true))).isFalse();
}
@Test
public void isSameByPlan_false_when_propertyNameDiff() throws Exception {
assertThat(new NullExpression("customer.startDate", true)
.isSameByPlan(new NullExpression("customer.name", true))).isFalse();
}
}
@@ -0,0 +1,50 @@
package com.avaje.ebeaninternal.server.expression;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class RawExpressionTest {
@NotNull
private RawExpression exp(String sql, Object... values) {
return new RawExpression(sql, values);
}
@Test
public void isSameByPlan_when_same() {
assertThat(exp("a", 10).isSameByPlan(exp("a", 10))).isTrue();
}
@Test
public void isSameByPlan_when_diffBindValues() {
assertThat(exp("a", 10).isSameByPlan(exp("a", 20))).isTrue();
}
@Test
public void isSameByPlan_when_diffSql() {
assertThat(exp("a", 10).isSameByPlan(exp("b", 10))).isFalse();
}
@Test
public void isSameByBind_when_same() {
assertThat(exp("a", 10).isSameByBind(exp("a", 10))).isTrue();
}
@Test
public void isSameByBind_when_diffBindValues() {
assertThat(exp("a", 10).isSameByBind(exp("a", 20))).isFalse();
}
@Test
public void isSameByBind_when_moreBindValues() {
assertThat(exp("a", 10).isSameByBind(exp("a", 10, 20))).isFalse();
}
@Test
public void isSameByBind_when_lessBindValues() {
assertThat(exp("a", 10, 20).isSameByBind(exp("a", 10))).isFalse();
}
}
@@ -0,0 +1,29 @@
package com.avaje.ebeaninternal.server.expression;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class SameTest {
@Test
public void sameByNull() throws Exception {
assertThat(Same.sameByNull("a", "a")).isTrue();
assertThat(Same.sameByNull("a", "b")).isTrue();
assertThat(Same.sameByNull(null, null)).isTrue();
assertThat(Same.sameByNull("a", null)).isFalse();
assertThat(Same.sameByNull(null, "a")).isFalse();
}
@Test
public void sameByValue() throws Exception {
assertThat(Same.sameByValue("a", "a")).isTrue();
assertThat(Same.sameByValue("a", "b")).isFalse();
assertThat(Same.sameByValue(null, null)).isTrue();
assertThat(Same.sameByValue("a", null)).isFalse();
assertThat(Same.sameByValue(null, "a")).isFalse();
}
}
@@ -0,0 +1,58 @@
package com.avaje.ebeaninternal.server.expression;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class SimpleExpressionTest extends BaseExpressionTest {
@NotNull
private SimpleExpression exp(String propertyName, Op operator, Object value) {
return new SimpleExpression(propertyName, operator, value);
}
@Test
public void isSameByPlan_when_same() {
assertThat(exp("a", Op.EQ, 10).isSameByPlan(exp("a", Op.EQ, 10))).isTrue();
}
@Test
public void isSameByPlan_when_diffBind_same() {
assertThat(exp("a", Op.EQ, 10).isSameByPlan(exp("a", Op.EQ, 20))).isTrue();
}
@Test
public void isSameByPlan_when_diffProperty_diff() {
assertThat(exp("a", Op.EQ, 10).isSameByPlan(exp("b", Op.EQ, 10))).isFalse();
}
@Test
public void isSameByPlan_when_diffOperator_diff() {
assertThat(exp("a", Op.EQ, 10).isSameByPlan(exp("a", Op.LT, 10))).isFalse();
}
@Test
public void isSameByPlan_when_diffType_diff() {
assertThat(exp("a", Op.EQ, 10).isSameByPlan(new NoopExpression())).isFalse();
}
@Test
public void isSameByBind_when_sameBindValues() {
assertThat(exp("a", Op.EQ, 10).isSameByBind(exp("a", Op.LT, 10))).isTrue();
}
@Test
public void isSameByBind_when_diffBindValues() {
assertThat(exp("a", Op.EQ, 10).isSameByBind(exp("a", Op.EQ, "junk"))).isFalse();
}
}
@@ -0,0 +1,61 @@
package com.avaje.ebeaninternal.server.query;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class RawSqlQueryPlanKeyTest {
@Test
public void test_equals_same_instance() {
RawSqlQueryPlanKey key = key("select foo", true, true, "");
assertThat(key).isEqualTo(key);
assertThat(key.hashCode()).isEqualTo(key.hashCode());
}
@Test
public void test_equals_diff_instance() {
assertThat(key("select foo", true, true, "")).isEqualTo(key("select foo", true, true, ""));
assertThat(key("select foo", true, true, "").hashCode()).isEqualTo(key("select foo", true, true, "").hashCode());
}
@Test
public void test_notEquals_diff_sql() {
assertThat(key("select foo", true, true, "")).isNotEqualTo(key("select bar", true, true, ""));
assertThat(key("select foo", true, true, "").hashCode()).isNotEqualTo(key("select bar", true, true, "").hashCode());
}
@Test
public void test_notEquals_diff_rawSqlFlag() {
assertThat(key("select foo", true, true, "")).isNotEqualTo(key("select foo", false, true, ""));
assertThat(key("select foo", true, true, "").hashCode()).isNotEqualTo(key("select foo", false, true, "").hashCode());
}
@Test
public void test_notEquals_diff_rowNumberIncluded() {
assertThat(key("select foo", true, true, "")).isNotEqualTo(key("select foo", true, false, ""));
assertThat(key("select foo", true, true, "").hashCode()).isNotEqualTo(key("select foo", true, false, "").hashCode());
}
@Test
public void test_notEquals_diff_logWhereSql() {
assertThat(key("select foo", true, true, "")).isNotEqualTo(key("select foo", true, true, "a"));
assertThat(key("select foo", true, true, "").hashCode()).isNotEqualTo(key("select foo", true, true, "a").hashCode());
}
@NotNull
private RawSqlQueryPlanKey key(String sql, boolean rawSql, boolean rowNumberIncluded, String logWhereSql) {
return new RawSqlQueryPlanKey(sql, rawSql, rowNumberIncluded, logWhereSql);
}
}
@@ -16,7 +16,7 @@ public class DefaultOrmQueryTest {
DefaultOrmQuery<Order> q1 = (DefaultOrmQuery<Order>)Ebean.find(Order.class).where().in("name", "a","b","c").query();
DefaultOrmQuery<Order> q2 = (DefaultOrmQuery<Order>)Ebean.find(Order.class).where().in("id", 2,2,3).query();
assertThat(q1.calculateQueryPlanHash()).isNotEqualTo(q2.calculateQueryPlanHash());
assertThat(q1.createQueryPlanKey()).isNotEqualTo(q2.createQueryPlanKey());
assertThat(q1.queryBindHash()).isNotEqualTo(q2.queryBindHash());
}
@@ -26,7 +26,7 @@ public class DefaultOrmQueryTest {
DefaultOrmQuery<Order> q1 = (DefaultOrmQuery<Order>)Ebean.find(Order.class).where().in("id", 1,2,3).query();
DefaultOrmQuery<Order> q2 = (DefaultOrmQuery<Order>)Ebean.find(Order.class).where().in("id", 2,2,3).query();
assertThat(q1.calculateQueryPlanHash()).isEqualTo(q2.calculateQueryPlanHash());
assertThat(q1.createQueryPlanKey()).isEqualTo(q2.createQueryPlanKey());
assertThat(q1.queryBindHash()).isNotEqualTo(q2.queryBindHash());
}
@@ -36,7 +36,7 @@ public class DefaultOrmQueryTest {
DefaultOrmQuery<Order> q1 = (DefaultOrmQuery<Order>)Ebean.find(Order.class).where().in("id", 1,2,3).query();
DefaultOrmQuery<Order> q2 = (DefaultOrmQuery<Order>)Ebean.find(Order.class).where().in("id", 1,2,3).query();
assertThat(q1.calculateQueryPlanHash()).isEqualTo(q2.calculateQueryPlanHash());
assertThat(q1.createQueryPlanKey()).isEqualTo(q2.createQueryPlanKey());
assertThat(q1.queryBindHash()).isEqualTo(q2.queryBindHash());
}
@@ -55,7 +55,7 @@ public class DefaultOrmQueryTest {
.fetch("details", "orderQty, unitPrice")
.fetch("details.product", "sku, name");
assertThat(query1.calculateQueryPlanHash()).isNotEqualTo(query2.calculateQueryPlanHash());
assertThat(query1.createQueryPlanKey()).isNotEqualTo(query2.createQueryPlanKey());
}
@Test
@@ -69,7 +69,7 @@ public class DefaultOrmQueryTest {
.setFirstRow(1)
.setMaxRows(0);
assertThat(query1.calculateQueryPlanHash()).isNotEqualTo(query2.calculateQueryPlanHash());
assertThat(query1.createQueryPlanKey()).isNotEqualTo(query2.createQueryPlanKey());
}
}
@@ -0,0 +1,432 @@
package com.avaje.ebeaninternal.server.querydefn;
import com.avaje.ebean.OrderBy;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionList;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.server.deploy.TableJoin;
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
import com.avaje.ebeaninternal.server.expression.BaseExpressionTest;
import com.avaje.tests.model.basic.Customer;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class OrmQueryPlanKeyTest extends BaseExpressionTest {
@Test
public void equals_when_defaults() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
@Test
public void equals_when_diffTableJoinNull() {
TableJoin tableJoin = tableJoin("id", "customer_id");
OrmQueryPlanKey key1 = new OrmQueryPlanKey(tableJoin, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_diffTableJoin() {
TableJoin tableJoin1 = tableJoin("id", "customer_id");
TableJoin tableJoin2 = tableJoin("id", "other_customer_id");
OrmQueryPlanKey key1 = new OrmQueryPlanKey(tableJoin1, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(tableJoin2, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_sameTableJoin() {
TableJoin tableJoin1 = tableJoin("id", "customer_id");
TableJoin tableJoin2 = tableJoin("id", "customer_id");
OrmQueryPlanKey key1 = new OrmQueryPlanKey(tableJoin1, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(tableJoin2, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
@NotNull
private TableJoin tableJoin(String col1, String col2) {
DeployTableJoin deploy = new DeployTableJoin();
deploy.setTable("myTable");
deploy.addJoinColumn(new DeployTableJoinColumn(col1, col2));
return new TableJoin(deploy);
}
@Test
public void equals_when_diffQueryType() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.LIST, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_firstRowsDifferent() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 10, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_maxRowsDifferent() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 10, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_firstRowsMaxRowsSame() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 10, 20, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 10, 20, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
@Test
public void equals_when_diffDisableLazyLoading() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, true, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_diffRawWhereNull() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, "rawWhere", null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_diffRawWhere() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, "rawWhere", null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, "rawDiff", null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_diffOrderByNull() {
OrderBy<Object> o1 = new OrderBy<Object>("id");
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, o1, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_orderBySame() {
OrderBy<Object> o1 = new OrderBy<Object>("id, name");
OrderBy<Object> o2 = new OrderBy<Object>("id, name");
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, o1, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, o2, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
@Test
public void equals_when_diffQueryNull() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, "query", null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_diffQuery() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, "query", null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, "queryDiff", null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_querySame() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, "query", null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, "query", null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
@Test
public void equals_when_diffAddWhereNull() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, "addWhere", null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_diffAddWhere() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, "addWhere", null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, "diff", null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_sameAddWhere() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, "addWhere", null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, "addWhere", null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
@Test
public void equals_when_diffAddHavingNull() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, "addHaving", false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_diffAddHaving() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, "addHaving", false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, "diff", false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_sameAddHaving() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, "addHaving", false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, "addHaving", false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
@Test
public void equals_when_diffDistinct() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, true, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_sameDistinct() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, true, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, true, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
@Test
public void equals_when_diffSqlDistinct() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, true, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_sameSqlDistinct() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, true, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, true, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
@Test
public void equals_when_diffMapKeyNull() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_diffMapKey() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, "diff", null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_sameMapKey() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
@Test
public void equals_when_diffIdNull() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, 42, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_idBothGiven() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, 42, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, 23, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
@Test
public void equals_when_diffTemporalMode() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.DRAFT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_diffForUpdate() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, true, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_diffRootAliasNull() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, "rootAlias", null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_diffRootAlias() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, "rootAlias", null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, "diff", null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_sameRootAlias() {
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, "rootAlias", null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, "rootAlias", null);
assertSame(key1, key2);
}
SpiExpressionList<Customer> list_id_eq_42() {
return (SpiExpressionList<Customer>) server().find(Customer.class)
.where().eq("id", 42);
}
SpiExpressionList<Customer> list_id_eq_43() {
return (SpiExpressionList<Customer>) server().find(Customer.class)
.where().eq("id", 43);
}
SpiExpressionList<Customer> list_id_eq_42_and_name_eq_rob() {
return (SpiExpressionList<Customer>) server().find(Customer.class)
.where().eq("id", 43).eq("name", "rob");
}
@Test
public void equals_when_sameWhere() {
SpiExpressionList<Customer> list1 = list_id_eq_42();
SpiExpressionList<Customer> list2 = list_id_eq_43();
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, list1, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, list2, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
@Test
public void equals_when_diffWhere() {
SpiExpressionList<Customer> where1 = list_id_eq_42();
SpiExpressionList<Customer> where2 = list_id_eq_42_and_name_eq_rob();
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, where1, null, SpiQuery.TemporalMode.DRAFT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, where2, null, SpiQuery.TemporalMode.DRAFT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_diffWhereNullLast() {
SpiExpressionList<Customer> list1 = list_id_eq_42();
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, list1, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_diffWhereNullFirst() {
SpiExpressionList<Customer> list1 = list_id_eq_42();
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, list1, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_diffHaving() {
SpiExpression having1 = list_id_eq_42().copyForPlanKey();
SpiExpression having2 = list_id_eq_42_and_name_eq_rob().copyForPlanKey();
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, having2, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertDifferent(key1, key2);
}
@Test
public void equals_when_sameHaving() {
SpiExpression having1 = list_id_eq_42().copyForPlanKey();
SpiExpression having2 = list_id_eq_42().copyForPlanKey();
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, having2, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
@Test
public void equals_when_havingNullLast() {
SpiExpression having1 = list_id_eq_42().copyForPlanKey();
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
@Test
public void equals_when_havingNullFirst() {
SpiExpression having1 = list_id_eq_42().copyForPlanKey();
OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null);
OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, null, null, null, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, false, null, null);
assertSame(key1, key2);
}
private void assertDifferent(OrmQueryPlanKey key1, OrmQueryPlanKey key2) {
assertThat(key1).isNotEqualTo(key2);
assertThat(key1.hashCode()).isNotEqualTo(key2.hashCode());
}
private void assertSame(OrmQueryPlanKey key1, OrmQueryPlanKey key2) {
assertThat(key1).isEqualTo(key2);
assertThat(key1.hashCode()).isEqualTo(key2.hashCode());
}
}