diff --git a/pom.xml b/pom.xml index 37d6b08ad..85d2ecd68 100644 --- a/pom.xml +++ b/pom.xml @@ -254,7 +254,7 @@ com.microsoft.sqlserver mssql-jdbc - 6.1.3.jre8-preview + 6.4.0.jre8 test diff --git a/src/main/java/io/ebean/ExpressionFactory.java b/src/main/java/io/ebean/ExpressionFactory.java index a2c44cffb..0c81a32e3 100644 --- a/src/main/java/io/ebean/ExpressionFactory.java +++ b/src/main/java/io/ebean/ExpressionFactory.java @@ -327,6 +327,30 @@ public interface ExpressionFactory { */ Expression allEq(Map 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. *

diff --git a/src/main/java/io/ebean/ExpressionList.java b/src/main/java/io/ebean/ExpressionList.java index 4723ab212..711d23906 100644 --- a/src/main/java/io/ebean/ExpressionList.java +++ b/src/main/java/io/ebean/ExpressionList.java @@ -482,7 +482,7 @@ public interface ExpressionList { /** * Extended version for setDistinct in conjunction with "findSingleAttributeList"; - * + *

*

{@code
    *
    *  List> orderStatusCount =
@@ -878,7 +878,7 @@ public interface ExpressionList {
 
   /**
    * In - using a subQuery.
-   *
+   * 

* 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 { /** * In - property has a value in the array of values. - * + *

* 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 { /** * In - property has a value in the collection of values. - * + *

* 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 { */ ExpressionList arrayIsNotEmpty(String propertyName); + /** + * Add expression for ANY of the given bit flags to be set. + *

{@code
+   *
+   * where().bitwiseAny("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
+   *
+   * }
+ * + * @param propertyName The property that holds the flags value + * @param flags The flags we are looking for + */ + ExpressionList bitwiseAny(String propertyName, long flags); + + /** + * Add expression for ALL of the given bit flags to be set. + *

+ *

{@code
+   *
+   * where().bitwiseAll("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
+   *
+   * }
+ * + * @param propertyName The property that holds the flags value + * @param flags The flags we are looking for + */ + ExpressionList bitwiseAll(String propertyName, long flags); + + /** + * Add bitwise AND expression of the given bit flags to compare with the match/mask. + *

+ *

{@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)
+   *
+   * }
+ * + * @param propertyName The property that holds the flags value + * @param flags The flags we are looking for + */ + ExpressionList bitwiseAnd(String propertyName, long flags, long match); + /** * Add raw expression with a single parameter. *

diff --git a/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java b/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java index 49bb47bf9..e61c9479e 100644 --- a/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java +++ b/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java @@ -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; diff --git a/src/main/java/io/ebeaninternal/server/core/BaseDbExpression.java b/src/main/java/io/ebeaninternal/server/core/BaseDbExpression.java deleted file mode 100644 index fe2c97893..000000000 --- a/src/main/java/io/ebeaninternal/server/core/BaseDbExpression.java +++ /dev/null @@ -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; - } - -} diff --git a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java index e9b423ece..ab0587d94 100644 --- a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java +++ b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java @@ -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) { diff --git a/src/main/java/io/ebeaninternal/server/expression/BitwiseExpression.java b/src/main/java/io/ebeaninternal/server/expression/BitwiseExpression.java new file mode 100644 index 000000000..073ee51df --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/expression/BitwiseExpression.java @@ -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); + } +} diff --git a/src/main/java/io/ebeaninternal/server/expression/BitwiseOp.java b/src/main/java/io/ebeaninternal/server/expression/BitwiseOp.java new file mode 100644 index 000000000..c7a063f54 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/expression/BitwiseOp.java @@ -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 +} diff --git a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java index 4725d41e5..14ab457c8 100644 --- a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java +++ b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java @@ -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. */ diff --git a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java index 29747b439..ef2e8c89c 100644 --- a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java @@ -699,6 +699,24 @@ public class DefaultExpressionList implements SpiExpressionList { return this; } + @Override + public ExpressionList bitwiseAny(String propertyName, long flags) { + add(expr.bitwiseAny(propertyName, flags)); + return this; + } + + @Override + public ExpressionList bitwiseAll(String propertyName, long flags) { + add(expr.bitwiseAll(propertyName, flags)); + return this; + } + + @Override + public ExpressionList bitwiseAnd(String propertyName, long flags, long match) { + add(expr.bitwiseAnd(propertyName, flags, match)); + return this; + } + @Override public ExpressionList eq(String propertyName, Object value) { add(expr.eq(propertyName, value)); diff --git a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java index a1cc868f0..557c53996 100644 --- a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java +++ b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java @@ -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; diff --git a/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java index 4d4c3a53c..d7d6c0c7a 100644 --- a/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java @@ -533,6 +533,21 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression return exprList.arrayIsNotEmpty(propertyName); } + @Override + public ExpressionList bitwiseAny(String propertyName, long flags) { + return exprList.bitwiseAny(propertyName, flags); + } + + @Override + public ExpressionList bitwiseAll(String propertyName, long flags) { + return exprList.bitwiseAll(propertyName, flags); + } + + @Override + public ExpressionList bitwiseAnd(String propertyName, long flags, long match) { + return exprList.bitwiseAnd(propertyName, flags, match); + } + @Override public ExpressionList ge(String propertyName, Object value) { return exprList.ge(propertyName, value); diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java new file mode 100644 index 000000000..584215d4c --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java @@ -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?"); + } + } + +} diff --git a/src/main/java/io/ebeaninternal/server/core/BasicDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/BasicDbExpression.java similarity index 94% rename from src/main/java/io/ebeaninternal/server/core/BasicDbExpression.java rename to src/main/java/io/ebeaninternal/server/expression/platform/BasicDbExpression.java index ef8ad5b4a..adacca04d 100644 --- a/src/main/java/io/ebeaninternal/server/core/BasicDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/BasicDbExpression.java @@ -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; diff --git a/src/main/java/io/ebeaninternal/server/core/DbExpressionHandler.java b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandler.java similarity index 73% rename from src/main/java/io/ebeaninternal/server/core/DbExpressionHandler.java rename to src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandler.java index 7ce5a4074..7cf6d696a 100644 --- a/src/main/java/io/ebeaninternal/server/core/DbExpressionHandler.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandler.java @@ -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); } diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java new file mode 100644 index 000000000..b7b62eb71 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java @@ -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); + } + } +} diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java new file mode 100644 index 000000000..4e0b544f2 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java @@ -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); + } +} diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java new file mode 100644 index 000000000..e0e04ad1f --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java @@ -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); + } + +} diff --git a/src/main/java/io/ebeaninternal/server/core/OracleDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java similarity index 75% rename from src/main/java/io/ebeaninternal/server/core/OracleDbExpression.java rename to src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java index 82480723d..4347d2e80 100644 --- a/src/main/java/io/ebeaninternal/server/core/OracleDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java @@ -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"); diff --git a/src/main/java/io/ebeaninternal/server/core/PostgresCast.java b/src/main/java/io/ebeaninternal/server/expression/platform/PostgresCast.java similarity index 95% rename from src/main/java/io/ebeaninternal/server/core/PostgresCast.java rename to src/main/java/io/ebeaninternal/server/expression/platform/PostgresCast.java index 47dbb3f74..3e833cb12 100644 --- a/src/main/java/io/ebeaninternal/server/core/PostgresCast.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/PostgresCast.java @@ -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. diff --git a/src/main/java/io/ebeaninternal/server/core/PostgresDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java similarity index 97% rename from src/main/java/io/ebeaninternal/server/core/PostgresDbExpression.java rename to src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java index a6f42bc68..4af9aa2f7 100644 --- a/src/main/java/io/ebeaninternal/server/core/PostgresDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java @@ -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; diff --git a/src/main/java/io/ebeaninternal/server/core/SqlServerDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java similarity index 95% rename from src/main/java/io/ebeaninternal/server/core/SqlServerDbExpression.java rename to src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java index 06a7824a1..dc52066e3 100644 --- a/src/main/java/io/ebeaninternal/server/core/SqlServerDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java @@ -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; diff --git a/src/main/java/io/ebeaninternal/server/persist/Binder.java b/src/main/java/io/ebeaninternal/server/persist/Binder.java index 7a69ee7eb..55833eae5 100644 --- a/src/main/java/io/ebeaninternal/server/persist/Binder.java +++ b/src/main/java/io/ebeaninternal/server/persist/Binder.java @@ -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; diff --git a/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java b/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java index f0179ea0a..5bd44e3de 100644 --- a/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java +++ b/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java @@ -1,9 +1,9 @@ package io.ebeaninternal.server.expression; 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.expression.platform.DbExpressionHandler; import java.util.ArrayList; import java.util.List; diff --git a/src/test/java/io/ebeaninternal/server/core/PostgresCastTest.java b/src/test/java/io/ebeaninternal/server/expression/platform/PostgresCastTest.java similarity index 84% rename from src/test/java/io/ebeaninternal/server/core/PostgresCastTest.java rename to src/test/java/io/ebeaninternal/server/expression/platform/PostgresCastTest.java index f8e43263f..526ca3353 100644 --- a/src/test/java/io/ebeaninternal/server/core/PostgresCastTest.java +++ b/src/test/java/io/ebeaninternal/server/expression/platform/PostgresCastTest.java @@ -1,4 +1,4 @@ -package io.ebeaninternal.server.core; +package io.ebeaninternal.server.expression.platform; import org.junit.Test; @@ -8,7 +8,7 @@ import static org.assertj.core.api.Assertions.assertThat; public class PostgresCastTest { @Test - public void cast() throws Exception { + public void cast() { assertThat(PostgresCast.cast(1)).isEqualTo("::integer"); assertThat(PostgresCast.cast(1L)).isEqualTo("::bigint"); @@ -17,7 +17,7 @@ public class PostgresCastTest { } @Test - public void cast1() throws Exception { + public void cast1() { assertThat(PostgresCast.cast(1, true)).isEqualTo("::integer[]"); assertThat(PostgresCast.cast(1L, true)).isEqualTo("::bigint[]"); diff --git a/src/test/java/org/tests/expression/bitwise/BwBean.java b/src/test/java/org/tests/expression/bitwise/BwBean.java new file mode 100644 index 000000000..5c7fab206 --- /dev/null +++ b/src/test/java/org/tests/expression/bitwise/BwBean.java @@ -0,0 +1,70 @@ +package org.tests.expression.bitwise; + +import io.ebean.Model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; + +@Entity +public class BwBean extends Model { + + @Id + long id; + + String name; + + // sqlserver wants integer type for bitwise AND operator + @Column(columnDefinition = "integer") + long flags; + + @Version + long version; + + public BwBean(String name) { + this.name = name; + } + + public BwBean(String name, long flags) { + this.name = name; + this.flags = flags; + } + + @Override + public String toString() { + return "nm:" + name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getFlags() { + return flags; + } + + public void setFlags(long flags) { + this.flags = flags; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/expression/bitwise/BwFlags.java b/src/test/java/org/tests/expression/bitwise/BwFlags.java new file mode 100644 index 000000000..41944659d --- /dev/null +++ b/src/test/java/org/tests/expression/bitwise/BwFlags.java @@ -0,0 +1,78 @@ +package org.tests.expression.bitwise; + +public class BwFlags { + + public static final int NOTHING = 0; + + /** + * Indicates the bean is being inserted. + */ + public static final int HAS_COLOUR = 0x00000001; + + /** + * Indicates persist cascade. + */ + public static final int HAS_SIZE = 0x00000002; + + /** + * Indicates Publish mode. + */ + public static final int HAS_BULK = 0x00000004; + + /** + * Return true if part of a Merge or Publish. + */ + public static boolean isColour(long state) { + return (state & HAS_COLOUR) != 0; + } + + /** + * Return true if the given flag is set. + */ + public static boolean isSet(int state, int flag) { + return (state & flag) == flag; + } + + public static int setHasColour(int state) { + return set(state, HAS_COLOUR, true); + } + + /** + * Parent was not inserted. + */ + public static int unsetHasColour(int state) { + return set(state, HAS_COLOUR, false); + } + + /** + * Set Recurse flag. + */ + public static int setHasSize(int state) { + return set(state, HAS_SIZE, true); + } + + public static int unsetHasSize(int state) { + return set(state, HAS_SIZE, false); + } + + /** + * Set Publish flag. + */ + public static int setHasBulk(int state) { + return set(state, HAS_BULK, true); + } + + public static int unsetHasBulk(int state) { + return set(state, HAS_BULK, false); + } + + + private static int set(int state, int flag, boolean setFlag) { + if (setFlag) { + return (state |= flag); + } else { + return state &= ~flag; + } + } + +} diff --git a/src/test/java/org/tests/expression/bitwise/TestBitwiseExpressions.java b/src/test/java/org/tests/expression/bitwise/TestBitwiseExpressions.java new file mode 100644 index 000000000..05be5d1ae --- /dev/null +++ b/src/test/java/org/tests/expression/bitwise/TestBitwiseExpressions.java @@ -0,0 +1,141 @@ +package org.tests.expression.bitwise; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestBitwiseExpressions extends BaseTestCase { + + @Test + public void where() { + + setup(); + bitwiseAnd(); + bitwiseAny(); + bitwiseAll(); + } + + private void bitwiseAnd() { + + List list = Ebean.find(BwBean.class) + // not bulk set AND size set + .where().bitwiseAnd("flags", BwFlags.HAS_BULK + BwFlags.HAS_SIZE, BwFlags.HAS_SIZE) + .findList(); + + assertThat(list).hasSize(1); + assertThat(list.get(0).getName()).isEqualTo("SizeOnly"); + + list = Ebean.find(BwBean.class) + // bulk set AND not size set + .where().bitwiseAnd("flags", BwFlags.HAS_BULK + BwFlags.HAS_SIZE, BwFlags.HAS_BULK) + .findList(); + + assertThat(list).hasSize(1); + assertThat(list.get(0).getName()).isEqualTo("ColourAndBulk"); + + list = Ebean.find(BwBean.class) + // bulk set AND not size set + .where().bitwiseAnd("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR, BwFlags.HAS_COLOUR) + .findList(); + + assertThat(list).hasSize(1); + assertThat(list.get(0).getName()).isEqualTo("ColourOnly"); + } + + private void bitwiseAny() { + + List list = Ebean.find(BwBean.class) + .where().bitwiseAny("flags", BwFlags.HAS_BULK + BwFlags.HAS_SIZE) + .findList(); + + assertThat(list).hasSize(3); + assertThat(list.get(0).getName()).isEqualTo("SizeOnly"); + assertThat(list.get(1).getName()).isEqualTo("ColourAndBulk"); + assertThat(list.get(2).getName()).isEqualTo("Everything"); + + + list = Ebean.find(BwBean.class) + .where().bitwiseAny("flags", BwFlags.HAS_BULK + BwFlags.HAS_SIZE + BwFlags.HAS_COLOUR) + .findList(); + + assertThat(list).hasSize(4); + + list = Ebean.find(BwBean.class) + .where().bitwiseAny("flags", BwFlags.HAS_SIZE + BwFlags.HAS_COLOUR) + .findList(); + + assertThat(list).hasSize(4); + + list = Ebean.find(BwBean.class) + .where().bitwiseAny("flags", BwFlags.HAS_SIZE) + .findList(); + + assertThat(list).hasSize(2); + assertThat(list.get(0).getName()).isEqualTo("SizeOnly"); + assertThat(list.get(1).getName()).isEqualTo("Everything"); + + list = Ebean.find(BwBean.class) + .where().bitwiseAny("flags", BwFlags.HAS_COLOUR) + .findList(); + + assertThat(list).hasSize(3); + assertThat(list.get(0).getName()).isEqualTo("ColourOnly"); + assertThat(list.get(1).getName()).isEqualTo("ColourAndBulk"); + assertThat(list.get(2).getName()).isEqualTo("Everything"); + } + + private void bitwiseAll() { + + List list = Ebean.find(BwBean.class) + .where().bitwiseAll("flags", BwFlags.HAS_BULK + BwFlags.HAS_SIZE) + .findList(); + + assertThat(list).hasSize(1); + assertThat(list.get(0).getName()).isEqualTo("Everything"); + + list = Ebean.find(BwBean.class) + .where().bitwiseAll("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR) + .orderBy().asc("id") + .findList(); + + assertThat(list).hasSize(2); + assertThat(list.get(0).getName()).isEqualTo("ColourAndBulk"); + assertThat(list.get(1).getName()).isEqualTo("Everything"); + + list = Ebean.find(BwBean.class) + .where().bitwiseAll("flags", BwFlags.HAS_SIZE) + .orderBy().asc("id") + .findList(); + + assertThat(list).hasSize(2); + assertThat(list.get(0).getName()).isEqualTo("SizeOnly"); + assertThat(list.get(1).getName()).isEqualTo("Everything"); + + list = Ebean.find(BwBean.class) + .where().bitwiseAll("flags", BwFlags.HAS_COLOUR) + .orderBy().asc("id") + .findList(); + + assertThat(list).hasSize(3); + assertThat(list.get(0).getName()).isEqualTo("ColourOnly"); + assertThat(list.get(1).getName()).isEqualTo("ColourAndBulk"); + assertThat(list.get(2).getName()).isEqualTo("Everything"); + + } + + private void setup() { + + Ebean.find(BwBean.class).delete(); + + new BwBean("Nothing", BwFlags.NOTHING).save(); + new BwBean("ColourOnly", BwFlags.HAS_COLOUR).save(); + new BwBean("SizeOnly", BwFlags.HAS_SIZE).save(); + new BwBean("ColourAndBulk", BwFlags.HAS_COLOUR + BwFlags.HAS_BULK).save(); + new BwBean("Everything", BwFlags.HAS_COLOUR + BwFlags.HAS_BULK + BwFlags.HAS_SIZE).save(); + + } +} diff --git a/src/test/java/org/tests/repository/CustomerRepository.java b/src/test/java/org/tests/repository/CustomerRepository.java index 31d18ef96..1dfdb51b1 100644 --- a/src/test/java/org/tests/repository/CustomerRepository.java +++ b/src/test/java/org/tests/repository/CustomerRepository.java @@ -4,12 +4,13 @@ import io.ebean.BeanRepository; import io.ebean.EbeanServer; import org.tests.model.basic.Customer; -import javax.inject.Inject; import java.util.List; +//import javax.inject.Inject; + public class CustomerRepository extends BeanRepository { - @Inject + //@Inject public CustomerRepository(EbeanServer server) { super(Customer.class, server); }