mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Add support for raw SQL SubQuery expressions IN,EQ,NE,GT,GE,LT,LE,EXISTS,Not IN, Not EXISTS
For these expressions the SQL SubQuery is not parsed by ebean and just used as is.
This commit is contained in:
@@ -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.
|
||||
*/
|
||||
|
||||
+64
-9
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+55
-39
@@ -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
-2
@@ -93,9 +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 (").parse(sql).append(")");
|
||||
request.append("exists (").parse(sql).append(")");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+106
@@ -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
|
||||
}
|
||||
}
|
||||
+54
-36
@@ -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);
|
||||
|
||||
+3
-18
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
+61
@@ -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);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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();
|
||||
|
||||
@@ -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 = ?)");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user