package io.ebeaninternal.server.expression;

import io.ebean.CacheMode;
import io.ebean.CountDistinctOrder;
import io.ebean.DtoQuery;
import io.ebean.Expression;
import io.ebean.ExpressionList;
import io.ebean.FetchGroup;
import io.ebean.FetchPath;
import io.ebean.FutureIds;
import io.ebean.FutureList;
import io.ebean.FutureRowCount;
import io.ebean.Junction;
import io.ebean.OrderBy;
import io.ebean.PagedList;
import io.ebean.Pairs;
import io.ebean.Query;
import io.ebean.QueryIterator;
import io.ebean.Transaction;
import io.ebean.UpdateQuery;
import io.ebean.Version;
import io.ebean.event.BeanQueryRequest;
import io.ebean.search.Match;
import io.ebean.search.MultiMatch;
import io.ebean.search.TextCommonTerms;
import io.ebean.search.TextQueryString;
import io.ebean.search.TextSimple;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.NaturalKeyQueryData;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiExpressionValidation;
import io.ebeaninternal.api.SpiJunction;
import io.ebeaninternal.server.deploy.BeanDescriptor;

import java.io.IOException;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;

Junction implementation.
/** * Junction implementation. */
class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, ExpressionList<T> { protected DefaultExpressionList<T> exprList; protected Junction.Type type; JunctionExpression(Junction.Type type, Query<T> query, ExpressionList<T> parent) { this.type = type; this.exprList = new DefaultExpressionList<>(query, parent); }
Construct for copyForPlanKey.
/** * Construct for copyForPlanKey. */
JunctionExpression(Junction.Type type, DefaultExpressionList<T> exprList) { this.type = type; this.exprList = exprList; } @Override public boolean naturalKey(NaturalKeyQueryData<?> data) { // can't use naturalKey cache return false; }
Simplify nested expressions where possible.

This is expected to only used after expressions are built via query language parsing.

/** * Simplify nested expressions where possible. * <p> * This is expected to only used after expressions are built via query language parsing. * </p> */
@SuppressWarnings("unchecked") @Override public void simplify() { exprList.simplifyEntries(); List<SpiExpression> list = exprList.list; if (list.size() == 1 && list.get(0) instanceof JunctionExpression) { @SuppressWarnings("rawtypes") JunctionExpression nested = (JunctionExpression) list.get(0); if (type == Type.AND && !nested.type.isText()) { // and (and (a, b, c)) -> and (a, b, c) // and (not (a, b, c)) -> not (a, b, c) // and (or (a, b, c)) -> or (a, b, c) this.exprList = nested.exprList; this.type = nested.type; } else if (type == Type.NOT && nested.type == Type.AND) { // not (and (a, b, c)) -> not (a, b, c) this.exprList = nested.exprList; } } } @Override public SpiExpression copyForPlanKey() { return new JunctionExpression<>(type, exprList.copyForPlanKey()); } @Override public void writeDocQuery(DocQueryContext context) throws IOException { context.startBool(type); List<SpiExpression> list = exprList.internalList(); for (SpiExpression aList : list) { aList.writeDocQuery(context); } context.endBool(); } @Override public void writeDocQueryJunction(DocQueryContext context) throws IOException { context.startBoolGroupList(type); List<SpiExpression> list = exprList.internalList(); for (SpiExpression aList : list) { aList.writeDocQuery(context); } context.endBoolGroupList(); } @Override public Object getIdEqualTo(String idName) { // always null for this expression return null; } @Override public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) { List<SpiExpression> list = exprList.internalList(); // get the current state for 'require outer joins' boolean parentOuterJoins = manyWhereJoin.isRequireOuterJoins(); if (type == Type.OR) { // turn on outer joins required for disjunction expressions manyWhereJoin.setRequireOuterJoins(true); } for (SpiExpression aList : list) { aList.containsMany(desc, manyWhereJoin); } if (type == Type.OR && !parentOuterJoins) { // restore state to not forcing outer joins manyWhereJoin.setRequireOuterJoins(false); } } @Override public void validate(SpiExpressionValidation validation) { exprList.validate(validation); } @Override public Junction<T> add(Expression item) { exprList.add(item); return this; } @Override public Junction<T> addAll(ExpressionList<T> addList) { exprList.addAll(addList); return this; } @Override public void addBindValues(SpiExpressionRequest request) { List<SpiExpression> list = exprList.internalList(); for (SpiExpression aList : list) { aList.addBindValues(request); } } @Override public void addSql(SpiExpressionRequest request) { List<SpiExpression> list = exprList.internalList(); if (!list.isEmpty()) { request.append(type.prefix()); request.append("("); for (int i = 0; i < list.size(); i++) { SpiExpression item = list.get(i); if (i > 0) { request.append(type.literal()); } item.addSql(request); } request.append(")"); } } @Override public void prepareExpression(BeanQueryRequest<?> request) { List<SpiExpression> list = exprList.internalList(); for (SpiExpression aList : list) { aList.prepareExpression(request); } }
Based on Junction type and all the expression contained.
/** * Based on Junction type and all the expression contained. */
@Override public void queryPlanHash(StringBuilder builder) { builder.append(type).append("["); List<SpiExpression> list = exprList.internalList(); for (SpiExpression aList : list) { aList.queryPlanHash(builder); builder.append(","); } builder.append("]"); } @Override public int queryBindHash() { int hc = JunctionExpression.class.getName().hashCode(); List<SpiExpression> list = exprList.internalList(); for (SpiExpression aList : list) { hc = hc * 92821 + aList.queryBindHash(); } return hc; } @Override public boolean isSameByBind(SpiExpression other) { JunctionExpression<?> that = (JunctionExpression<?>) other; return type == that.type && exprList.isSameByBind(that.exprList); } @Override public ExpressionList<T> match(String propertyName, String search) { return match(propertyName, search, null); } @Override public ExpressionList<T> match(String propertyName, String search, Match options) { return exprList.match(propertyName, search, options); } @Override public ExpressionList<T> multiMatch(String query, String... properties) { return exprList.multiMatch(query, properties); } @Override public ExpressionList<T> multiMatch(String query, MultiMatch options) { return exprList.multiMatch(query, options); } @Override public ExpressionList<T> textSimple(String search, TextSimple options) { return exprList.textSimple(search, options); } @Override public ExpressionList<T> textQueryString(String search, TextQueryString options) { return exprList.textQueryString(search, options); } @Override public ExpressionList<T> textCommonTerms(String search, TextCommonTerms options) { return exprList.textCommonTerms(search, options); } @Override public ExpressionList<T> allEq(Map<String, Object> propertyMap) { return exprList.allEq(propertyMap); } @Override public ExpressionList<T> and(Expression expOne, Expression expTwo) { return exprList.and(expOne, expTwo); } @Override public ExpressionList<T> inRangeWith(String lowProperty, String highProperty, Object value) { return exprList.inRangeWith(lowProperty, highProperty, value); } @Override public ExpressionList<T> inRange(String propertyName, Object value1, Object value2) { return exprList.inRange(propertyName, value1, value2); } @Override public ExpressionList<T> between(String propertyName, Object value1, Object value2) { return exprList.between(propertyName, value1, value2); } @Override public ExpressionList<T> betweenProperties(String lowProperty, String highProperty, Object value) { return exprList.betweenProperties(lowProperty, highProperty, value); } @Override public ExpressionList<T> contains(String propertyName, String value) { return exprList.contains(propertyName, value); } @Override public ExpressionList<T> endsWith(String propertyName, String value) { return exprList.endsWith(propertyName, value); } @Override public ExpressionList<T> eq(String propertyName, Object value) { return exprList.eq(propertyName, value); } @Override public ExpressionList<T> eqOrNull(String propertyName, Object value) { return exprList.eqOrNull(propertyName, value); } @Override public ExpressionList<T> exampleLike(Object example) { return exprList.exampleLike(example); } @Override public ExpressionList<T> where(String expressions, Object... params) { throw new IllegalStateException("where not allowed on Junction expression list"); } @Override public ExpressionList<T> filterMany(String prop) { throw new IllegalStateException("filterMany not allowed on Junction expression list"); } @Override public ExpressionList<T> filterMany(String manyProperty, String expressions, Object... params) { throw new IllegalStateException("filterMany not allowed on Junction expression list"); } @Override public Query<T> usingTransaction(Transaction transaction) { return exprList.usingTransaction(transaction); } @Override public Query<T> usingConnection(Connection connection) { return exprList.usingConnection(connection); } @Override public int delete() { return exprList.delete(); } @Override public int delete(Transaction transaction) { return exprList.delete(transaction); } @Override public int update() { return exprList.update(); } @Override public int update(Transaction transaction) { return exprList.update(transaction); } @Override public Query<T> asOf(Timestamp asOf) { return exprList.asOf(asOf); } @Override public Query<T> asDraft() { return exprList.asDraft(); } @Override public <D> DtoQuery<D> asDto(Class<D> dtoClass) { return exprList.asDto(dtoClass); } @Override public UpdateQuery<T> asUpdate() { return exprList.asUpdate(); } @Override public Query<T> setIncludeSoftDeletes() { return exprList.setIncludeSoftDeletes(); } @Override public List<Version<T>> findVersions() { return exprList.findVersions(); } @Override public List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end) { return exprList.findVersionsBetween(start, end); } @Override public Query<T> apply(FetchPath fetchPath) { return exprList.apply(fetchPath); } @Override public boolean exists() { return exprList.exists(); } @Override public FutureIds<T> findFutureIds() { return exprList.findFutureIds(); } @Override public FutureList<T> findFutureList() { return exprList.findFutureList(); } @Override public FutureRowCount<T> findFutureCount() { return exprList.findFutureCount(); } @Override public <A> List<A> findIds() { return exprList.findIds(); } @Override public QueryIterator<T> findIterate() { return exprList.findIterate(); } @Override public void findEach(Consumer<T> consumer) { exprList.findEach(consumer); } @Override public void findEachWhile(Predicate<T> consumer) { exprList.findEachWhile(consumer); } @Override public List<T> findList() { return exprList.findList(); } @Override public <K> Map<K, T> findMap() { return exprList.findMap(); } @Override public <A> List<A> findSingleAttributeList() { return exprList.findSingleAttributeList(); } @Override public PagedList<T> findPagedList() { return exprList.findPagedList(); } @Override public int findCount() { return exprList.findCount(); } @Override public Set<T> findSet() { return exprList.findSet(); } @Override public T findOne() { return exprList.findOne(); } @Override public Optional<T> findOneOrEmpty() { return exprList.findOneOrEmpty(); } @Override public Query<T> withLock(Query.LockType lockType) { return exprList.withLock(lockType); } @Override public Query<T> withLock(Query.LockType lockType, Query.LockWait lockWait) { return exprList.withLock(lockType, lockWait); } @Override public Query<T> forUpdate() { return exprList.forUpdate(); } @Override public Query<T> forUpdate(Query.LockType lockType) { return exprList.forUpdate(lockType); } @Override public Query<T> forUpdateNoWait() { return exprList.forUpdateNoWait(); } @Override public Query<T> forUpdateNoWait(Query.LockType lockType) { return exprList.forUpdateNoWait(lockType); } @Override public Query<T> forUpdateSkipLocked() { return exprList.forUpdateSkipLocked(); } @Override public Query<T> forUpdateSkipLocked(Query.LockType lockType) { return exprList.forUpdateSkipLocked(lockType); }
Path exists - for the given path in a JSON document.
/** * Path exists - for the given path in a JSON document. */
@Override public ExpressionList<T> jsonExists(String propertyName, String path) { return exprList.jsonExists(propertyName, path); }
Path does not exist - for the given path in a JSON document.
/** * Path does not exist - for the given path in a JSON document. */
@Override public ExpressionList<T> jsonNotExists(String propertyName, String path) { return exprList.jsonNotExists(propertyName, path); }
Equal to - for the value at the given path in the JSON document.
/** * Equal to - for the value at the given path in the JSON document. */
@Override public ExpressionList<T> jsonEqualTo(String propertyName, String path, Object value) { return exprList.jsonEqualTo(propertyName, path, value); }
Not Equal to - for the given path in a JSON document.
/** * Not Equal to - for the given path in a JSON document. */
@Override public ExpressionList<T> jsonNotEqualTo(String propertyName, String path, Object val) { return exprList.jsonNotEqualTo(propertyName, path, val); }
Greater than - for the given path in a JSON document.
/** * Greater than - for the given path in a JSON document. */
@Override public ExpressionList<T> jsonGreaterThan(String propertyName, String path, Object val) { return exprList.jsonGreaterThan(propertyName, path, val); }
Greater than or equal to - for the given path in a JSON document.
/** * Greater than or equal to - for the given path in a JSON document. */
@Override public ExpressionList<T> jsonGreaterOrEqual(String propertyName, String path, Object val) { return exprList.jsonGreaterOrEqual(propertyName, path, val); }
Less than - for the given path in a JSON document.
/** * Less than - for the given path in a JSON document. */
@Override public ExpressionList<T> jsonLessThan(String propertyName, String path, Object val) { return exprList.jsonLessThan(propertyName, path, val); }
Less than or equal to - for the given path in a JSON document.
/** * Less than or equal to - for the given path in a JSON document. */
@Override public ExpressionList<T> jsonLessOrEqualTo(String propertyName, String path, Object val) { return exprList.jsonLessOrEqualTo(propertyName, path, val); }
Between - for the given path in a JSON document.
/** * Between - for the given path in a JSON document. */
@Override public ExpressionList<T> jsonBetween(String propertyName, String path, Object lowerValue, Object upperValue) { return exprList.jsonBetween(propertyName, path, lowerValue, upperValue); } @Override public ExpressionList<T> arrayContains(String propertyName, Object... values) { return exprList.arrayContains(propertyName, values); } @Override public ExpressionList<T> arrayNotContains(String propertyName, Object... values) { return exprList.arrayNotContains(propertyName, values); } @Override public ExpressionList<T> arrayIsEmpty(String propertyName) { return exprList.arrayIsEmpty(propertyName); } @Override public ExpressionList<T> arrayIsNotEmpty(String propertyName) { return exprList.arrayIsNotEmpty(propertyName); } @Override public ExpressionList<T> bitwiseAny(String propertyName, long flags) { return exprList.bitwiseAny(propertyName, flags); } @Override public ExpressionList<T> bitwiseAll(String propertyName, long flags) { return exprList.bitwiseAll(propertyName, flags); } @Override public ExpressionList<T> bitwiseAnd(String propertyName, long flags, long match) { return exprList.bitwiseAnd(propertyName, flags, match); } @Override public ExpressionList<T> bitwiseNot(String propertyName, long flags) { return exprList.bitwiseNot(propertyName, flags); } @Override public ExpressionList<T> ge(String propertyName, Object value) { return exprList.ge(propertyName, value); } @Override public ExpressionList<T> gt(String propertyName, Object value) { return exprList.gt(propertyName, value); } @Override public ExpressionList<T> gtOrNull(String propertyName, Object value) { return exprList.gtOrNull(propertyName, value); } @Override public ExpressionList<T> geOrNull(String propertyName, Object value) { return exprList.geOrNull(propertyName, value); } @Override public ExpressionList<T> having() { throw new IllegalStateException("having() not allowed on Junction expression list"); } @Override public ExpressionList<T> icontains(String propertyName, String value) { return exprList.icontains(propertyName, value); } @Override public ExpressionList<T> idEq(Object value) { return exprList.idEq(value); } @Override public ExpressionList<T> idIn(Object... idValues) { return exprList.idIn(idValues); } @Override public ExpressionList<T> idIn(Collection<?> idValues) { return exprList.idIn(idValues); } @Override public ExpressionList<T> iendsWith(String propertyName, String value) { return exprList.iendsWith(propertyName, value); } @Override public ExpressionList<T> ieq(String propertyName, String value) { return exprList.ieq(propertyName, value); } @Override public ExpressionList<T> ine(String propertyName, String value) { return exprList.ine(propertyName, value); } @Override public ExpressionList<T> iexampleLike(Object example) { return exprList.iexampleLike(example); } @Override public ExpressionList<T> ilike(String propertyName, String value) { return exprList.ilike(propertyName, value); } @Override public ExpressionList<T> inPairs(Pairs pairs) { return exprList.inPairs(pairs); } @Override public ExpressionList<T> in(String propertyName, Collection<?> values) { return exprList.in(propertyName, values); } @Override public ExpressionList<T> inOrEmpty(String propertyName, Collection<?> values) { return exprList.inOrEmpty(propertyName, values); } @Override public ExpressionList<T> in(String propertyName, Object... values) { return exprList.in(propertyName, values); } @Override public ExpressionList<T> in(String propertyName, Query<?> subQuery) { return exprList.in(propertyName, subQuery); } @Override public ExpressionList<T> notIn(String propertyName, Collection<?> values) { return exprList.notIn(propertyName, values); } @Override public ExpressionList<T> notIn(String propertyName, Object... values) { return exprList.notIn(propertyName, values); } @Override public ExpressionList<T> notIn(String propertyName, Query<?> subQuery) { return exprList.notIn(propertyName, subQuery); } @Override public ExpressionList<T> isEmpty(String propertyName) { return exprList.isEmpty(propertyName); } @Override public ExpressionList<T> isNotEmpty(String propertyName) { return exprList.isNotEmpty(propertyName); } @Override public ExpressionList<T> exists(Query<?> subQuery) { return exprList.exists(subQuery); } @Override public ExpressionList<T> notExists(Query<?> subQuery) { return exprList.notExists(subQuery); } @Override public ExpressionList<T> isNotNull(String propertyName) { return exprList.isNotNull(propertyName); } @Override public ExpressionList<T> isNull(String propertyName) { return exprList.isNull(propertyName); } @Override public ExpressionList<T> istartsWith(String propertyName, String value) { return exprList.istartsWith(propertyName, value); } @Override public ExpressionList<T> le(String propertyName, Object value) { return exprList.le(propertyName, value); } @Override public ExpressionList<T> like(String propertyName, String value) { return exprList.like(propertyName, value); } @Override public ExpressionList<T> lt(String propertyName, Object value) { return exprList.lt(propertyName, value); } @Override public ExpressionList<T> ltOrNull(String propertyName, Object value) { return exprList.ltOrNull(propertyName, value); } @Override public ExpressionList<T> leOrNull(String propertyName, Object value) { return exprList.leOrNull(propertyName, value); } @Override public ExpressionList<T> ne(String propertyName, Object value) { return exprList.ne(propertyName, value); } @Override public ExpressionList<T> not(Expression exp) { return exprList.not(exp); } @Override public ExpressionList<T> or(Expression expOne, Expression expTwo) { return exprList.or(expOne, expTwo); } @Override public OrderBy<T> order() { return exprList.order(); } @Override public ExpressionList<T> order(String orderByClause) { return exprList.order(orderByClause); } @Override public OrderBy<T> orderBy() { return exprList.orderBy(); } @Override public ExpressionList<T> orderBy(String orderBy) { return exprList.orderBy(orderBy); } @Override public Query<T> orderById(boolean orderById) { return exprList.orderById(orderById); } @Override public Query<T> query() { return exprList.query(); } @Override public ExpressionList<T> raw(String raw, Object value) { return exprList.raw(raw, value); } @Override public ExpressionList<T> raw(String raw, Object... values) { return exprList.raw(raw, values); } @Override public ExpressionList<T> rawOrEmpty(String raw, Collection<?> values) { return exprList.rawOrEmpty(raw, values); } @Override public ExpressionList<T> raw(String raw) { return exprList.raw(raw); } @Override public Query<T> select(String properties) { return exprList.select(properties); } @Override public Query<T> select(FetchGroup fetchGroup) { return exprList.select(fetchGroup); } @Override public Query<T> setDistinct(boolean distinct) { return exprList.setDistinct(distinct); } @Override public Query<T> setDocIndexName(String indexName) { return exprList.setDocIndexName(indexName); } @Override public ExpressionList<T> setFirstRow(int firstRow) { return exprList.setFirstRow(firstRow); } @Override public Query<T> setMapKey(String mapKey) { return exprList.setMapKey(mapKey); } @Override public ExpressionList<T> setMaxRows(int maxRows) { return exprList.setMaxRows(maxRows); } @Override public Query<T> setOrderBy(String orderBy) { return exprList.setOrderBy(orderBy); } @Override public Query<T> setUseCache(boolean useCache) { return exprList.setUseCache(useCache); } @Override public Query<T> setBeanCacheMode(CacheMode useCache) { return exprList.setBeanCacheMode(useCache); } @Override public Query<T> setUseQueryCache(CacheMode useCache) { return exprList.setUseQueryCache(useCache); } @Override public Query<T> setUseDocStore(boolean useDocsStore) { return exprList.setUseDocStore(useDocsStore); } @Override public Query<T> setDisableLazyLoading(boolean disableLazyLoading) { return exprList.setDisableLazyLoading(disableLazyLoading); } @Override public Query<T> setDisableReadAuditing() { return exprList.setDisableReadAuditing(); } @Override public Query<T> setCountDistinct(CountDistinctOrder orderBy) { return exprList.setCountDistinct(orderBy); } @Override public Query<T> setLabel(String label) { return exprList.setLabel(label); } @Override public ExpressionList<T> startsWith(String propertyName, String value) { return exprList.startsWith(propertyName, value); } @Override public ExpressionList<T> where() { return exprList.where(); } @Override public Junction<T> and() { return conjunction(); } @Override public Junction<T> or() { return disjunction(); } @Override public Junction<T> not() { return exprList.not(); } @Override public Junction<T> conjunction() { return exprList.conjunction(); } @Override public Junction<T> disjunction() { return exprList.disjunction(); } @Override public Junction<T> must() { return exprList.must(); } @Override public Junction<T> should() { return exprList.should(); } @Override public Junction<T> mustNot() { return exprList.mustNot(); } @Override public ExpressionList<T> endJunction() { return exprList.endJunction(); } @Override public ExpressionList<T> endAnd() { return endJunction(); } @Override public ExpressionList<T> endOr() { return endJunction(); } @Override public ExpressionList<T> endNot() { return endJunction(); } @Override public String nestedPath(BeanDescriptor<?> desc) { PrepareDocNested.prepare(exprList, desc, type); String nestedPath = exprList.allDocNestedPath; if (nestedPath != null) { // push the nestedPath up to parent exprList.setAllDocNested(null); return nestedPath; } return null; } }