com.avaje.ebeaninternal.server.expression.DefaultExpressionList Maven / Gradle / Ivy
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.*;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebean.search.Match;
import com.avaje.ebean.search.MultiMatch;
import com.avaje.ebean.search.TextCommonTerms;
import com.avaje.ebean.search.TextQueryString;
import com.avaje.ebean.search.TextSimple;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.ManyWhereJoins;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionList;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
import com.avaje.ebeaninternal.api.SpiJunction;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Default implementation of ExpressionList.
*/
public class DefaultExpressionList implements SpiExpressionList {
private static final String AND = " and ";
protected List list;
protected final Query query;
private final ExpressionList parentExprList;
protected transient ExpressionFactory expr;
protected String allDocNestedPath;
/**
* Set to true for the "Text" root expression list.
*/
private final boolean textRoot;
/**
* Construct for Text root expression list - this handles implicit Bool Should, Must etc.
*/
public DefaultExpressionList(Query query) {
this(query, query.getExpressionFactory(), null, new ArrayList<>(), true);
}
public DefaultExpressionList(Query query, ExpressionList parentExprList) {
this(query, query.getExpressionFactory(), parentExprList);
}
DefaultExpressionList(Query query, ExpressionFactory expr, ExpressionList parentExprList) {
this(query, expr, parentExprList, new ArrayList<>());
}
DefaultExpressionList(Query query, ExpressionFactory expr, ExpressionList parentExprList, List list) {
this(query, expr, parentExprList, list, false);
}
private DefaultExpressionList(Query query, ExpressionFactory expr, ExpressionList parentExprList, List list, boolean textRoot) {
this.textRoot = textRoot;
this.list = list;
this.query = query;
this.expr = expr;
this.parentExprList = parentExprList;
}
private DefaultExpressionList() {
this(null, null, null, new ArrayList<>());
}
/**
* Wrap the expression list as a Junction or top level DefaultExpressionList.
*
* @param list The list of expressions grouped by nested path
* @param nestedPath The doc store nested path
* @param type The junction type (or null for top level expression list).
* @return A single SpiExpression that has the nestedPath set
*/
SpiExpression wrap(List list, String nestedPath, Junction.Type type) {
DefaultExpressionList wrapper = new DefaultExpressionList<>(query, expr, null, list, false);
wrapper.setAllDocNested(nestedPath);
if (type != null) {
return new JunctionExpression<>(type, wrapper);
} else {
return wrapper;
}
}
void simplifyEntries() {
for (SpiExpression element : list) {
element.simplify();
}
}
@Override
public Junction toJunction() {
return new JunctionExpression<>(Junction.Type.FILTER, this);
}
public void simplify() {
simplifyEntries();
}
/**
* Write being aware if it is the Top level "text" expressions.
*
* If this is the Top level "text" expressions then it detects if explicit or implicit Bool Should, Must etc is required
* to wrap the expressions.
*
*
* If implicit Bool is required SHOULD is used.
*
*/
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
if (!textRoot) {
writeDocQuery(context, null);
} else {
// this is a Top level "text" expressions so we may need to wrap in Bool SHOULD etc.
if (list.isEmpty()) throw new IllegalStateException("empty expression list?");
if (allDocNestedPath!=null) context.startNested(allDocNestedPath);
int size = list.size();
SpiExpression first = list.get(0);
boolean explicitBool = first instanceof SpiJunction>;
boolean implicitBool = !explicitBool && size > 1;
if (implicitBool || explicitBool) {
context.startBoolGroup();
}
if (implicitBool) {
context.startBoolGroupList(Junction.Type.SHOULD);
}
for (SpiExpression expr : list) {
if (explicitBool) {
try {
((SpiJunction>) expr).writeDocQueryJunction(context);
} catch (ClassCastException e) {
throw new IllegalStateException("The top level text() expressions should be all be 'Must', 'Should' or 'Must Not' or none of them should be.", e);
}
} else {
expr.writeDocQuery(context);
}
}
if (implicitBool) {
context.endBoolGroupList();
}
if (implicitBool || explicitBool) {
context.endBoolGroup();
}
if (allDocNestedPath!=null) context.endNested();
}
}
public void writeDocQuery(DocQueryContext context, SpiExpression idEquals) throws IOException {
if (allDocNestedPath!=null) context.startNested(allDocNestedPath);
int size = list.size();
if (size == 1 && idEquals == null) {
// only 1 expression - skip bool
list.get(0).writeDocQuery(context);
} else if (size == 0 && idEquals != null) {
// only idEquals - skip bool
idEquals.writeDocQuery(context);
} else {
// bool must wrap all the children
context.startBoolMust();
if (idEquals != null) {
idEquals.writeDocQuery(context);
}
for (SpiExpression aList : list) {
aList.writeDocQuery(context);
}
context.endBool();
}
if (allDocNestedPath!=null) context.endNested();
}
@Override
public SpiExpressionList> trimPath(int prefixTrim) {
throw new RuntimeException("Only allowed on FilterExpressionList");
}
public List internalList() {
return list;
}
/**
* Return a copy of the expression list.
*
* Each of the expressions are expected to be immutable and safe to reference.
*
*/
public DefaultExpressionList copy(Query query) {
DefaultExpressionList copy = new DefaultExpressionList<>(query, expr, null);
copy.list.addAll(list);
return copy;
}
public DefaultExpressionList copyForPlanKey() {
DefaultExpressionList copy = new DefaultExpressionList<>();
for (int i = 0; i < list.size(); i++) {
copy.list.add(list.get(i).copyForPlanKey());
}
return copy;
}
@Override
public Object getIdEqualTo(String idName) {
// always return null for this expression
return null;
}
/**
* Return true if one of the expressions is related to a Many property.
*/
@Override
public void containsMany(BeanDescriptor> desc, ManyWhereJoins whereManyJoins) {
for (SpiExpression aList : list) {
aList.containsMany(desc, whereManyJoins);
}
}
@Override
public void validate(SpiExpressionValidation validation) {
for (SpiExpression aList : list) {
aList.validate(validation);
}
}
@Override
public Query query() {
return query;
}
@Override
public Query asOf(Timestamp asOf) {
return query.asOf(asOf);
}
@Override
public Query asDraft() {
return query.asDraft();
}
@Override
public Query setIncludeSoftDeletes() {
return query.setIncludeSoftDeletes();
}
@Override
public List> findVersions() {
return query.findVersions();
}
@Override
public List> findVersionsBetween(Timestamp start, Timestamp end) {
return query.findVersionsBetween(start, end);
}
@Override
public ExpressionList where() {
return query.where();
}
@Override
public OrderBy order() {
return query.order();
}
@Override
public OrderBy orderBy() {
return query.order();
}
@Override
public Query order(String orderByClause) {
return query.order(orderByClause);
}
@Override
public Query orderBy(String orderBy) {
return query.order(orderBy);
}
@Override
public Query setOrderBy(String orderBy) {
return query.order(orderBy);
}
@Override
public Query apply(FetchPath fetchPath) {
return query.apply(fetchPath);
}
@Override
public int delete() {
return query.delete();
}
@Override
public int update() {
return query.update();
}
@Override
public FutureIds findFutureIds() {
return query.findFutureIds();
}
@Override
public FutureRowCount findFutureCount() {
return query.findFutureCount();
}
@Override
public FutureList findFutureList() {
return query.findFutureList();
}
@Override
public PagedList findPagedList() {
return query.findPagedList();
}
@Override
public int findCount() {
return query.findCount();
}
@Override
public List findIds() {
return query.findIds();
}
@Override
public QueryIterator findIterate() {
return query.findIterate();
}
@Override
public void findEach(QueryEachConsumer consumer) {
query.findEach(consumer);
}
@Override
public void findEachWhile(QueryEachWhileConsumer consumer) {
query.findEachWhile(consumer);
}
@Override
public List findList() {
return query.findList();
}
@Override
public Set findSet() {
return query.findSet();
}
@Override
public Map findMap() {
return query.findMap();
}
@Override
public List findSingleAttributeList() {
return query.findSingleAttributeList();
}
@Override
public T findUnique() {
return query.findUnique();
}
@Override
public ExpressionList filterMany(String prop) {
return query.filterMany(prop);
}
@Override
public Query select(String fetchProperties) {
return query.select(fetchProperties);
}
@Override
public Query setDistinct(boolean distinct) {
return query.setDistinct(distinct);
}
@Override
public Query setFirstRow(int firstRow) {
return query.setFirstRow(firstRow);
}
@Override
public Query setMaxRows(int maxRows) {
return query.setMaxRows(maxRows);
}
@Override
public Query setMapKey(String mapKey) {
return query.setMapKey(mapKey);
}
@Override
public Query setUseCache(boolean useCache) {
return query.setUseCache(useCache);
}
@Override
public Query setUseQueryCache(boolean useCache) {
return query.setUseQueryCache(useCache);
}
@Override
public Query setUseDocStore(boolean useDocsStore) {
return query.setUseDocStore(useDocsStore);
}
@Override
public Query setDisableLazyLoading(boolean disableLazyLoading) {
return query.setDisableLazyLoading(disableLazyLoading);
}
@Override
public Query setDisableReadAuditing() {
return query.setDisableReadAuditing();
}
@Override
public ExpressionList having() {
return query.having();
}
@Override
public ExpressionList add(Expression expr) {
list.add((SpiExpression) expr);
return this;
}
@Override
public ExpressionList addAll(ExpressionList exprList) {
SpiExpressionList spiList = (SpiExpressionList) exprList;
list.addAll(spiList.getUnderlyingList());
return this;
}
@Override
public List getUnderlyingList() {
return list;
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public void addSql(SpiExpressionRequest request) {
for (int i = 0, size = list.size(); i < size; i++) {
SpiExpression expression = list.get(i);
if (i > 0) {
request.append(AND);
}
expression.addSql(request);
}
}
@Override
public void addBindValues(SpiExpressionRequest request) {
for (SpiExpression aList : list) {
aList.addBindValues(request);
}
}
@Override
public void prepareExpression(BeanQueryRequest> request) {
for (SpiExpression aList : list) {
aList.prepareExpression(request);
}
}
/**
* Calculate a hash based on the expressions but excluding the actual bind
* values.
*/
@Override
public void queryPlanHash(HashQueryPlanBuilder builder) {
builder.add(DefaultExpressionList.class);
for (SpiExpression aList : list) {
aList.queryPlanHash(builder);
}
}
/**
* Calculate a hash based on the expressions.
*/
@Override
public int queryBindHash() {
int hash = DefaultExpressionList.class.getName().hashCode();
for (SpiExpression aList : list) {
hash = hash * 92821 + aList.queryBindHash();
}
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.
*/
@Override
public ExpressionList jsonExists(String propertyName, String path) {
add(expr.jsonExists(propertyName, path));
return this;
}
/**
* Path does not exist - for the given path in a JSON document.
*/
@Override
public ExpressionList jsonNotExists(String propertyName, String path) {
add(expr.jsonNotExists(propertyName, path));
return this;
}
/**
* Equal to expression for the value at the given path in the JSON document.
*/
@Override
public ExpressionList jsonEqualTo(String propertyName, String path, Object value) {
add(expr.jsonEqualTo(propertyName, path, value));
return this;
}
/**
* Not Equal to - for the given path in a JSON document.
*/
@Override
public ExpressionList jsonNotEqualTo(String propertyName, String path, Object val) {
add(expr.jsonNotEqualTo(propertyName, path, val));
return this;
}
/**
* Greater than - for the given path in a JSON document.
*/
@Override
public ExpressionList jsonGreaterThan(String propertyName, String path, Object val) {
add(expr.jsonGreaterThan(propertyName, path, val));
return this;
}
/**
* Greater than or equal to - for the given path in a JSON document.
*/
@Override
public ExpressionList jsonGreaterOrEqual(String propertyName, String path, Object val) {
add(expr.jsonGreaterOrEqual(propertyName, path, val));
return this;
}
/**
* Less than - for the given path in a JSON document.
*/
@Override
public ExpressionList jsonLessThan(String propertyName, String path, Object val) {
add(expr.jsonLessThan(propertyName, path, val));
return this;
}
/**
* Less than or equal to - for the given path in a JSON document.
*/
@Override
public ExpressionList jsonLessOrEqualTo(String propertyName, String path, Object val) {
add(expr.jsonLessOrEqualTo(propertyName, path, val));
return this;
}
/**
* Between - for the given path in a JSON document.
*/
@Override
public ExpressionList jsonBetween(String propertyName, String path, Object lowerValue, Object upperValue) {
add(expr.jsonBetween(propertyName, path, lowerValue, upperValue));
return this;
}
@Override
public ExpressionList eq(String propertyName, Object value) {
add(expr.eq(propertyName, value));
return this;
}
@Override
public ExpressionList ieq(String propertyName, String value) {
add(expr.ieq(propertyName, value));
return this;
}
@Override
public ExpressionList ne(String propertyName, Object value) {
add(expr.ne(propertyName, value));
return this;
}
@Override
public ExpressionList allEq(Map propertyMap) {
add(expr.allEq(propertyMap));
return this;
}
@Override
public ExpressionList and(Expression expOne, Expression expTwo) {
add(expr.and(expOne, expTwo));
return this;
}
@Override
public ExpressionList between(String propertyName, Object value1, Object value2) {
add(expr.between(propertyName, value1, value2));
return this;
}
@Override
public ExpressionList betweenProperties(String lowProperty, String highProperty, Object value) {
add(expr.betweenProperties(lowProperty, highProperty, value));
return this;
}
@Override
public ExpressionList contains(String propertyName, String value) {
add(expr.contains(propertyName, value));
return this;
}
@Override
public ExpressionList endsWith(String propertyName, String value) {
add(expr.endsWith(propertyName, value));
return this;
}
@Override
public ExpressionList ge(String propertyName, Object value) {
add(expr.ge(propertyName, value));
return this;
}
@Override
public ExpressionList gt(String propertyName, Object value) {
add(expr.gt(propertyName, value));
return this;
}
@Override
public ExpressionList icontains(String propertyName, String value) {
add(expr.icontains(propertyName, value));
return this;
}
@Override
public ExpressionList idIn(Object... idValues) {
add(expr.idIn(idValues));
return this;
}
@Override
public ExpressionList idIn(List> idList) {
add(expr.idIn(idList));
return this;
}
@Override
public ExpressionList idEq(Object value) {
if (query != null && parentExprList == null) {
query.setId(value);
} else {
add(expr.idEq(value));
}
return this;
}
@Override
public ExpressionList iendsWith(String propertyName, String value) {
add(expr.iendsWith(propertyName, value));
return this;
}
@Override
public ExpressionList ilike(String propertyName, String value) {
add(expr.ilike(propertyName, value));
return this;
}
@Override
public ExpressionList in(String propertyName, Query> subQuery) {
add(expr.in(propertyName, subQuery));
return this;
}
@Override
public ExpressionList in(String propertyName, Collection> values) {
add(expr.in(propertyName, values));
return this;
}
@Override
public ExpressionList in(String propertyName, Object... values) {
add(expr.in(propertyName, values));
return this;
}
@Override
public ExpressionList notIn(String propertyName, Object... values) {
add(expr.notIn(propertyName, values));
return this;
}
@Override
public ExpressionList notIn(String propertyName, Collection> values) {
add(expr.notIn(propertyName, values));
return this;
}
@Override
public ExpressionList notIn(String propertyName, Query> subQuery) {
add(expr.notIn(propertyName, subQuery));
return this;
}
@Override
public ExpressionList isEmpty(String propertyName) {
add(expr.isEmpty(propertyName));
return this;
}
@Override
public ExpressionList isNotEmpty(String propertyName) {
add(expr.isNotEmpty(propertyName));
return this;
}
@Override
public ExpressionList exists(Query> subQuery) {
add(expr.exists(subQuery));
return this;
}
@Override
public ExpressionList notExists(Query> subQuery) {
add(expr.notExists(subQuery));
return this;
}
@Override
public ExpressionList isNotNull(String propertyName) {
add(expr.isNotNull(propertyName));
return this;
}
@Override
public ExpressionList isNull(String propertyName) {
add(expr.isNull(propertyName));
return this;
}
@Override
public ExpressionList istartsWith(String propertyName, String value) {
add(expr.istartsWith(propertyName, value));
return this;
}
@Override
public ExpressionList le(String propertyName, Object value) {
add(expr.le(propertyName, value));
return this;
}
@Override
public ExpressionList exampleLike(Object example) {
add(expr.exampleLike(example));
return this;
}
@Override
public ExpressionList iexampleLike(Object example) {
add(expr.iexampleLike(example));
return this;
}
@Override
public ExpressionList like(String propertyName, String value) {
add(expr.like(propertyName, value));
return this;
}
@Override
public ExpressionList lt(String propertyName, Object value) {
add(expr.lt(propertyName, value));
return this;
}
@Override
public ExpressionList not(Expression exp) {
add(expr.not(exp));
return this;
}
@Override
public ExpressionList or(Expression expOne, Expression expTwo) {
add(expr.or(expOne, expTwo));
return this;
}
@Override
public ExpressionList arrayContains(String propertyName, Object... elementValue) {
add(expr.arrayContains(propertyName, elementValue));
return this;
}
@Override
public ExpressionList arrayNotContains(String propertyName, Object... values) {
add(expr.arrayNotContains(propertyName, values));
return this;
}
@Override
public ExpressionList arrayIsEmpty(String propertyName) {
add(expr.arrayIsEmpty(propertyName));
return this;
}
@Override
public ExpressionList arrayIsNotEmpty(String propertyName) {
add(expr.arrayIsNotEmpty(propertyName));
return this;
}
@Override
public ExpressionList raw(String raw, Object value) {
add(expr.raw(raw, value));
return this;
}
@Override
public ExpressionList raw(String raw, Object... values) {
add(expr.raw(raw, values));
return this;
}
@Override
public ExpressionList raw(String raw) {
add(expr.raw(raw));
return this;
}
@Override
public ExpressionList startsWith(String propertyName, String value) {
add(expr.startsWith(propertyName, value));
return this;
}
@Override
public ExpressionList match(String propertyName, String search) {
return match(propertyName, search, null);
}
@Override
public ExpressionList match(String propertyName, String search, Match options) {
add(expr.textMatch(propertyName, search, options));
setUseDocStore(true);
return this;
}
@Override
public ExpressionList multiMatch(String query, String... fields) {
return multiMatch(query, MultiMatch.fields(fields));
}
@Override
public ExpressionList multiMatch(String query, MultiMatch options) {
setUseDocStore(true);
add(expr.textMultiMatch(query, options));
return this;
}
@Override
public ExpressionList textSimple(String search, TextSimple options) {
setUseDocStore(true);
add(expr.textSimple(search, options));
return this;
}
@Override
public ExpressionList textQueryString(String search, TextQueryString options) {
setUseDocStore(true);
add(expr.textQueryString(search, options));
return this;
}
@Override
public ExpressionList textCommonTerms(String search, TextCommonTerms options) {
setUseDocStore(true);
add(expr.textCommonTerms(search, options));
return this;
}
private Junction junction(Junction.Type type) {
Junction junction = expr.junction(type, query, this);
add(junction);
return junction;
}
@Override
public ExpressionList endJunction() {
return parentExprList == null ? this : parentExprList;
}
@Override
public ExpressionList endAnd() {
return endJunction();
}
@Override
public ExpressionList endOr() {
return endJunction();
}
@Override
public ExpressionList endNot() {
return endJunction();
}
@Override
public Junction and() {
return conjunction();
}
@Override
public Junction or() {
return disjunction();
}
@Override
public Junction not() {
return junction(Junction.Type.NOT);
}
@Override
public Junction conjunction() {
return junction(Junction.Type.AND);
}
@Override
public Junction disjunction() {
return junction(Junction.Type.OR);
}
@Override
public Junction must() {
setUseDocStore(true);
return junction(Junction.Type.MUST);
}
@Override
public Junction should() {
setUseDocStore(true);
return junction(Junction.Type.SHOULD);
}
@Override
public Junction mustNot() {
setUseDocStore(true);
return junction(Junction.Type.MUST_NOT);
}
@Override
public String nestedPath(BeanDescriptor> desc) {
// effectively handled by JunctionExpression
return null;
}
/**
* Set the nested path that all contained expressions share.
*/
public void setAllDocNested(String allDocNestedPath) {
this.allDocNestedPath = allDocNestedPath;
}
/**
* Replace the underlying expression list with one organised by nested path.
*/
public void setUnderlying(List groupedByNesting) {
this.list = groupedByNesting;
}
/**
* Prepare expressions for document store nested path handling.
*/
public void prepareDocNested(BeanDescriptor beanDescriptor) {
PrepareDocNested.prepare(this, beanDescriptor);
}
public Object idEqualTo(String idName) {
if (list.size() == 1) {
return list.get(0).getIdEqualTo(idName);
}
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy