Merge pull request #3009 from ebean-orm/build/13-16

Build 13.17.0
This commit is contained in:
Rob Bygrave
2023-04-06 14:09:53 +12:00
committed by GitHub
76 changed files with 1120 additions and 489 deletions
@@ -1,10 +1,6 @@
package io.ebean;
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.ebean.search.*;
import java.util.Collection;
import java.util.Map;
@@ -423,6 +419,94 @@ public interface ExpressionFactory {
*/
Expression inOrEmpty(String propertyName, Collection<?> values);
/**
* EXISTS a raw SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
Expression exists(String sqlSubQuery, Object... bindValues);
/**
* Not EXISTS a raw SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
Expression notExists(String sqlSubQuery, Object... bindValues);
/**
* IN a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
Expression inSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Not IN a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
Expression notInSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Equal To a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
Expression eqSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Not Equal To a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
Expression neSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Greater Than or Equal To a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
Expression geSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Greater Than a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
Expression gtSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Less Than or Equal To a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
Expression leSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Less Than a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
Expression ltSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Not In - property has a value in the array of values.
*/
@@ -1141,6 +1141,94 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> inPairs(Pairs pairs);
/**
* EXISTS a raw SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList<T> exists(String sqlSubQuery, Object... bindValues);
/**
* Not EXISTS a raw SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList<T> notExists(String sqlSubQuery, Object... bindValues);
/**
* IN a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList<T> inSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Not IN a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList<T> notInSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Equal To a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList<T> eqSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Not Equal To a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList<T> neSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Greater Than a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList<T> gtSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Greater Than or Equal To a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList<T> geSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Less Than a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList<T> ltSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Less Than or Equal To a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList<T> leSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* In - using a subQuery.
*/
@@ -13,7 +13,7 @@ public interface BeanLoader {
/**
* Return the name of the associated Database.
*/
String getName();
String name();
/**
* Invoke the lazy loading for this bean.
@@ -192,13 +192,13 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
public void setBeanLoader(BeanLoader beanLoader, PersistenceContext ctx) {
this.beanLoader = beanLoader;
this.persistenceContext = ctx;
this.ebeanServerName = beanLoader.getName();
this.ebeanServerName = beanLoader.name();
}
@Override
public void setBeanLoader(BeanLoader beanLoader) {
this.beanLoader = beanLoader;
this.ebeanServerName = beanLoader.getName();
this.ebeanServerName = beanLoader.name();
}
@Override
@@ -19,7 +19,7 @@ public abstract class SingleBeanLoader implements BeanLoader {
}
@Override
public String getName() {
public String name() {
return database.name();
}
@@ -16,7 +16,7 @@ public interface LoadContext {
/**
* Return the minimum batch size when using QueryIterator with query joins.
*/
int getSecondaryQueriesMinBatchSize();
int secondaryQueriesMinBatchSize();
/**
* Execute any secondary (+query) queries if there are any defined.
@@ -29,12 +29,12 @@ public interface LoadContext {
/**
* Return the node for a given path which is used by AutoTune profiling.
*/
ObjectGraphNode getObjectGraphNode(String path);
ObjectGraphNode objectGraphNode(String path);
/**
* Return the persistence context used by this query and future lazy loading.
*/
PersistenceContext getPersistenceContext();
PersistenceContext persistenceContext();
/**
* Register a Bean for lazy loading.
@@ -31,15 +31,15 @@ public interface LoadManyBuffer {
*/
boolean removeFromBuffer(BeanCollection<?> collection);
BeanPropertyAssocMany<?> getBeanProperty();
BeanPropertyAssocMany<?> beanProperty();
ObjectGraphNode getObjectGraphNode();
ObjectGraphNode objectGraphNode();
BeanDescriptor<?> getBeanDescriptor();
BeanDescriptor<?> descriptor();
PersistenceContext getPersistenceContext();
PersistenceContext persistenceContext();
String getFullPath();
String fullPath();
void configureQuery(SpiQuery<?> query);
@@ -50,11 +50,11 @@ public final class LoadManyRequest extends LoadRequest {
@Override
public Class<?> beanType() {
return loadContext.getBeanDescriptor().type();
return loadContext.descriptor().type();
}
public String description() {
return loadContext.getFullPath();
return loadContext.fullPath();
}
private List<Object> parentIdList(SpiEbeanServer server) {
@@ -82,7 +82,7 @@ public final class LoadManyRequest extends LoadRequest {
}
private BeanPropertyAssocMany<?> many() {
return loadContext.getBeanProperty();
return loadContext.beanProperty();
}
public SpiQuery<?> createQuery(SpiEbeanServer server) {
@@ -100,7 +100,7 @@ public final class LoadManyRequest extends LoadRequest {
}
query.setLazyLoadForParents(many);
many.addWhereParentIdIn(query, parentIdList(server), loadContext.isUseDocStore());
query.setPersistenceContext(loadContext.getPersistenceContext());
query.setPersistenceContext(loadContext.persistenceContext());
query.setLoadDescription(lazy ? "+lazy" : "+query", description());
if (lazy) {
query.setLazyLoadBatchSize(loadContext.batchSize());
@@ -120,7 +120,7 @@ public final class LoadManyRequest extends LoadRequest {
* After the query execution check for empty collections and load L2 cache if desired.
*/
public void postLoad() {
BeanDescriptor<?> desc = loadContext.getBeanDescriptor();
BeanDescriptor<?> desc = loadContext.descriptor();
BeanPropertyAssocMany<?> many = many();
// check for BeanCollection's that where never processed
// in the +query or +lazy load due to no rows (predicates)
@@ -14,7 +14,7 @@ public interface SpiExpressionRequest {
/**
* Return the DB specific handler for JSON and ARRAY expressions.
*/
DbExpressionHandler getDbPlatformHandler();
DbExpressionHandler platformHandler();
/**
* Parse the logical property name to the deployment name.
@@ -24,17 +24,30 @@ public interface SpiExpressionRequest {
/**
* Return the bean descriptor for the root type.
*/
BeanDescriptor<?> getBeanDescriptor();
BeanDescriptor<?> descriptor();
/**
* Return the associated QueryRequest.
*/
SpiOrmQueryRequest<?> getQueryRequest();
SpiOrmQueryRequest<?> queryRequest();
/**
* Append to the expression sql.
* Append to the expression sql without any parsing.
*/
SpiExpressionRequest append(String sql);
SpiExpressionRequest append(String expression);
/**
* Append to the expression sql with logical property parsing to db columns with logical path prefix.
* <p>
* This is a fast path case when expression is a bean property path and falls back to using parse()
* when that isn't the case.
*/
SpiExpressionRequest property(String expression);
/**
* Append to the expression sql with logical property parsing to db columns with logical path prefix.
*/
SpiExpressionRequest parse(String expression);
/**
* Add an encryption key to bind to this request.
@@ -49,12 +62,12 @@ public interface SpiExpressionRequest {
/**
* Return the accumulated expression sql for all expressions in this request.
*/
String getSql();
String sql();
/**
* Return the ordered list of bind values for all expressions in this request.
*/
List<Object> getBindValues();
List<Object> bindValues();
/**
* Increments the parameter index and returns that value.
@@ -127,7 +127,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
* iteration is fine.
*/
public int secondaryQueriesMinBatchSize() {
return loadContext.getSecondaryQueriesMinBatchSize();
return loadContext.secondaryQueriesMinBatchSize();
}
/**
@@ -416,8 +416,8 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
public String assocIsEmpty(SpiExpressionRequest request, String path) {
boolean softDelete = targetDescriptor.isSoftDelete();
boolean needsX2Table = softDelete || extraWhere() != null;
StringBuilder sb = new StringBuilder(50);
SpiQuery<?> query = request.getQueryRequest().query();
StringBuilder sb = new StringBuilder(50).append("from "); // use from to stop parsing on table name
SpiQuery<?> query = request.queryRequest().query();
if (hasJoinTable()) {
sb.append(query.isAsDraft() ? intersectionDraftTable : intersectionPublishTable);
} else {
@@ -46,25 +46,37 @@ public abstract class DeployParser {
protected abstract String convertWord();
public abstract String getDeployWord(String expression);
public abstract String deployWord(String expression);
/**
* Return the join includes.
*/
public abstract Set<String> getIncludes();
public abstract Set<String> includes();
public void setEncrypted(boolean encrypted) {
this.encrypted = encrypted;
}
public String parse(String source) {
if (source == null) {
/**
* Fast path parse() which first checks that the source is a bean property.
*/
public String property(String expression) {
String deployWord = deployWord(expression);
if (deployWord != null) {
return deployWord;
}
// fallback to use parse()
return parse(expression);
}
public String parse(String expression) {
if (expression == null) {
return null;
}
pos = -1;
this.source = source;
this.sourceLength = source.length();
this.sb = new StringBuilder(source.length() + 20);
this.source = expression;
this.sourceLength = expression.length();
this.sb = new StringBuilder(expression.length() + 20);
while (nextWord()) {
if (skipWordConvert()) {
sb.append(word);
@@ -37,12 +37,12 @@ public final class DeployPropertyParser extends DeployParser {
/**
* Return the first property found by the parser.
*/
public ElPropertyDeploy getFirstProp() {
public ElPropertyDeploy firstProp() {
return firstProp;
}
@Override
public Set<String> getIncludes() {
public Set<String> includes() {
return includes;
}
@@ -55,7 +55,7 @@ public final class DeployPropertyParser extends DeployParser {
}
@Override
public String getDeployWord(String expression) {
public String deployWord(String expression) {
ElPropertyDeploy elProp = beanDescriptor.elPropertyDeploy(expression);
if (elProp == null) {
return null;
@@ -70,7 +70,7 @@ public final class DeployPropertyParser extends DeployParser {
@Override
public String convertWord() {
String r = getDeployWord(word);
String r = deployWord(word);
return r == null ? word : r;
}
@@ -19,18 +19,18 @@ public class DeployPropertyParserMap extends DeployParser {
* Returns null for raw sql queries.
*/
@Override
public Set<String> getIncludes() {
public Set<String> includes() {
return Collections.emptySet();
}
@Override
public String convertWord() {
String r = getDeployWord(word);
String r = deployWord(word);
return r == null ? word : r;
}
@Override
public String getDeployWord(String expression) {
public String deployWord(String expression) {
return map.get(expression);
}
@@ -19,13 +19,13 @@ public final class DeployUpdateParser extends DeployParser {
* Return null as not used for updates.
*/
@Override
public Set<String> getIncludes() {
public Set<String> includes() {
return null;
}
@Override
public String convertWord() {
String dbWord = getDeployWord(word);
String dbWord = deployWord(word);
if (dbWord != null) {
return dbWord;
}
@@ -62,7 +62,7 @@ public final class DeployUpdateParser extends DeployParser {
start = dotPos + 1;
String remainder = currentWord.substring(start);
String dbWord = getDeployWord(remainder);
String dbWord = deployWord(remainder);
if (dbWord != null) {
// we have found a match for the remainder
localBuffer.append(dbWord);
@@ -72,7 +72,7 @@ public final class DeployUpdateParser extends DeployParser {
}
@Override
public String getDeployWord(String expression) {
public String deployWord(String expression) {
if (expression.equalsIgnoreCase(beanDescriptor.name())) {
return beanDescriptor.baseTable();
}
@@ -48,7 +48,7 @@ final class FormulaPropertyPath {
parsed = parsed.replace("${}", "${" + path + "}");
}
this.parsedAggregation = buildFormula(parsed);
this.firstProp = parser.getFirstProp();
this.firstProp = parser.firstProp();
}
private void parseSuffix(String suffix) {
@@ -82,9 +82,9 @@ public final class IntersectionRow {
idIn.addSqlNoAlias(er);
idIn.addBindValues(er);
sb.append(" and not ( ");
sb.append(er.getSql());
sb.append(er.sql());
sb.append(" ) ");
List<Object> bindValues = er.getBindValues();
List<Object> bindValues = er.bindValues();
for (Object bindValue : bindValues) {
bindParams.setParameter(++count, bindValue);
}
@@ -8,31 +8,14 @@ import io.ebean.config.DatabaseConfig;
import io.ebean.config.TableName;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
import io.ebean.event.BeanFindController;
import io.ebean.event.BeanPersistController;
import io.ebean.event.BeanPersistListener;
import io.ebean.event.BeanPostConstructListener;
import io.ebean.event.BeanPostLoad;
import io.ebean.event.BeanQueryAdapter;
import io.ebean.event.*;
import io.ebean.event.changelog.ChangeLogFilter;
import io.ebean.text.PathProperties;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.ConcurrencyMode;
import io.ebeaninternal.server.core.CacheOptions;
import io.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
import io.ebeaninternal.server.deploy.ChainedBeanPersistController;
import io.ebeaninternal.server.deploy.ChainedBeanPersistListener;
import io.ebeaninternal.server.deploy.ChainedBeanPostConstructListener;
import io.ebeaninternal.server.deploy.ChainedBeanPostLoad;
import io.ebeaninternal.server.deploy.ChainedBeanQueryAdapter;
import io.ebeaninternal.server.deploy.DeployPropertyParserMap;
import io.ebeaninternal.server.deploy.IdentityMode;
import io.ebeaninternal.server.deploy.IndexDefinition;
import io.ebeaninternal.server.deploy.InheritInfo;
import io.ebeaninternal.server.deploy.PartitionMeta;
import io.ebeaninternal.server.deploy.TableJoin;
import io.ebeaninternal.server.deploy.TablespaceMeta;
import io.ebeaninternal.server.deploy.*;
import io.ebeaninternal.server.deploy.parse.DeployBeanInfo;
import io.ebeaninternal.server.idgen.UuidV1IdGenerator;
import io.ebeaninternal.server.idgen.UuidV1RndIdGenerator;
@@ -41,13 +24,7 @@ import io.ebeaninternal.server.rawsql.SpiRawSql;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* Describes Beans including their deployment information.
@@ -1102,7 +1079,7 @@ public class DeployBeanDescriptor<T> {
}
@Override
public String getDeployWord(String expression) {
public String deployWord(String expression) {
return descriptor.getDeployWord(expression);
}
}
@@ -2,11 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebean.event.BeanQueryRequest;
import io.ebean.util.SplitName;
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.*;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.el.ElPropertyDeploy;
import io.ebeaninternal.server.el.ElPropertyValue;
@@ -102,6 +98,6 @@ abstract class AbstractExpression implements SpiExpression {
}
protected final ElPropertyValue getElProp(SpiExpressionRequest request) {
return request.getBeanDescriptor().elGetValue(propName);
return request.descriptor().elGetValue(propName);
}
}
@@ -1,10 +1,6 @@
package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiExpressionValidation;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.el.ElPropertyDeploy;
@@ -80,7 +76,7 @@ final class AllEqualsExpression extends NonPrepareExpression {
if (count > 0) {
request.append("and ");
}
request.append(name(propName));
request.property(name(propName));
if (value == null) {
request.append(" is null ");
} else {
@@ -68,7 +68,7 @@ final class ArrayContainsExpression extends AbstractExpression {
@Override
public void addSql(SpiExpressionRequest request) {
request.getDbPlatformHandler().arrayContains(request, propName, contains, values);
request.platformHandler().arrayContains(request, propName, contains, values);
}
@Override
@@ -45,7 +45,7 @@ final class ArrayIsEmptyExpression extends AbstractExpression {
@Override
public void addSql(SpiExpressionRequest request) {
request.getDbPlatformHandler().arrayIsEmpty(request, propName, empty);
request.platformHandler().arrayIsEmpty(request, propName, empty);
}
@Override
@@ -52,7 +52,7 @@ final class BetweenExpression extends AbstractExpression {
if (prop != null && prop.isDbEncrypted()) {
pname = prop.beanProperty().decryptProperty(propName);
}
request.append(pname).append(_BETWEEN);
request.property(pname).append(_BETWEEN);
}
@Override
@@ -1,11 +1,7 @@
package io.ebeaninternal.server.expression;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiExpressionValidation;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.el.ElPropertyDeploy;
@@ -85,7 +81,7 @@ final class BetweenPropertyExpression extends NonPrepareExpression {
@Override
public void addSql(SpiExpressionRequest request) {
request.append(" ?").append(BETWEEN).append(name(lowProperty)).append(" and ").append(name(highProperty));
request.append(" ?").append(BETWEEN).property(name(lowProperty)).append(" and ").property(name(highProperty));
}
@Override
@@ -48,7 +48,7 @@ final class BitwiseExpression extends AbstractExpression {
@Override
public void addSql(SpiExpressionRequest request) {
// Use DB specific expression handling
request.getDbPlatformHandler().bitwise(request, propName, operator, flags, compare, match);
request.platformHandler().bitwise(request, propName, operator, flags, compare, match);
}
@Override
@@ -52,9 +52,9 @@ final class CaseInsensitiveEqualExpression extends AbstractValueExpression {
pname = prop.beanProperty().decryptProperty(propName);
}
if (not) {
request.append("lower(").append(pname).append(") != ?");
request.append("lower(").property(pname).append(") != ?");
} else {
request.append("lower(").append(pname).append(") = ?");
request.append("lower(").property(pname).append(") = ?");
}
}
@@ -5,7 +5,6 @@ import io.ebean.bean.EntityBean;
import io.ebean.search.*;
import io.ebeaninternal.api.SpiExpressionFactory;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.expression.SubQueryExpression.SQOp;
import io.ebeaninternal.server.grammer.EqlParser;
import java.util.Arrays;
@@ -149,7 +148,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
@Override
public Expression eq(String propertyName, Query<?> subQuery) {
return new SubQueryExpression(SQOp.EQ, propertyName, (SpiQuery<?>) subQuery);
return new SubQueryExpression(SubQueryOp.EQ, propertyName, (SpiQuery<?>) subQuery);
}
/**
@@ -170,7 +169,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
@Override
public Expression ne(String propertyName, Query<?> subQuery) {
return new SubQueryExpression(SQOp.NE, propertyName, (SpiQuery<?>) subQuery);
return new SubQueryExpression(SubQueryOp.NE, propertyName, (SpiQuery<?>) subQuery);
}
/**
@@ -260,7 +259,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
@Override
public Expression gt(String propertyName, Query<?> subQuery) {
return new SubQueryExpression(SQOp.GT, propertyName, (SpiQuery<?>) subQuery);
return new SubQueryExpression(SubQueryOp.GT, propertyName, (SpiQuery<?>) subQuery);
}
/**
@@ -286,7 +285,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
@Override
public Expression ge(String propertyName, Query<?> subQuery) {
return new SubQueryExpression(SQOp.GE, propertyName, (SpiQuery<?>) subQuery);
return new SubQueryExpression(SubQueryOp.GE, propertyName, (SpiQuery<?>) subQuery);
}
/**
@@ -313,7 +312,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
@Override
public Expression lt(String propertyName, Query<?> subQuery) {
return new SubQueryExpression(SQOp.LT, propertyName, (SpiQuery<?>) subQuery);
return new SubQueryExpression(SubQueryOp.LT, propertyName, (SpiQuery<?>) subQuery);
}
/**
@@ -326,7 +325,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
@Override
public Expression le(String propertyName, Query<?> subQuery) {
return new SubQueryExpression(SQOp.LE, propertyName, (SpiQuery<?>) subQuery);
return new SubQueryExpression(SubQueryOp.LE, propertyName, (SpiQuery<?>) subQuery);
}
/**
@@ -480,12 +479,68 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
return new InExpression(propertyName, values, false);
}
/**
* In - using a subQuery.
*/
@Override
public Expression exists(String subQuery, Object... bindValues) {
return new ExistsSqlQueryExpression(false, subQuery, bindValues);
}
/**
* In - using a subQuery.
*/
@Override
public Expression notExists(String subQuery, Object... bindValues) {
return new ExistsSqlQueryExpression(true, subQuery, bindValues);
}
/**
* In - using a subQuery.
*/
@Override
public Expression in(String propertyName, Query<?> subQuery) {
return new SubQueryExpression(SQOp.IN, propertyName, (SpiQuery<?>) subQuery);
return new SubQueryExpression(SubQueryOp.IN, propertyName, (SpiQuery<?>) subQuery);
}
@Override
public Expression inSubQuery(String propertyName, String subQuery, Object... bindValues) {
return new SubQueryRawExpression(SubQueryOp.IN, propertyName, subQuery, bindValues);
}
@Override
public Expression notInSubQuery(String propertyName, String subQuery, Object... bindValues) {
return new SubQueryRawExpression(SubQueryOp.NOTIN, propertyName, subQuery, bindValues);
}
@Override
public Expression eqSubQuery(String propertyName, String subQuery, Object... bindValues) {
return new SubQueryRawExpression(SubQueryOp.EQ, propertyName, subQuery, bindValues);
}
@Override
public Expression neSubQuery(String propertyName, String subQuery, Object... bindValues) {
return new SubQueryRawExpression(SubQueryOp.NE, propertyName, subQuery, bindValues);
}
@Override
public Expression geSubQuery(String propertyName, String subQuery, Object... bindValues) {
return new SubQueryRawExpression(SubQueryOp.GE, propertyName, subQuery, bindValues);
}
@Override
public Expression gtSubQuery(String propertyName, String subQuery, Object... bindValues) {
return new SubQueryRawExpression(SubQueryOp.GT, propertyName, subQuery, bindValues);
}
@Override
public Expression leSubQuery(String propertyName, String subQuery, Object... bindValues) {
return new SubQueryRawExpression(SubQueryOp.LE, propertyName, subQuery, bindValues);
}
@Override
public Expression ltSubQuery(String propertyName, String subQuery, Object... bindValues) {
return new SubQueryRawExpression(SubQueryOp.LT, propertyName, subQuery, bindValues);
}
/**
@@ -527,7 +582,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
*/
@Override
public Expression notIn(String propertyName, Query<?> subQuery) {
return new SubQueryExpression(SQOp.NOTIN, propertyName, (SpiQuery<?>) subQuery);
return new SubQueryExpression(SubQueryOp.NOTIN, propertyName, (SpiQuery<?>) subQuery);
}
/**
@@ -2,51 +2,16 @@ package io.ebeaninternal.server.expression;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.CacheMode;
import io.ebean.CountDistinctOrder;
import io.ebean.DtoQuery;
import io.ebean.Expression;
import io.ebean.ExpressionFactory;
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.*;
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.BindValuesKey;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.NaturalKeyQueryData;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionList;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiExpressionValidation;
import io.ebeaninternal.api.SpiJunction;
import io.ebean.search.*;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import java.io.IOException;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -953,6 +918,57 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return add(expr.inPairs(pairs));
}
@Override
public ExpressionList<T> exists(String sqlSubQuery, Object... bindValues) {
return add(expr.exists(sqlSubQuery, bindValues));
}
@Override
public ExpressionList<T> notExists(String sqlSubQuery, Object... bindValues) {
return add(expr.notExists(sqlSubQuery, bindValues));
}
@Override
public ExpressionList<T> inSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return add(expr.inSubQuery(propertyName, sqlSubQuery, bindValues));
}
@Override
public ExpressionList<T> notInSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return add(expr.notInSubQuery(propertyName, sqlSubQuery, bindValues));
}
@Override
public ExpressionList<T> eqSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return add(expr.eqSubQuery(propertyName, sqlSubQuery, bindValues));
}
@Override
public ExpressionList<T> neSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return add(expr.neSubQuery(propertyName, sqlSubQuery, bindValues));
}
@Override
public ExpressionList<T> gtSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return add(expr.gtSubQuery(propertyName, sqlSubQuery, bindValues));
}
@Override
public ExpressionList<T> geSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return add(expr.geSubQuery(propertyName, sqlSubQuery, bindValues));
}
@Override
public ExpressionList<T> ltSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return add(expr.ltSubQuery(propertyName, sqlSubQuery, bindValues));
}
@Override
public ExpressionList<T> leSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return add(expr.leSubQuery(propertyName, sqlSubQuery, bindValues));
}
@Override
public ExpressionList<T> in(String propertyName, Query<?> subQuery) {
return add(expr.in(propertyName, subQuery));
@@ -2,12 +2,12 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.SpiExpressionList;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.bind.DataBind;
import io.ebeaninternal.server.core.SpiOrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.DeployParser;
import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
import io.ebeaninternal.server.persist.Binder;
import io.ebeaninternal.server.bind.DataBind;
import java.sql.SQLException;
import java.util.ArrayList;
@@ -67,14 +67,13 @@ public final class DefaultExpressionRequest implements SpiExpressionRequest {
}
@Override
public DbExpressionHandler getDbPlatformHandler() {
public DbExpressionHandler platformHandler() {
return binder.getDbExpressionHandler();
}
@Override
public String parseDeploy(String logicalProp) {
String s = deployParser.getDeployWord(logicalProp);
String s = deployParser.deployWord(logicalProp);
return s == null ? logicalProp : s;
}
@@ -102,12 +101,12 @@ public final class DefaultExpressionRequest implements SpiExpressionRequest {
}
@Override
public BeanDescriptor<?> getBeanDescriptor() {
public BeanDescriptor<?> descriptor() {
return beanDescriptor;
}
@Override
public SpiOrmQueryRequest<?> getQueryRequest() {
public SpiOrmQueryRequest<?> queryRequest() {
return queryRequest;
}
@@ -115,8 +114,28 @@ public final class DefaultExpressionRequest implements SpiExpressionRequest {
* Append text the underlying sql expression.
*/
@Override
public SpiExpressionRequest append(String sqlExpression) {
sql.append(sqlExpression);
public SpiExpressionRequest append(String expression) {
sql.append(expression);
return this;
}
@Override
public SpiExpressionRequest property(String expression) {
if (deployParser == null) {
sql.append(expression);
} else {
sql.append(deployParser.property(expression));
}
return this;
}
@Override
public SpiExpressionRequest parse(String expression) {
if (deployParser == null) {
sql.append(expression);
} else {
sql.append(deployParser.parse(expression));
}
return this;
}
@@ -143,17 +162,17 @@ public final class DefaultExpressionRequest implements SpiExpressionRequest {
}
}
public String getBindLog() {
public String bindLog() {
return bindLog == null ? "" : bindLog.toString();
}
@Override
public String getSql() {
public String sql() {
return sql.toString();
}
@Override
public List<Object> getBindValues() {
public List<Object> bindValues() {
return bindValues;
}
@@ -93,11 +93,9 @@ final class ExistsQueryExpression implements SpiExpression, UnsupportedDocStoreE
@Override
public void addSql(SpiExpressionRequest request) {
if (not) {
request.append(" not");
request.append("not ");
}
request.append(" exists (");
request.append(sql);
request.append(")");
request.append("exists (").parse(sql).append(")");
}
@Override
@@ -0,0 +1,106 @@
package io.ebeaninternal.server.expression;
import io.ebean.event.BeanQueryRequest;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import java.util.Arrays;
final class ExistsSqlQueryExpression implements SpiExpression, UnsupportedDocStoreExpression {
private final boolean not;
private final String subQuery;
private final Object[] bindParams;
ExistsSqlQueryExpression(boolean not, String subQuery, Object[] bindParams) {
this.not = not;
this.subQuery = subQuery;
this.bindParams = bindParams;
}
@Override
public void prefixProperty(String path) {
// do nothing
}
@Override
public boolean naturalKey(NaturalKeyQueryData<?> data) {
// can't use naturalKey cache
return false;
}
@Override
public void simplify() {
// do nothing
}
@Override
public void writeDocQuery(DocQueryContext context) {
throw new IllegalStateException("Not supported");
}
@Override
public Object getIdEqualTo(String idName) {
// always return null for this expression
return null;
}
@Override
public void prepareExpression(BeanQueryRequest<?> request) {
// do nothing
}
@Override
public SpiExpression copyForPlanKey() {
return this;
}
@Override
public void queryPlanHash(StringBuilder builder) {
builder.append("ExistsSqlQuery[").append(" not:").append(not);
builder.append(" sql:").append(subQuery).append(" ?:").append(bindParams.length).append("]");
}
@Override
public void queryBindKey(BindValuesKey key) {
for (Object value : bindParams) {
key.add(value);
}
}
@Override
public void addSql(SpiExpressionRequest request) {
if (not) {
request.append("not ");
}
request.append("exists (").parse(subQuery).append(")");
}
@Override
public void addBindValues(SpiExpressionRequest request) {
for (Object bindParam : bindParams) {
request.addBindValue(bindParam);
}
}
@Override
public boolean isSameByBind(SpiExpression other) {
final ExistsSqlQueryExpression that = (ExistsSqlQueryExpression) other;
return Arrays.equals(bindParams, that.bindParams);
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
return null;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins whereManyJoins) {
// Nothing to do for exists expression
}
@Override
public void validate(SpiExpressionValidation validation) {
// Nothing to do for exists expression
}
}
@@ -1,10 +1,6 @@
package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiExpressionValidation;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import java.io.IOException;
@@ -50,23 +46,16 @@ final class IdExpression extends NonPrepareExpression implements SpiExpression {
@Override
public void addBindValues(SpiExpressionRequest request) {
// 'flatten' EmbeddedId and multiple ID cases
// into an array of the underlying scalar field values
DefaultExpressionRequest r = (DefaultExpressionRequest) request;
Object[] bindIdValues = r.getBeanDescriptor().bindIdValues(value);
for (Object bindIdValue : bindIdValues) {
for (Object bindIdValue : request.descriptor().bindIdValues(value)) {
request.addBindValue(bindIdValue);
}
}
@Override
public void addSql(SpiExpressionRequest request) {
DefaultExpressionRequest r = (DefaultExpressionRequest) request;
String idSql = r.getBeanDescriptor().idBinderIdSql(null);
request.append(idSql);
request.parse(request.descriptor().idBinderIdSql(null));
}
/**
@@ -1,21 +1,13 @@
package io.ebeaninternal.server.expression;
import io.ebean.event.BeanQueryRequest;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiExpressionValidation;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.core.BindPadding;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.id.IdBinder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.*;
/**
* In a collection of ID values.
@@ -74,42 +66,34 @@ public final class IdInExpression extends NonPrepareExpression implements IdInCo
return;
}
// Bind the ID values including EmbeddedId and multiple ID
DefaultExpressionRequest r = (DefaultExpressionRequest) request;
BeanDescriptor<?> descriptor = r.getBeanDescriptor();
IdBinder idBinder = descriptor.idBinder();
idBinder.addIdInBindValues(request, idCollection);
request.descriptor().idBinder().addIdInBindValues(request, idCollection);
}
/**
* For use with deleting non-attached detail beans during stateless update.
*/
public void addSqlNoAlias(SpiExpressionRequest request) {
DefaultExpressionRequest r = (DefaultExpressionRequest) request;
BeanDescriptor<?> descriptor = r.getBeanDescriptor();
IdBinder idBinder = descriptor.idBinder();
if (idCollection.isEmpty()) {
request.append(SQL_FALSE); // append false for this stage
} else {
request.append(descriptor.idBinder().getBindIdInSql(null));
String inClause = idBinder.getIdInValueExpr(false, idCollection.size());
request.append(inClause);
final BeanDescriptor<?> descriptor = request.descriptor();
request.property(descriptor.idBinder().getBindIdInSql(null));
request.append(descriptor.idBinder().getIdInValueExpr(false, idCollection.size()));
}
}
@Override
public void addSql(SpiExpressionRequest request) {
BeanDescriptor<?> descriptor = request.getBeanDescriptor();
IdBinder idBinder = descriptor.idBinder();
if (idCollection.isEmpty()) {
request.append(SQL_FALSE); // append false for this stage
} else {
final BeanDescriptor<?> descriptor = request.descriptor();
final IdBinder idBinder = descriptor.idBinder();
if (idBinder.isComplexId()) {
request.append(descriptor.idBinderInLHSSql());
request.parse(descriptor.idBinderInLHSSql());
request.append(idBinder.getIdInValueExpr(false, idCollection.size()));
} else {
request.append(idBinder.getBeanProperty().name());
request.property(idBinder.getBeanProperty().name());
request.appendInExpression(false, idCollection);
}
}
@@ -156,21 +156,20 @@ public final class InExpression extends AbstractExpression implements IdInCommon
request.append(not ? SQL_TRUE : SQL_FALSE);
return;
}
ElPropertyValue prop = getElProp(request);
if (prop != null) {
if (prop.isAssocId()) {
request.append(prop.assocIdInExpr(propName));
request.parse(prop.assocIdInExpr(propName));
request.append(prop.assocIdInValueExpr(not, bindValues.size()));
return;
}
if (prop.isDbEncrypted()) {
request.append(prop.beanProperty().decryptProperty(propName));
request.parse(prop.beanProperty().decryptProperty(propName));
request.appendInExpression(not, bindValues);
return;
}
}
request.append(propName);
request.property(propName);
request.appendInExpression(not, bindValues);
}
@@ -85,14 +85,11 @@ final class InPairsExpression extends AbstractExpression {
@Override
public void addSql(SpiExpressionRequest request) {
if (entries.isEmpty()) {
String expr = not ? SQL_TRUE : SQL_FALSE;
request.append(expr);
request.append(not ? SQL_TRUE : SQL_FALSE);
return;
}
request.append(request.getDbPlatformHandler().concat(property0, separator, property1, suffix));
request.parse(request.platformHandler().concat(property0, separator, property1, suffix));
request.appendInExpression(not, concatBindValues);
}
@@ -55,7 +55,7 @@ final class InRangeExpression extends AbstractExpression {
if (prop != null && prop.isDbEncrypted()) {
pname = prop.beanProperty().decryptProperty(propName);
}
request.append("(").append(pname).append(" >= ? and ").append(pname).append(" < ?)");
request.append("(").property(pname).append(" >= ? and ").property(pname).append(" < ?)");
}
@Override
@@ -1,12 +1,12 @@
package io.ebeaninternal.server.expression;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.el.ElPropertyValue;
import io.ebean.util.SplitName;
import java.io.IOException;
@@ -78,13 +78,12 @@ final class IsEmptyExpression extends AbstractExpression {
* Append an exists subQuery for the property.
*/
static void isEmptySql(SpiExpressionRequest request, ElPropertyValue prop, boolean empty, String propertyPath) {
if (empty) {
request.append("not ");
}
request
.append("exists (select 1 from ")
.append(prop.assocIsEmpty(request, propertyPath))
.append("exists (select 1 ")
.parse(prop.assocIsEmpty(request, propertyPath))
.append(")");
}
@@ -97,14 +97,12 @@ final class JsonPathExpression extends AbstractExpression {
@Override
public void addSql(SpiExpressionRequest request) {
// Use DB specific expression handling (Postgres and Oracle supported)
request.getDbPlatformHandler().json(request, propName, path, operator, value);
request.platformHandler().json(request, propName, path, operator, value);
}
@Override
public void addBindValues(SpiExpressionRequest request) {
if (value != null) {
// value is null for EXISTS/NOT EXISTS
request.addBindValue(value);
@@ -2,48 +2,16 @@ package io.ebeaninternal.server.expression;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
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.*;
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.BindValuesKey;
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.ebean.search.*;
import io.ebeaninternal.api.*;
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.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -762,6 +730,56 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
return exprList.in(propertyName, subQuery);
}
@Override
public ExpressionList<T> exists(String sqlSubQuery, Object... bindValues) {
return exprList.exists(sqlSubQuery, bindValues);
}
@Override
public ExpressionList<T> notExists(String sqlSubQuery, Object... bindValues) {
return exprList.notExists(sqlSubQuery, bindValues);
}
@Override
public ExpressionList<T> inSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return exprList.inSubQuery(propertyName, sqlSubQuery, bindValues);
}
@Override
public ExpressionList<T> notInSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return exprList.notInSubQuery(propertyName, sqlSubQuery, bindValues);
}
@Override
public ExpressionList<T> eqSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return exprList.eqSubQuery(propertyName, sqlSubQuery, bindValues);
}
@Override
public ExpressionList<T> neSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return exprList.neSubQuery(propertyName, sqlSubQuery, bindValues);
}
@Override
public ExpressionList<T> gtSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return exprList.gtSubQuery(propertyName, sqlSubQuery, bindValues);
}
@Override
public ExpressionList<T> geSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return exprList.geSubQuery(propertyName, sqlSubQuery, bindValues);
}
@Override
public ExpressionList<T> ltSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return exprList.ltSubQuery(propertyName, sqlSubQuery, bindValues);
}
@Override
public ExpressionList<T> leSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) {
return exprList.leSubQuery(propertyName, sqlSubQuery, bindValues);
}
@Override
public ExpressionList<T> notIn(String propertyName, Collection<?> values) {
return exprList.notIn(propertyName, values);
@@ -44,9 +44,9 @@ final class LikeExpression extends AbstractValueExpression {
pname = prop.beanProperty().decryptProperty(propName);
}
if (caseInsensitive) {
request.append("lower(").append(pname).append(")");
request.append("lower(").property(pname).append(")");
} else {
request.append(pname);
request.property(pname);
}
if (type == LikeType.EQUAL_TO) {
request.append(" = ?");
@@ -36,14 +36,12 @@ final class NativeILikeExpression extends AbstractExpression {
@Override
public void addSql(SpiExpressionRequest request) {
String pname = propName;
ElPropertyValue prop = getElProp(request);
if (prop != null && prop.isDbEncrypted()) {
pname = prop.beanProperty().decryptProperty(propName);
}
request.append(pname).append(" ilike ?");
request.property(pname).append(" ilike ?");
}
/**
@@ -57,18 +57,16 @@ final class NullExpression extends AbstractExpression {
@Override
public void addSql(SpiExpressionRequest request) {
if (assocMany) {
// translate to exists subquery
// translate to exists sub-query
IsEmptyExpression.isEmptySql(request, elProperty, !notNull, propertyPath);
return;
}
String nullExpr = notNull ? " is not null" : " is null";
if (elProperty != null && elProperty.isAssocId()) {
request.append(elProperty.assocIdExpression(propName, nullExpr));
request.parse(elProperty.assocIdExpression(propName, nullExpr));
} else {
request.append(propName).append(nullExpr);
request.property(propName).append(nullExpr);
}
}
@@ -1,10 +1,6 @@
package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiExpressionValidation;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.persist.MultiValueWrapper;
@@ -57,7 +53,7 @@ final class RawExpression extends NonPrepareExpression {
@Override
public void addSql(SpiExpressionRequest request) {
request.append(sql);
request.parse(sql);
}
/**
@@ -2,11 +2,11 @@ package io.ebeaninternal.server.expression;
import io.ebean.bean.EntityBean;
import io.ebean.plugin.ExpressionPath;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.NaturalKeyQueryData;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.el.ElPropertyValue;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.NaturalKeyQueryData;
import java.io.IOException;
import java.util.Arrays;
@@ -97,20 +97,19 @@ public final class SimpleExpression extends AbstractValueExpression {
@Override
public void addSql(SpiExpressionRequest request) {
ElPropertyValue prop = getElProp(request);
if (prop != null) {
if (prop.isAssocId()) {
request.append(prop.assocIdExpression(propName, type.bind()));
request.parse(prop.assocIdExpression(propName, type.bind()));
return;
}
if (prop.isDbEncrypted()) {
String dsql = prop.beanProperty().decryptProperty(propName);
request.append(dsql).append(type.bind());
request.parse(dsql).append(type.bind());
return;
}
}
request.append(propName).append(type.bind());
request.property(propName).append(type.bind());
}
/**
@@ -12,33 +12,18 @@ import java.util.List;
*/
final class SubQueryExpression extends AbstractExpression implements UnsupportedDocStoreExpression {
enum SQOp {
EQ(" = "),
NE(" <> "),
GT(" > "),
GE(" >= "),
LT(" < "),
LE(" <= "),
IN(" in "),
NOTIN(" not in ");
final String expression;
SQOp(String expression) {
this.expression = expression;
}
}
private final SQOp op;
private final SubQueryOp op;
private final SpiQuery<?> subQuery;
private List<Object> bindParams;
private String sql;
SubQueryExpression(SQOp op, String propertyName, SpiQuery<?> subQuery) {
SubQueryExpression(SubQueryOp op, String propertyName, SpiQuery<?> subQuery) {
super(propertyName);
this.op = op;
this.subQuery = subQuery;
}
SubQueryExpression(SQOp op, String propertyName, String sql, List<Object> bindParams) {
SubQueryExpression(SubQueryOp op, String propertyName, String sql, List<Object> bindParams) {
super(propertyName);
this.op = op;
this.subQuery = null;
@@ -90,7 +75,7 @@ final class SubQueryExpression extends AbstractExpression implements Unsupported
@Override
public void addSql(SpiExpressionRequest request) {
request.append(propName).append(op.expression).append("(").append(sql).append(")");
request.property(propName).append(op.expression).append("(").parse(sql).append(")");
}
@Override
@@ -0,0 +1,17 @@
package io.ebeaninternal.server.expression;
enum SubQueryOp {
EQ(" = "),
NE(" <> "),
GT(" > "),
GE(" >= "),
LT(" < "),
LE(" <= "),
IN(" in "),
NOTIN(" not in ");
final String expression;
SubQueryOp(String expression) {
this.expression = expression;
}
}
@@ -0,0 +1,61 @@
package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import java.util.Arrays;
/**
* Raw SQL based Sub-Query expression.
*/
final class SubQueryRawExpression extends AbstractExpression implements UnsupportedDocStoreExpression {
private final SubQueryOp op;
private final String subQuery;
private final Object[] bindParams;
SubQueryRawExpression(SubQueryOp op, String propertyName, String subQuery, Object[] bindParams) {
super(propertyName);
this.op = op;
this.subQuery = subQuery;
this.bindParams = bindParams;
}
@Override
public void writeDocQuery(DocQueryContext context) {
throw new IllegalStateException("Not supported");
}
@Override
public void queryPlanHash(StringBuilder builder) {
builder.append("SubQueryRaw[").append(propName).append(op.expression)
.append(" subQuery:").append(subQuery)
.append(" ?:").append(bindParams.length).append("]");
}
@Override
public void queryBindKey(BindValuesKey key) {
for (Object value : bindParams) {
key.add(value);
}
}
@Override
public void addSql(SpiExpressionRequest request) {
request.property(propName).append(op.expression).append("(").append(subQuery).append(")");
}
@Override
public void addBindValues(SpiExpressionRequest request) {
for (Object bindParam : bindParams) {
request.addBindValue(bindParam);
}
}
@Override
public boolean isSameByBind(SpiExpression other) {
final SubQueryRawExpression that = (SubQueryRawExpression) other;
return Arrays.equals(bindParams, that.bindParams);
}
}
@@ -10,8 +10,8 @@ abstract class BaseDbExpression implements DbExpressionHandler {
@Override
public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
String bitOp = bitOp(operator);
request.append("(").append(propName).append(" ").append(bitOp).append(" ? ").append(compare).append(" ?)");
final String bitOp = bitOp(operator);
request.append("(").property(propName).append(" ").append(bitOp).append(" ? ").append(compare).append(" ?)");
}
private String bitOp(BitwiseOp operator) {
@@ -29,8 +29,8 @@ abstract class BaseDbExpression implements DbExpressionHandler {
* Common alternative where the bitwise operation is a function (specifically bitand is used - H2 and Oracle).
*/
protected void bitwiseFunction(SpiExpressionRequest request, String propName, BitwiseOp operator, String compare) {
String funcName = functionName(operator);
request.append(funcName).append("(").append(propName).append(", ?) ").append(compare).append(" ?");
final String funcName = functionName(operator);
request.append(funcName).append("(").property(propName).append(", ?) ").append(compare).append(" ?");
}
protected String functionName(BitwiseOp operator) {
@@ -10,7 +10,7 @@ final class H2DbExpression extends BasicDbExpression {
@Override
public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
String funcName = functionName(operator);
request.append(funcName).append("(").append(propName).append(", cast(? as long)) ").append(compare).append(" cast(? as long)");
final String funcName = functionName(operator);
request.append(funcName).append("(").property(propName).append(", cast(? as long)) ").append(compare).append(" cast(? as long)");
}
}
@@ -16,13 +16,12 @@ final class HanaDbExpression extends BaseDbExpression {
@Override
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
request.append("json_value(").append(propName).append(", '$.").append(path).append("')");
request.append(operator.bind());
request.append("json_value(").property(propName).append(", '$.").append(path).append("')").append(operator.bind());
}
@Override
public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) {
request.append("cardinality(").append(propName).append(")");
request.append("cardinality(").property(propName).append(")");
if (empty) {
request.append(" = 0");
} else {
@@ -51,8 +50,7 @@ final class HanaDbExpression extends BaseDbExpression {
if (!contains) {
request.append(" not ");
}
request.append(" member of ").append(propName).append(")");
request.append(" member of ").property(propName).append(")");
}
}
@@ -10,7 +10,6 @@ final class MariaDbExpression extends BasicDbExpression {
@Override
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
request.append("(").append(propName).append(" ->> '$.").append(path).append("')");
request.append(operator.bind());
request.append("(").property(propName).append(" ->> '$.").append(path).append("')").append(operator.bind());
}
}
@@ -10,8 +10,7 @@ final class MySqlDbExpression extends BasicDbExpression {
@Override
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
request.append("(").append(propName).append(" ->> '$.").append(path).append("')");
request.append(operator.bind());
request.append("(").property(propName).append(" ->> '$.").append(path).append("')").append(operator.bind());
}
}
@@ -17,12 +17,11 @@ final class OracleDbExpression extends BaseDbExpression {
@Override
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
if (operator == Op.EXISTS) {
request.append("json_exists(").append(propName).append(", '$.").append(path).append("')");
request.append("json_exists(").property(propName).append(", '$.").append(path).append("')");
} else if (operator == Op.NOT_EXISTS) {
request.append("not json_exists(").append(propName).append(", '$.").append(path).append("')");
request.append("not json_exists(").property(propName).append(", '$.").append(path).append("')");
} else {
request.append("json_value(").append(propName).append(", '$.").append(path).append("')");
request.append(operator.bind());
request.append("json_value(").property(propName).append(", '$.").append(path).append("')").append(operator.bind());
}
}
@@ -15,27 +15,22 @@ final class PostgresDbExpression extends BaseDbExpression {
@Override
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
StringBuilder sb = new StringBuilder(50);
String[] paths = path.split("\\.");
if (paths.length == 1) {
// (t0.content ->> 'title') = 'Some value'
sb.append("(").append(propName).append(" ->> '").append(path).append("')");
request.append("(").property(propName).append(" ->> '").append(path).append("')");
} else {
// (t0.content #>> '{path,inner}') = 'Some value'
sb.append("(").append(propName).append(" #>> '{");
request.append("(").property(propName).append(" #>> '{");
for (int i = 0; i < paths.length; i++) {
if (i > 0) {
sb.append(",");
request.append(",");
}
sb.append(paths[i]);
request.append(paths[i]);
}
sb.append("}')");
request.append("}')");
}
request.append(sb.toString());
request.append(PostgresCast.cast(value));
request.append(operator.bind());
request.append(PostgresCast.cast(value)).append(operator.bind());
}
@Override
@@ -43,12 +38,11 @@ final class PostgresDbExpression extends BaseDbExpression {
if (!contains) {
request.append("not (");
}
request.append(propName).append(" @> array[?");
request.property(propName).append(" @> array[?");
for (int i = 1; i < values.length; i++) {
request.append(",?");
}
request.append("]");
request.append(PostgresCast.cast(values[0], true));
request.append("]").append(PostgresCast.cast(values[0], true));
if (!contains) {
request.append(")");
}
@@ -56,7 +50,7 @@ final class PostgresDbExpression extends BaseDbExpression {
@Override
public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) {
request.append("coalesce(cardinality(").append(propName).append("),0)");
request.append("coalesce(cardinality(").property(propName).append("),0)");
if (empty) {
request.append(" = 0");
} else {
@@ -11,8 +11,7 @@ final class SqlServerDbExpression extends BaseDbExpression {
@Override
public void json(final SpiExpressionRequest request, final String propName,
final String path, final Op operator, final Object value) {
request.append("json_value(").append(propName).append(", '$.").append(path).append("')");
request.append(operator.bind());
request.append("json_value(").property(propName).append(", '$.").append(path).append("')").append(operator.bind());
}
@Override
@@ -35,12 +35,12 @@ abstract class DLoadBaseContext {
DLoadBaseContext(DLoadContext parent, BeanDescriptor<?> desc, String path, OrmQueryProperties queryProps) {
this.parent = parent;
this.serverName = parent.getEbeanServer().name();
this.serverName = parent.server().name();
this.desc = desc;
this.queryProps = queryProps;
this.fullPath = parent.getFullPath(path);
this.fullPath = parent.fullPath(path);
this.hitCache = parent.isBeanCacheGet() && desc.isBeanCaching();
this.objectGraphNode = parent.getObjectGraphNode(path);
this.objectGraphNode = parent.objectGraphNode(path);
this.queryFetch = queryProps != null && queryProps.isQueryFetch();
this.batchSize = parent.batchSize(queryProps);
}
@@ -50,14 +50,14 @@ abstract class DLoadBaseContext {
* set onto the secondary query.
*/
void setLabel(SpiQuery<?> query) {
String label = parent.getPlanLabel();
String label = parent.planLabel();
if (label != null) {
query.setProfilePath(label, fullPath, parent.getProfileLocation());
query.setProfilePath(label, fullPath, parent.profileLocation());
}
}
PersistenceContext getPersistenceContext() {
return parent.getPersistenceContext();
PersistenceContext persistenceContext() {
return parent.persistenceContext();
}
}
@@ -71,7 +71,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
if (currentBuffer.isFull()) {
currentBuffer = createBuffer(batchSize);
}
ebi.setBeanLoader(currentBuffer, getPersistenceContext());
ebi.setBeanLoader(currentBuffer, persistenceContext());
currentBuffer.add(ebi);
}
@@ -93,7 +93,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
if (bufferList != null) {
for (LoadBuffer loadBuffer : bufferList) {
if (!loadBuffer.batch.isEmpty()) {
parent.getEbeanServer().loadBean(new LoadBeanRequest(loadBuffer, parentRequest));
parent.server().loadBean(new LoadBeanRequest(loadBuffer, parentRequest));
}
if (forEach) {
clear();
@@ -165,7 +165,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
}
@Override
public String getName() {
public String name() {
return context.serverName;
}
@@ -2,24 +2,11 @@ package io.ebeaninternal.server.loadcontext;
import io.ebean.CacheMode;
import io.ebean.ProfileLocation;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.CallOrigin;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.ObjectGraphNode;
import io.ebean.bean.ObjectGraphOrigin;
import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.api.LoadContext;
import io.ebeaninternal.api.LoadSecondaryQuery;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuerySecondary;
import io.ebean.bean.*;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.autotune.ProfilingListener;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.deploy.*;
import io.ebeaninternal.server.el.ElPropertyValue;
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
@@ -127,14 +114,14 @@ public final class DLoadContext implements LoadContext {
/**
* Return the query plan label of the origin query.
*/
String getPlanLabel() {
String planLabel() {
return planLabel;
}
/**
* Return the profile location of the origin query.
*/
public ProfileLocation getProfileLocation() {
public ProfileLocation profileLocation() {
return profileLocation;
}
@@ -179,7 +166,7 @@ public final class DLoadContext implements LoadContext {
* Return the minimum batch size when using QueryIterator with query joins.
*/
@Override
public int getSecondaryQueriesMinBatchSize() {
public int secondaryQueriesMinBatchSize() {
if (secQuery == null) {
return -1;
}
@@ -201,7 +188,7 @@ public final class DLoadContext implements LoadContext {
public void executeSecondaryQueries(OrmQueryRequest<?> parentRequest, boolean forEach) {
if (secQuery != null) {
for (OrmQueryProperties aSecQuery : secQuery) {
LoadSecondaryQuery load = getLoadSecondaryQuery(aSecQuery.getPath());
LoadSecondaryQuery load = loadSecondaryQuery(aSecQuery.getPath());
load.loadSecondaryQuery(parentRequest, forEach);
}
}
@@ -210,13 +197,13 @@ public final class DLoadContext implements LoadContext {
/**
* Return the LoadBeanContext or LoadManyContext for the given path.
*/
private LoadSecondaryQuery getLoadSecondaryQuery(String path) {
private LoadSecondaryQuery loadSecondaryQuery(String path) {
LoadSecondaryQuery beanLoad = beanMap.get(path);
return beanLoad == null ? manyMap.get(path) : beanLoad;
}
@Override
public ObjectGraphNode getObjectGraphNode(String path) {
public ObjectGraphNode objectGraphNode(String path) {
return nodePathMap.computeIfAbsent(path, this::createObjectGraphNode);
}
@@ -231,7 +218,7 @@ public final class DLoadContext implements LoadContext {
return new ObjectGraphNode(origin, path);
}
String getFullPath(String path) {
String fullPath(String path) {
if (relativePath == null) {
return path;
} else {
@@ -239,7 +226,7 @@ public final class DLoadContext implements LoadContext {
}
}
SpiEbeanServer getEbeanServer() {
SpiEbeanServer server() {
return ebeanServer;
}
@@ -252,23 +239,23 @@ public final class DLoadContext implements LoadContext {
}
@Override
public PersistenceContext getPersistenceContext() {
public PersistenceContext persistenceContext() {
return persistenceContext;
}
@Override
public void register(String path, EntityBeanIntercept ebi) {
getBeanContext(path).register(ebi);
beanContext(path).register(ebi);
}
@Override
public void register(String path, EntityBeanIntercept ebi, BeanPropertyAssocOne<?> property) {
getBeanContextWithInherit(path, property).register(ebi);
beanContextWithInherit(path, property).register(ebi);
}
@Override
public void register(String path, BeanPropertyAssocMany<?> many, BeanCollection<?> bc) {
getManyContext(path, many).register(bc);
manyContext(path, many).register(bc);
}
int batchSize(OrmQueryProperties props) {
@@ -279,14 +266,14 @@ public final class DLoadContext implements LoadContext {
return batchSize == 0 ? defaultBatchSize : batchSize;
}
DLoadBeanContext getBeanContext(String path) {
DLoadBeanContext beanContext(String path) {
if (path == null) {
return rootBeanContext;
}
return beanMap.computeIfAbsent(path, p -> createBeanContext(p, null));
}
DLoadBeanContext getBeanContextWithInherit(String path, BeanPropertyAssocOne<?> property) {
DLoadBeanContext beanContextWithInherit(String path, BeanPropertyAssocOne<?> property) {
String key = path + ":" + property.targetDescriptor().name();
return beanMap.computeIfAbsent(key, p -> createBeanContext(property, path));
}
@@ -300,7 +287,7 @@ public final class DLoadContext implements LoadContext {
}
}
DLoadManyContext getManyContext(String path, BeanPropertyAssocMany<?> many) {
DLoadManyContext manyContext(String path, BeanPropertyAssocMany<?> many) {
return manyMap.computeIfAbsent(path, p -> createManyContext(p, many));
}
@@ -309,12 +296,12 @@ public final class DLoadContext implements LoadContext {
}
private DLoadManyContext createManyContext(String path, OrmQueryProperties queryProps) {
BeanPropertyAssocMany<?> p = (BeanPropertyAssocMany<?>) getBeanProperty(rootDescriptor, path);
BeanPropertyAssocMany<?> p = (BeanPropertyAssocMany<?>) beanProperty(rootDescriptor, path);
return new DLoadManyContext(this, p, path, queryProps);
}
private DLoadBeanContext createBeanContext(String path, OrmQueryProperties queryProps) {
BeanPropertyAssoc<?> p = (BeanPropertyAssoc<?>) getBeanProperty(rootDescriptor, path);
BeanPropertyAssoc<?> p = (BeanPropertyAssoc<?>) beanProperty(rootDescriptor, path);
return new DLoadBeanContext(this, p.targetDescriptor(), path, queryProps);
}
@@ -322,7 +309,7 @@ public final class DLoadContext implements LoadContext {
return new DLoadBeanContext(this, property.targetDescriptor(), path, null);
}
private BeanProperty getBeanProperty(BeanDescriptor<?> desc, String path) {
private BeanProperty beanProperty(BeanDescriptor<?> desc, String path) {
return desc.findPropertyFromPath(path);
}
@@ -1,10 +1,6 @@
package io.ebeaninternal.server.loadcontext;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanCollectionLoader;
import io.ebean.bean.EntityBean;
import io.ebean.bean.ObjectGraphNode;
import io.ebean.bean.PersistenceContext;
import io.ebean.bean.*;
import io.ebeaninternal.api.LoadManyBuffer;
import io.ebeaninternal.api.LoadManyContext;
import io.ebeaninternal.api.LoadManyRequest;
@@ -77,7 +73,7 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
public String getName() {
return parent.getEbeanServer().name();
return parent.server().name();
}
public void register(BeanCollection<?> bc) {
@@ -99,7 +95,7 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
for (LoadBuffer loadBuffer : bufferList) {
if (loadBuffer.size() > 0) {
LoadManyRequest req = new LoadManyRequest(loadBuffer, parentRequest);
parent.getEbeanServer().loadMany(req);
parent.server().loadMany(req);
}
}
if (forEach) {
@@ -129,7 +125,7 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
this.context = context;
// set the persistence context as at this moment in
// case it changes as part of a findIterate etc
this.persistenceContext = context.getPersistenceContext();
this.persistenceContext = context.persistenceContext();
this.batchSize = batchSize;
}
@@ -158,12 +154,12 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
abstract void clear();
@Override
public BeanPropertyAssocMany<?> getBeanProperty() {
public BeanPropertyAssocMany<?> beanProperty() {
return context.property;
}
@Override
public ObjectGraphNode getObjectGraphNode() {
public ObjectGraphNode objectGraphNode() {
return context.objectGraphNode;
}
@@ -178,17 +174,17 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
}
@Override
public BeanDescriptor<?> getBeanDescriptor() {
public BeanDescriptor<?> descriptor() {
return context.desc;
}
@Override
public PersistenceContext getPersistenceContext() {
public PersistenceContext persistenceContext() {
return persistenceContext;
}
@Override
public String getFullPath() {
public String fullPath() {
return context.fullPath;
}
@@ -205,14 +201,14 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
if (parentDesc.cacheManyPropLoad(context.property, bc, parentKey, context.parent.isReadOnly())) {
// we loaded the bean collection from cache so remove it from the buffer
if (removeFromBuffer(bc)) {
bc.setLoader(context.parent.getEbeanServer());
bc.setLoader(context.parent.server());
}
// find it using instance equality - avoiding equals() and potential deadlock issue
return;
}
}
context.parent.getEbeanServer().loadMany(new LoadManyRequest(this, onlyIds, useCache, bc));
context.parent.server().loadMany(new LoadManyRequest(this, onlyIds, useCache, bc));
// clear the buffer as all entries have been loaded
clear();
} finally {
@@ -661,7 +661,7 @@ public final class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfi
@Override
public void profileBean(EntityBeanIntercept ebi, String prefix) {
ObjectGraphNode node = request.loadContext().getObjectGraphNode(prefix);
ObjectGraphNode node = request.loadContext().objectGraphNode(prefix);
ebi.setNodeUsageCollector(new NodeUsageCollector(node, profilingListener));
}
@@ -5,6 +5,7 @@ import io.ebeaninternal.api.BindParams;
import io.ebeaninternal.api.CoreLog;
import io.ebeaninternal.api.SpiExpressionList;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.bind.DataBind;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
@@ -14,7 +15,6 @@ import io.ebeaninternal.server.persist.Binder;
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
import io.ebeaninternal.server.querydefn.OrmUpdateProperties;
import io.ebeaninternal.server.rawsql.SpiRawSql;
import io.ebeaninternal.server.bind.DataBind;
import io.ebeaninternal.server.util.BindParamsParser;
import java.sql.Connection;
@@ -47,26 +47,14 @@ public final class CQueryPredicates {
private final Object idValue;
private final BindParams bindParams;
private DefaultExpressionRequest filterMany;
/**
* SQL generated from the where expressions.
*/
private String filterManyExprSql;
/**
* Bind values from the where expressions.
*/
private DefaultExpressionRequest where;
/**
* SQL generated from the where expressions.
*/
private String whereExprSql;
/**
* Bind values for having expression.
*/
private DefaultExpressionRequest having;
/**
* SQL generated from the having expression.
*/
private String havingExprSql;
private String dbHaving;
/**
* logicalWhere with property names converted to db columns.
@@ -190,70 +178,46 @@ public final class CQueryPredicates {
buildUpdateClause(buildSql, deployParser);
buildBindWhereRawSql(buildSql);
BeanPropertyAssocMany<?> manyProperty = request.determineMany();
if (buildSql) {
String logicalOrderBy = deriveOrderByWithMany(request.manyPropertyForOrderBy());
if (logicalOrderBy != null) {
dbOrderBy = deployParser.parse(logicalOrderBy);
}
// create a copy of the includes required to support the orderBy
orderByIncludes = new HashSet<>(deployParser.includes());
}
SpiExpressionList<?> whereExp = query.getWhereExpressions();
if (whereExp != null) {
this.where = new DefaultExpressionRequest(request, deployParser, binder, whereExp);
if (buildSql) {
whereExprSql = where.buildSql();
dbWhere = where.buildSql();
}
}
BeanPropertyAssocMany<?> manyProperty = request.determineMany();
if (manyProperty != null) {
OrmQueryProperties chunk = query.getDetail().getChunk(manyProperty.name(), false);
SpiExpressionList<?> filterManyExpr = chunk.getFilterMany();
if (filterManyExpr != null) {
this.filterMany = new DefaultExpressionRequest(request, deployParser, binder, filterManyExpr);
if (buildSql) {
filterManyExprSql = filterMany.buildSql();
dbFilterMany = filterMany.buildSql();
}
}
}
// having expression
SpiExpressionList<?> havingExpr = query.getHavingExpressions();
if (havingExpr != null) {
this.having = new DefaultExpressionRequest(request, deployParser, binder, havingExpr);
if (buildSql) {
havingExprSql = having.buildSql();
dbHaving = having.buildSql();
}
}
if (buildSql) {
parsePropertiesToDbColumns(deployParser);
predicateIncludes = deployParser.includes();
}
}
/**
* Parse/Convert property names to database columns in the where and order by
* clauses etc.
*/
private void parsePropertiesToDbColumns(DeployParser deployParser) {
// order by is dependent on the manyProperty (if there is one)
String logicalOrderBy = deriveOrderByWithMany(request.manyPropertyForOrderBy());
if (logicalOrderBy != null) {
dbOrderBy = deployParser.parse(logicalOrderBy);
}
// create a copy of the includes required to support the orderBy
orderByIncludes = new HashSet<>(deployParser.getIncludes());
dbWhere = deriveWhere(deployParser);
dbFilterMany = deriveFilterMany(deployParser);
dbHaving = deriveHaving(deployParser);
// all includes, including ones for manyWhere clause
predicateIncludes = deployParser.getIncludes();
}
private String deriveFilterMany(DeployParser deployParser) {
if (isEmpty(filterManyExprSql)) {
return null;
} else {
return deployParser.parse(filterManyExprSql);
}
}
private String deriveWhere(DeployParser deployParser) {
return parse(whereExprSql, deployParser);
}
/**
* Replace the table alias place holders.
* Replace the table alias place-holders.
*/
void parseTableAlias(SqlTreeAlias alias) {
if (dbWhere != null) {
@@ -272,20 +236,6 @@ public final class CQueryPredicates {
}
}
private boolean isEmpty(String s) {
return s == null || s.isEmpty();
}
private String parse(String expr, DeployParser deployParser) {
if (expr == null) return "";
if (expr.isEmpty()) return expr;
return deployParser.parse(expr);
}
private String deriveHaving(DeployParser deployParser) {
return parse(havingExprSql, deployParser);
}
private String parseOrderBy() {
OrderBy<?> orderBy = query.getOrderBy();
if (orderBy == null) {
@@ -353,7 +303,7 @@ public final class CQueryPredicates {
* Return the bind values for the where expression.
*/
public List<Object> whereExprBindValues() {
return where == null ? Collections.emptyList() : where.getBindValues();
return where == null ? Collections.emptyList() : where.bindValues();
}
/**
@@ -26,11 +26,13 @@ public class DeployPropertyParserTest extends BaseTest {
@Test
public void depth1_path() {
Assertions.assertThat(parser().property("billingAddress.city")).isEqualTo("${billingAddress}city");
Assertions.assertThat(parser().parse("billingAddress.city")).isEqualTo("${billingAddress}city");
}
@Test
public void depth2_path() {
Assertions.assertThat(parser().property("max(billingAddress.country.name)")).isEqualTo("max(${billingAddress.country}name)");
Assertions.assertThat(parser().parse("max(billingAddress.country.name)")).isEqualTo("max(${billingAddress.country}name)");
}
@@ -69,6 +71,7 @@ public class DeployPropertyParserTest extends BaseTest {
@Test
public void unknown_path() {
Assertions.assertThat(parser().property(" foo ")).isEqualTo(" foo ");
Assertions.assertThat(parser().parse(" foo ")).isEqualTo(" foo ");
}
@@ -15,7 +15,7 @@ public class BetweenExpressionTest extends BaseExpressionTest {
BetweenExpression exp = new BetweenExpression("startDate", 1, 2);
exp.addSql(expReq);
assertThat(expReq.getSql()).isEqualTo("startDate between ? and ?");
assertThat(expReq.sql()).isEqualTo("startDate between ? and ?");
}
@Test
@@ -15,7 +15,7 @@ public class BetweenPropertyExpressionTest extends BaseExpressionTest {
public void sqlExpression() {
TDSpiExpressionRequest request = new TDSpiExpressionRequest(null);
exp("a", "b", 10).addSql(request);
Assertions.assertThat(request.getSql()).isEqualTo(" ? between a and b");
Assertions.assertThat(request.sql()).isEqualTo(" ? between a and b");
}
@Test
@@ -13,14 +13,14 @@ import static org.mockito.Mockito.verify;
public class InQueryExpressionTest extends BaseExpressionTest {
private SubQueryExpression exp(String propertyName, boolean not, String sql, Object... bindValues) {
var op = not ? SubQueryExpression.SQOp.NOTIN : SubQueryExpression.SQOp.IN;
var op = not ? SubQueryOp.NOTIN : SubQueryOp.IN;
return new SubQueryExpression(op, propertyName, sql, Arrays.asList(bindValues));
}
@Test
void copy_subQuery_expectNewInstance() {
SpiQuery<?> subQuery = mock(SpiQuery.class);
var orig = new SubQueryExpression(SubQueryExpression.SQOp.IN, "name", subQuery);
var orig = new SubQueryExpression(SubQueryOp.IN, "name", subQuery);
SpiExpression copy = orig.copy();
assertThat(copy).isNotSameAs(orig);
verify(subQuery).copy();
@@ -15,7 +15,7 @@ public class InRangeExpressionTest extends BaseExpressionTest {
InRangeExpression exp = new InRangeExpression("startDate", 1, 2);
exp.addSql(expReq);
assertThat(expReq.getSql()).isEqualTo("(startDate >= ? and startDate < ?)");
assertThat(expReq.sql()).isEqualTo("(startDate >= ? and startDate < ?)");
}
@Test
@@ -29,7 +29,7 @@ public class LogicExpressionTest extends BaseExpressionTest {
LogicExpression and = and(eq("a", 10), eq("b", 10));
and.addSql(expReq);
assertThat(expReq.getSql()).isEqualTo("(a = ? and b = ?)");
assertThat(expReq.sql()).isEqualTo("(a = ? and b = ?)");
}
@Test
@@ -22,7 +22,7 @@ public class NullExpressionTest extends BaseExpressionTest {
nullExp("id", true).addSql(expReq);
assertThat(expReq.getSql()).isEqualTo("id is not null");
assertThat(expReq.sql()).isEqualTo("id is not null");
}
@Test
@@ -32,7 +32,7 @@ public class NullExpressionTest extends BaseExpressionTest {
nullExp("id", false).addSql(expReq);
assertThat(expReq.getSql()).isEqualTo("id is null");
assertThat(expReq.sql()).isEqualTo("id is null");
}
@Test
@@ -42,7 +42,7 @@ public class NullExpressionTest extends BaseExpressionTest {
nullExp("customer", true).addSql(expReq);
assertThat(expReq.getSql()).isEqualTo("customer.id is not null");
assertThat(expReq.sql()).isEqualTo("customer.id is not null");
}
@Test
@@ -52,7 +52,7 @@ public class NullExpressionTest extends BaseExpressionTest {
nullExp("customer", false).addSql(expReq);
assertThat(expReq.getSql()).isEqualTo("customer.id is null");
assertThat(expReq.sql()).isEqualTo("customer.id is null");
}
@Test
@@ -24,7 +24,7 @@ public class TDSpiExpressionRequest implements SpiExpressionRequest {
}
@Override
public DbExpressionHandler getDbPlatformHandler() {
public DbExpressionHandler platformHandler() {
return null;
}
@@ -34,18 +34,30 @@ public class TDSpiExpressionRequest implements SpiExpressionRequest {
}
@Override
public BeanDescriptor<?> getBeanDescriptor() {
public BeanDescriptor<?> descriptor() {
return descriptor;
}
@Override
public SpiOrmQueryRequest<?> getQueryRequest() {
public SpiOrmQueryRequest<?> queryRequest() {
return null;
}
@Override
public SpiExpressionRequest append(String sqlExpression) {
sql.append(sqlExpression);
public SpiExpressionRequest append(String expression) {
sql.append(expression);
return this;
}
@Override
public SpiExpressionRequest property(String expression) {
sql.append(expression);
return this;
}
@Override
public SpiExpressionRequest parse(String expression) {
sql.append(expression);
return this;
}
@@ -60,12 +72,12 @@ public class TDSpiExpressionRequest implements SpiExpressionRequest {
}
@Override
public String getSql() {
public String sql() {
return sql.toString();
}
@Override
public ArrayList<Object> getBindValues() {
public ArrayList<Object> bindValues() {
return null;
}
@@ -15,7 +15,7 @@ public class HanaDbExpressionTest {
SpiExpressionRequest request = new DefaultExpressionRequest(null);
expression.arrayContains(request, "arrayproperty", true, "v1", "v2", "v3");
assertEquals("(? member of arrayproperty) and (? member of arrayproperty) and (? member of arrayproperty)",
request.getSql());
request.sql());
}
@Test
@@ -24,28 +24,28 @@ public class HanaDbExpressionTest {
expression.arrayContains(request, "arrayproperty", false, "v1", "v2", "v3");
assertEquals(
"(? not member of arrayproperty) and (? not member of arrayproperty) and (? not member of arrayproperty)",
request.getSql());
request.sql());
}
@Test
public void testArrayContainsEmpty() {
SpiExpressionRequest request = new DefaultExpressionRequest(null);
expression.arrayContains(request, "arrayproperty", true);
assertEquals("", request.getSql());
assertEquals("", request.sql());
}
@Test
public void testArrayIsEmpty() {
SpiExpressionRequest request = new DefaultExpressionRequest(null);
expression.arrayIsEmpty(request, "arrayproperty", true);
assertEquals("cardinality(arrayproperty) = 0", request.getSql());
assertEquals("cardinality(arrayproperty) = 0", request.sql());
}
@Test
public void testArrayIsNotEmpty() {
SpiExpressionRequest request = new DefaultExpressionRequest(null);
expression.arrayIsEmpty(request, "arrayproperty", false);
assertEquals("cardinality(arrayproperty) <> 0", request.getSql());
assertEquals("cardinality(arrayproperty) <> 0", request.sql());
}
@Test
@@ -64,6 +64,6 @@ public class HanaDbExpressionTest {
public void testJson() {
SpiExpressionRequest request = new DefaultExpressionRequest(null);
expression.json(request, "jsonproperty", "path", Op.EQ, "val");
assertEquals("json_value(jsonproperty, '$.path') = ?", request.getSql());
assertEquals("json_value(jsonproperty, '$.path') = ?", request.sql());
}
}
@@ -15,6 +15,6 @@ public class MySqlDbExpressionTest {
public void testJson() {
SpiExpressionRequest request = new DefaultExpressionRequest(null);
expression.json(request, "jsonproperty", "path", Op.EQ, "val");
assertEquals("(jsonproperty ->> '$.path') = ?", request.getSql());
assertEquals("(jsonproperty ->> '$.path') = ?", request.sql());
}
}
@@ -413,4 +413,48 @@ public abstract class PBaseComparable<R, T> extends PBaseValueEqual<R, T> {
expr().gt(_name, subQuery);
return _root;
}
/**
* Less Than or Equal To a raw SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
public final R leSubQuery(String sqlSubQuery, Object... bindValues) {
expr().leSubQuery(_name, sqlSubQuery, bindValues);
return _root;
}
/**
* Less Than a raw SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
public final R ltSubQuery(String sqlSubQuery, Object... bindValues) {
expr().ltSubQuery(_name, sqlSubQuery, bindValues);
return _root;
}
/**
* Greater Than or Equal To a raw SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
public final R geSubQuery(String sqlSubQuery, Object... bindValues) {
expr().geSubQuery(_name, sqlSubQuery, bindValues);
return _root;
}
/**
* Greater Than a raw SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
public final R gtSubQuery(String sqlSubQuery, Object... bindValues) {
expr().gtSubQuery(_name, sqlSubQuery, bindValues);
return _root;
}
}
@@ -301,6 +301,50 @@ public abstract class PBaseValueEqual<R, T> extends TQPropertyBase<R, T> {
return _root;
}
/**
* IN a raw SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
public final R inSubQuery(String sqlSubQuery, Object... bindValues) {
expr().inSubQuery(_name, sqlSubQuery, bindValues);
return _root;
}
/**
* Not IN a raw SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
public final R notInSubQuery(String sqlSubQuery, Object... bindValues) {
expr().notInSubQuery(_name, sqlSubQuery, bindValues);
return _root;
}
/**
* Equal To a raw SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
public final R eqSubQuery(String sqlSubQuery, Object... bindValues) {
expr().eqSubQuery(_name, sqlSubQuery, bindValues);
return _root;
}
/**
* Not Equal To a raw SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
public final R neSubQuery(String sqlSubQuery, Object... bindValues) {
expr().neSubQuery(_name, sqlSubQuery, bindValues);
return _root;
}
/**
* Property is equal to the result of a sub-query.
*
@@ -733,6 +733,28 @@ public abstract class TQRootBean<T, R> {
return root;
}
/**
* EXISTS using a SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
public final R exists(String sqlSubQuery, Object... bindValues) {
query().where().exists(sqlSubQuery, bindValues);
return root;
}
/**
* Not EXISTS using a SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
public final R notExists(String sqlSubQuery, Object... bindValues) {
query().where().notExists(sqlSubQuery, bindValues);
return root;
}
/**
* Execute using "for update" clause which results in the DB locking the record.
*/
@@ -268,6 +268,84 @@ public class QOrderTest {
assertThat(sql).isEqualTo("select t0.id, t0.status from o_order t0 join be_customer t1 on t1.id = t0.customer_id where (coalesce(t1.version,0) > ? or t0.id < ?)");
}
@Test
void geSqlSubQuery() {
var c = QCustomer.alias();
var query = new QCustomer()
.select(c.id)
.registered.geSubQuery("select max(o.order_date) as foo from o_order o")
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered >= (select max(o.order_date) as foo from o_order o)");
}
@Test
void gtSqlSubQuery() {
var c = QCustomer.alias();
var query = new QCustomer()
.select(c.id)
.registered.gtSubQuery("select max(o.order_date) as foo from o_order o")
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered > (select max(o.order_date) as foo from o_order o)");
}
@Test
void leSqlSubQuery() {
var c = QCustomer.alias();
var query = new QCustomer()
.select(c.id)
.registered.leSubQuery("select max(o.order_date) as foo from o_order o")
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <= (select max(o.order_date) as foo from o_order o)");
}
@Test
void ltSqlSubQuery() {
var c = QCustomer.alias();
var query = new QCustomer()
.select(c.id)
.registered.ltSubQuery("select max(o.order_date) as foo from o_order o")
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered < (select max(o.order_date) as foo from o_order o)");
}
@Test
void eqSqlSubQuery() {
var c = QCustomer.alias();
var query = new QCustomer()
.select(c.id)
.registered.eqSubQuery("select max(o.order_date) as foo from o_order o")
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered = (select max(o.order_date) as foo from o_order o)");
}
@Test
void neSqlSubQuery() {
var c = QCustomer.alias();
var query = new QCustomer()
.select(c.id)
.registered.neSubQuery("select max(o.order_date) as foo from o_order o")
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <> (select max(o.order_date) as foo from o_order o)");
}
@Test
void geSubQuery() {
var c = QCustomer.alias();
@@ -394,6 +472,30 @@ public class QOrderTest {
assertThat(sql).contains(" exists (select 1 from o_order_detail od where od.order_qty > ? and od.id = t1.id)");
}
@Test
void sqlSubQueryExists() {
Query<Order> query = new QOrder()
.exists("select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id", 10)
.orderBy("orderDate").query();
query.findList();
String sql = query.getGeneratedSql();
assertThat(sql).contains(" exists (select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id) order by t0.order_date");
}
@Test
void sqlSubQueryNotExists() {
Query<Order> query = new QOrder()
.notExists("select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id", 10)
.orderBy("orderDate").query();
query.findList();
String sql = query.getGeneratedSql();
assertThat(sql).contains(" not exists (select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id) order by t0.order_date");
}
@Test
void subQueryNotExists() {
Query<OrderDetail> subQuery = new QOrderDetail()
@@ -1,12 +1,12 @@
package org.tests.query;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import io.ebean.Expr;
import io.ebean.Query;
import io.ebean.xtest.ForPlatform;
import io.ebean.annotation.Platform;
import io.ebean.test.LoggedSql;
import io.ebean.xtest.BaseTestCase;
import io.ebean.xtest.ForPlatform;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.Customer;
import org.tests.model.basic.Order;
@@ -187,4 +187,93 @@ public class TestWhereRawClause extends BaseTestCase {
.findList();
}
@Test
void testSqlSubQueryExists() {
ResetBasicData.reset();
LoggedSql.start();
DB.find(Order.class)
.select("id")
.where()
.exists("select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id", 10)
.findList();
DB.find(Order.class)
.select("id")
.where()
.notExists("select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id", 10)
.findList();
List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(2);
assertThat(sql.get(0)).contains("select t0.id from o_order t0 where exists (select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id)");
assertThat(sql.get(1)).contains("select t0.id from o_order t0 where not exists (select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id)");
}
@Test
void testSqlSubQueryExpressions() {
ResetBasicData.reset();
LoggedSql.start();
DB.find(Customer.class)
.select("name")
.where()
.inSubQuery("id", "select c.id as id from o_customer c")
.findList();
DB.find(Customer.class)
.select("name")
.where()
.notInSubQuery("id", "select c.id as id from o_customer c")
.findList();
DB.find(Customer.class)
.select("name")
.where()
.eqSubQuery("id", "select c.id as id from o_customer c where c.name = ?", "Rob")
.findList();
DB.find(Customer.class)
.select("name")
.where()
.neSubQuery("id", "select c.id as id from o_customer c where c.name = ?", "Rob")
.findList();
DB.find(Customer.class)
.select("name")
.where()
.gtSubQuery("id", "select c.id as id from o_customer c where c.name = ?", "Rob")
.findList();
DB.find(Customer.class)
.select("name")
.where()
.geSubQuery("id", "select c.id as id from o_customer c where c.name = ?", "Rob")
.findList();
DB.find(Customer.class)
.select("name")
.where()
.ltSubQuery("id", "select c.id as id from o_customer c where c.name = ?", "Rob")
.findList();
DB.find(Customer.class)
.select("name")
.where()
.leSubQuery("id", "select c.id as id from o_customer c where c.name = ? and 1 = ?", "Rob", 1)
.like("name", "R%")
.findList();
List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(8);
assertThat(sql.get(0)).contains("select t0.id, t0.name from o_customer t0 where t0.id in (select c.id as id from o_customer c)");
assertThat(sql.get(1)).contains("select t0.id, t0.name from o_customer t0 where t0.id not in (select c.id as id from o_customer c)");
assertThat(sql.get(2)).contains("select t0.id, t0.name from o_customer t0 where t0.id = (select c.id as id from o_customer c where c.name = ?)");
assertThat(sql.get(3)).contains("select t0.id, t0.name from o_customer t0 where t0.id <> (select c.id as id from o_customer c where c.name = ?)");
assertThat(sql.get(4)).contains("select t0.id, t0.name from o_customer t0 where t0.id > (select c.id as id from o_customer c where c.name = ?)");
assertThat(sql.get(5)).contains("select t0.id, t0.name from o_customer t0 where t0.id >= (select c.id as id from o_customer c where c.name = ?)");
assertThat(sql.get(6)).contains("select t0.id, t0.name from o_customer t0 where t0.id < (select c.id as id from o_customer c where c.name = ?)");
assertThat(sql.get(7)).contains("select t0.id, t0.name from o_customer t0 where t0.id <= (select c.id as id from o_customer c where c.name = ? and 1 = ?)");
}
}