mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#1348 - ENH: Add support for bitwiseAnd / bitwiseAny / bitwiseAll .. expressions for use with integer/long "Flags" properties
This commit is contained in:
@@ -327,6 +327,30 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression allEq(Map<String, Object> propertyMap);
|
||||
|
||||
/**
|
||||
* Add expression for ANY of the given bit flags to be set.
|
||||
*
|
||||
* @param propertyName The property that holds the flags value
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
Expression bitwiseAny(String propertyName, long flags);
|
||||
|
||||
/**
|
||||
* Add expression for ALL of the given bit flags to be set.
|
||||
*
|
||||
* @param propertyName The property that holds the flags value
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
Expression bitwiseAll(String propertyName, long flags);
|
||||
|
||||
/**
|
||||
* Add bitwise AND expression of the given bit flags to compare with the match/mask.
|
||||
*
|
||||
* @param propertyName The property that holds the flags value
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
Expression bitwiseAnd(String propertyName, long flags, long match);
|
||||
|
||||
/**
|
||||
* Add raw expression with a single parameter.
|
||||
* <p>
|
||||
|
||||
@@ -482,7 +482,7 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Extended version for setDistinct in conjunction with "findSingleAttributeList";
|
||||
*
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<CountedValue<Order.Status>> orderStatusCount =
|
||||
@@ -878,7 +878,7 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* In - using a subQuery.
|
||||
*
|
||||
* <p>
|
||||
* This is exactly the same as in() and provided due to "in" being a Kotlin keyword
|
||||
* (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
|
||||
*/
|
||||
@@ -888,7 +888,7 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* In - property has a value in the array of values.
|
||||
*
|
||||
* <p>
|
||||
* This is exactly the same as in() and provided due to "in" being a Kotlin keyword
|
||||
* (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
|
||||
*/
|
||||
@@ -898,7 +898,7 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* In - property has a value in the collection of values.
|
||||
*
|
||||
* <p>
|
||||
* This is exactly the same as in() and provided due to "in" being a Kotlin keyword
|
||||
* (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
|
||||
*/
|
||||
@@ -996,6 +996,53 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> arrayIsNotEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Add expression for ANY of the given bit flags to be set.
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().bitwiseAny("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyName The property that holds the flags value
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
ExpressionList<T> bitwiseAny(String propertyName, long flags);
|
||||
|
||||
/**
|
||||
* Add expression for ALL of the given bit flags to be set.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().bitwiseAll("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyName The property that holds the flags value
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
ExpressionList<T> bitwiseAll(String propertyName, long flags);
|
||||
|
||||
/**
|
||||
* Add bitwise AND expression of the given bit flags to compare with the match/mask.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Flags Bulk + Size = Size
|
||||
* // ... meaning Bulk is not set and Size is set
|
||||
*
|
||||
* long selectedFlags = BwFlags.HAS_BULK + BwFlags.HAS_SIZE;
|
||||
* long mask = BwFlags.HAS_SIZE; // Only Size flag set
|
||||
*
|
||||
* where().bitwiseAnd("flags", selectedFlags, mask)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyName The property that holds the flags value
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
ExpressionList<T> bitwiseAnd(String propertyName, long flags, long match);
|
||||
|
||||
/**
|
||||
* Add raw expression with a single parameter.
|
||||
* <p>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebeaninternal.server.core.DbExpressionHandler;
|
||||
import io.ebeaninternal.server.core.SpiOrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
/**
|
||||
* Not supported JSON or ARRAY expression handler.
|
||||
*/
|
||||
abstract class BaseDbExpression implements DbExpressionHandler {
|
||||
|
||||
private final String concatOperator;
|
||||
|
||||
BaseDbExpression(String concatOperator) {
|
||||
this.concatOperator = concatOperator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConcatOperator() {
|
||||
return concatOperator;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -42,6 +42,8 @@ import io.ebeaninternal.server.deploy.parse.DeployInherit;
|
||||
import io.ebeaninternal.server.deploy.parse.DeployUtil;
|
||||
import io.ebeaninternal.server.dto.DtoBeanManager;
|
||||
import io.ebeaninternal.server.expression.DefaultExpressionFactory;
|
||||
import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
|
||||
import io.ebeaninternal.server.expression.platform.DbExpressionHandlerFactory;
|
||||
import io.ebeaninternal.server.persist.Binder;
|
||||
import io.ebeaninternal.server.persist.DefaultPersister;
|
||||
import io.ebeaninternal.server.persist.platform.MultiValueBind;
|
||||
@@ -267,18 +269,7 @@ public class InternalConfiguration {
|
||||
* Return the JSON expression handler for the given database platform.
|
||||
*/
|
||||
private DbExpressionHandler getDbExpressionHandler(DatabasePlatform databasePlatform) {
|
||||
Platform platform = databasePlatform.getPlatform();
|
||||
String concatOperator = databasePlatform.getConcatOperator();
|
||||
switch (platform) {
|
||||
case POSTGRES:
|
||||
return new PostgresDbExpression(concatOperator);
|
||||
case ORACLE:
|
||||
return new OracleDbExpression(concatOperator);
|
||||
case SQLSERVER:
|
||||
return new SqlServerDbExpression(concatOperator);
|
||||
default:
|
||||
return new BasicDbExpression(concatOperator);
|
||||
}
|
||||
return DbExpressionHandlerFactory.from(databasePlatform);
|
||||
}
|
||||
|
||||
private MultiValueBind createMultiValueBind(Platform platform) {
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Bitwise expression.
|
||||
*/
|
||||
class BitwiseExpression extends AbstractExpression {
|
||||
|
||||
protected final BitwiseOp operator;
|
||||
|
||||
private final String compare;
|
||||
|
||||
protected final long flags;
|
||||
|
||||
private final long match;
|
||||
|
||||
BitwiseExpression(String propertyName, BitwiseOp operator, long flags, String compare, long match) {
|
||||
super(propertyName);
|
||||
this.operator = operator;
|
||||
this.flags = flags;
|
||||
this.compare = compare;
|
||||
this.match = match;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeDocQuery(DocQueryContext context) throws IOException {
|
||||
throw new IllegalStateException("Not supported for document queries");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryPlanHash(StringBuilder builder) {
|
||||
builder.append("Bitwise[");
|
||||
builder.append(propName).append(" op:").append(operator).append(" cp:").append(compare);
|
||||
builder.append(" ?2]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return Long.hashCode(flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
BitwiseExpression that = (BitwiseExpression) other;
|
||||
return operator == that.operator && compare.equals(that.compare) && flags == that.flags && match == that.match;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSql(SpiExpressionRequest request) {
|
||||
// Use DB specific expression handling
|
||||
request.getDbPlatformHandler().bitwise(request, propName, operator, flags, compare, match);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
request.addBindValue(flags);
|
||||
request.addBindValue(match);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
/**
|
||||
* Bitwise expression operator.
|
||||
*/
|
||||
public enum BitwiseOp {
|
||||
|
||||
/**
|
||||
* All flags are set (derived expression BITAND flags == flags).
|
||||
*/
|
||||
ALL,
|
||||
|
||||
/**
|
||||
* Any flags are set (derived expression BITAND flags != 0).
|
||||
*/
|
||||
ANY,
|
||||
|
||||
/**
|
||||
* BITAND flags == match.
|
||||
*/
|
||||
AND
|
||||
}
|
||||
@@ -136,6 +136,21 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
|
||||
return new ArrayIsEmptyExpression(propertyName, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression bitwiseAny(String propertyName, long flags) {
|
||||
return new BitwiseExpression(propertyName, BitwiseOp.ANY, flags, "!=", 0L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression bitwiseAll(String propertyName, long flags) {
|
||||
return new BitwiseExpression(propertyName, BitwiseOp.ALL, flags, "=", flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression bitwiseAnd(String propertyName, long flags, long match) {
|
||||
return new BitwiseExpression(propertyName, BitwiseOp.AND, flags, "=", match);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
|
||||
@@ -699,6 +699,24 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> bitwiseAny(String propertyName, long flags) {
|
||||
add(expr.bitwiseAny(propertyName, flags));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> bitwiseAll(String propertyName, long flags) {
|
||||
add(expr.bitwiseAll(propertyName, flags));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> bitwiseAnd(String propertyName, long flags, long match) {
|
||||
add(expr.bitwiseAnd(propertyName, flags, match));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> eq(String propertyName, Object value) {
|
||||
add(expr.eq(propertyName, value));
|
||||
|
||||
@@ -2,10 +2,10 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.SpiExpressionList;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.core.DbExpressionHandler;
|
||||
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.type.DataBind;
|
||||
|
||||
|
||||
@@ -533,6 +533,21 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
return exprList.arrayIsNotEmpty(propertyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> bitwiseAny(String propertyName, long flags) {
|
||||
return exprList.bitwiseAny(propertyName, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> bitwiseAll(String propertyName, long flags) {
|
||||
return exprList.bitwiseAll(propertyName, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> bitwiseAnd(String propertyName, long flags, long match) {
|
||||
return exprList.bitwiseAnd(propertyName, flags, match);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> ge(String propertyName, Object value) {
|
||||
return exprList.ge(propertyName, value);
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package io.ebeaninternal.server.expression.platform;
|
||||
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.expression.BitwiseOp;
|
||||
|
||||
/**
|
||||
* Not supported JSON or ARRAY expression handler.
|
||||
*/
|
||||
abstract class BaseDbExpression implements DbExpressionHandler {
|
||||
|
||||
private final String concatOperator;
|
||||
|
||||
BaseDbExpression(String concatOperator) {
|
||||
this.concatOperator = concatOperator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConcatOperator() {
|
||||
return concatOperator;
|
||||
}
|
||||
|
||||
@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(" ?)");
|
||||
}
|
||||
|
||||
private String bitOp(BitwiseOp operator) {
|
||||
switch (operator) {
|
||||
case ANY:
|
||||
case AND:
|
||||
case ALL:
|
||||
return "&";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown Bitwise operator " + operator + " not handled?");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(" ?");
|
||||
}
|
||||
|
||||
protected String functionName(BitwiseOp operator) {
|
||||
switch (operator) {
|
||||
case AND:
|
||||
case ANY:
|
||||
case ALL:
|
||||
return "bitand";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown Bitwise operator " + operator + " not handled?");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
package io.ebeaninternal.server.expression.platform;
|
||||
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.expression.Op;
|
||||
+6
-1
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
package io.ebeaninternal.server.expression.platform;
|
||||
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.expression.BitwiseOp;
|
||||
import io.ebeaninternal.server.expression.Op;
|
||||
|
||||
/**
|
||||
@@ -28,4 +29,8 @@ public interface DbExpressionHandler {
|
||||
*/
|
||||
void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty);
|
||||
|
||||
/**
|
||||
* Add the bitwise expression.
|
||||
*/
|
||||
void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match);
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package io.ebeaninternal.server.expression.platform;
|
||||
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
|
||||
public class DbExpressionHandlerFactory {
|
||||
|
||||
/**
|
||||
* Create and return the appropriate platform specific handing of expressions.
|
||||
*/
|
||||
public static DbExpressionHandler from(DatabasePlatform databasePlatform) {
|
||||
|
||||
Platform platform = databasePlatform.getPlatform();
|
||||
String concatOperator = databasePlatform.getConcatOperator();
|
||||
switch (platform) {
|
||||
case H2:
|
||||
return new H2DbExpression(concatOperator);
|
||||
case POSTGRES:
|
||||
return new PostgresDbExpression(concatOperator);
|
||||
case MYSQL:
|
||||
return new MySqlDbExpression(concatOperator);
|
||||
case ORACLE:
|
||||
return new OracleDbExpression(concatOperator);
|
||||
case SQLSERVER:
|
||||
return new SqlServerDbExpression(concatOperator);
|
||||
default:
|
||||
return new BasicDbExpression(concatOperator);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package io.ebeaninternal.server.expression.platform;
|
||||
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.expression.BitwiseOp;
|
||||
|
||||
/**
|
||||
* H2 handling of platform specific expressions.
|
||||
*/
|
||||
class H2DbExpression extends BasicDbExpression {
|
||||
|
||||
H2DbExpression(String concatOperator) {
|
||||
super(concatOperator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
|
||||
|
||||
bitwiseFunction(request, propName, operator, compare);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package io.ebeaninternal.server.expression.platform;
|
||||
|
||||
/**
|
||||
* MySql specific handling of platform specific expressions.
|
||||
*/
|
||||
class MySqlDbExpression extends BasicDbExpression {
|
||||
|
||||
MySqlDbExpression(String concatOperator) {
|
||||
super(concatOperator);
|
||||
}
|
||||
|
||||
}
|
||||
+8
-2
@@ -1,10 +1,11 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
package io.ebeaninternal.server.expression.platform;
|
||||
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.expression.BitwiseOp;
|
||||
import io.ebeaninternal.server.expression.Op;
|
||||
|
||||
/**
|
||||
* Oracle JSON expression handler, ARRAY expressions not supported.
|
||||
* Oracle handling of platform specific expressions. ARRAY expressions not supported.
|
||||
*/
|
||||
public class OracleDbExpression extends BaseDbExpression {
|
||||
|
||||
@@ -25,6 +26,11 @@ public class OracleDbExpression extends BaseDbExpression {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
|
||||
bitwiseFunction(request, propName, operator, compare);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arrayContains(SpiExpressionRequest request, String propName, boolean contains, Object... values) {
|
||||
throw new IllegalStateException("ARRAY expressions not supported on Oracle");
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
package io.ebeaninternal.server.expression.platform;
|
||||
|
||||
/**
|
||||
* Helper for determining type casting for JSON and ARRAY expressions.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
package io.ebeaninternal.server.expression.platform;
|
||||
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.expression.Op;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
package io.ebeaninternal.server.expression.platform;
|
||||
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.expression.Op;
|
||||
@@ -2,9 +2,9 @@ package io.ebeaninternal.server.persist;
|
||||
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebeaninternal.api.BindParams;
|
||||
import io.ebeaninternal.server.core.DbExpressionHandler;
|
||||
import io.ebeaninternal.server.core.Message;
|
||||
import io.ebeaninternal.server.core.timezone.DataTimeZone;
|
||||
import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
|
||||
import io.ebeaninternal.server.persist.platform.MultiValueBind;
|
||||
import io.ebeaninternal.server.transaction.TransactionManager;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
|
||||
Reference in New Issue
Block a user