Compare commits

..
Author SHA1 Message Date
rob bygrave 923828ce87 [maven-release-plugin] prepare release ebean-11.35.2 2019-03-05 22:26:19 +13:00
rob bygrave e195f20981 #1645 - ENH: Add expression rawOrEmpty() ... as a convenience for conditionally added a raw expression 2019-03-05 22:13:38 +13:00
rob bygrave 86d0216159 #1644 - ENH: Improve batch flush when multiple "top level" (unrelated) types are persisted 2019-03-04 12:42:08 +13:00
rob bygrave a4698ea1b6 #1643 - ENH: Add expression inOrEmpty() ... as a convenience for conditionally added a IN expression 2019-03-01 18:24:00 +13:00
rob bygrave 888384f7db No effective change (change to DB from Ebean for TestSubQuery) 2019-03-01 18:12:36 +13:00
rob bygrave 817c946eeb [maven-release-plugin] prepare for next development iteration 2019-02-24 16:20:36 +13:00
rob bygrave 1749c2cb4c [maven-release-plugin] prepare release ebean-11.35.1 2019-02-24 16:20:21 +13:00
rob bygrave 3afd3c4530 #1640 Additionally add expression eq and in support for Inet and Postgres any
Bump ebean-types to 1.3 with of() helper methods
2019-02-24 16:18:49 +13:00
rob bygrave e5f98f1b7a #1640 Additionally add expression eq and in support for Inet and Postgres any 2019-02-24 15:29:07 +13:00
rob bygrave 2e496c9e1e Bump pom to 11.35.1-SNAPSHOT 2019-02-21 22:15:49 +13:00
Rob BygraveandGitHub 5975694538 #1640 - For Postgres support mapping InetAddress to INET db column (#1641)
* #1640 - For Postgres support mapping InetAddress to INET db column

* #1640 - For Postgres support mapping InetAddress to INET db column

Support for Inet and Cdir types + offlineMigrationGeneration + PlatformConfig.databaseInetAddressVarchar for turning off InetAddress mapping on Postgres
2019-02-21 22:14:21 +13:00
rob bygrave 03a42f7f6e No effective change - update test DefaultProfileHandlerTest to output profiling files to target 2019-02-21 09:37:14 +13:00
rob bygrave 84f1e05eb4 [maven-release-plugin] prepare for next development iteration 2019-02-18 10:58:21 +13:00
32 changed files with 1007 additions and 75 deletions
+8 -2
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>11.34.3</version>
<version>11.35.2</version>
<packaging>jar</packaging>
<name>ebean</name>
@@ -22,7 +22,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-11.34.3</tag>
<tag>ebean-11.35.2</tag>
</scm>
<profiles>
@@ -120,6 +120,12 @@
<version>4.5</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-types</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-datasource</artifactId>
+37
View File
@@ -250,6 +250,43 @@ public class Expr {
return Ebean.getExpressionFactory().in(propertyName, values);
}
/**
* In where null or empty values means that no predicate is added to the query.
* <p>
* That is, only add the IN predicate if the values are not null or empty.
* <p>
* Without this we typically need to code an <code>if</code> block to only add
* the IN predicate if the collection is not empty like:
* </p>
*
* <h3>Without inOrEmpty()</h3>
* <pre>{@code
*
* query.where() // add some predicates
* .eq("status", Status.NEW);
*
* if (ids != null && !ids.isEmpty()) {
* query.where().in("customer.id", ids);
* }
*
* query.findList();
*
* }</pre>
*
* <h3>Using inOrEmpty()</h3>
* <pre>{@code
*
* query.where()
* .eq("status", Status.NEW)
* .inOrEmpty("customer.id", ids)
* .findList();
*
* }</pre>
*/
public static Expression inOrEmpty(String propertyName, Collection<?> values) {
return Ebean.getExpressionFactory().inOrEmpty(propertyName, values);
}
/**
* Id Equal to - ID property is equal to the value.
*/
@@ -325,6 +325,41 @@ public interface ExpressionFactory {
*/
Expression in(String propertyName, Collection<?> values);
/**
* In where null or empty values means that no predicate is added to the query.
* <p>
* That is, only add the IN predicate if the values are not null or empty.
* <p>
* Without this we typically need to code an <code>if</code> block to only add
* the IN predicate if the collection is not empty like:
* </p>
*
* <h3>Without inOrEmpty()</h3>
* <pre>{@code
*
* query.where() // add some predicates
* .eq("status", Status.NEW);
*
* if (ids != null && !ids.isEmpty()) {
* query.where().in("customer.id", ids);
* }
*
* query.findList();
*
* }</pre>
*
* <h3>Using inOrEmpty()</h3>
* <pre>{@code
*
* query.where()
* .eq("status", Status.NEW)
* .inOrEmpty("customer.id", ids)
* .findList();
*
* }</pre>
*/
Expression inOrEmpty(String propertyName, Collection<?> values);
/**
* Not In - property has a value in the array of values.
*/
@@ -1003,6 +1003,41 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> in(String propertyName, Collection<?> values);
/**
* In where null or empty values means that no predicate is added to the query.
* <p>
* That is, only add the IN predicate if the values are not null or empty.
* <p>
* Without this we typically need to code an <code>if</code> block to only add
* the IN predicate if the collection is not empty like:
* </p>
*
* <h3>Without inOrEmpty()</h3>
* <pre>{@code
*
* query.where() // add some predicates
* .eq("status", Status.NEW);
*
* if (ids != null && !ids.isEmpty()) {
* query.where().in("customer.id", ids);
* }
*
* query.findList();
*
* }</pre>
*
* <h3>Using inOrEmpty()</h3>
* <pre>{@code
*
* query.where()
* .eq("status", Status.NEW)
* .inOrEmpty("customer.id", ids)
* .findList();
*
* }</pre>
*/
ExpressionList<T> inOrEmpty(String propertyName, Collection<?> values);
/**
* In - using a subQuery.
* <p>
@@ -1247,6 +1282,68 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> raw(String raw);
/**
* Only add the raw expression if the values is not null or empty.
* <p>
* This is a pure convenience expression to make it nicer to deal with the pattern where we use
* raw() expression with a subquery and only want to add the subquery predicate when the collection
* of values is not empty.
* </p>
* <h3>Without inOrEmpty()</h3>
* <pre>{@code
*
* query.where() // add some predicates
* .eq("status", Status.NEW);
*
* // common pattern - we can use rawOrEmpty() instead
* if (orderIds != null && !orderIds.isEmpty()) {
* query.where().raw("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds);
* }
*
* query.findList();
*
* }</pre>
*
* <h3>Using rawOrEmpty()</h3>
* Note that in the example below we use the <code>?1</code> bind parameter to get "parameter expansion"
* for each element in the collection.
*
* <pre>{@code
*
* query.where()
* .eq("status", Status.NEW)
* // only add the expression if orderIds is not empty
* .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds);
* .findList();
*
* }</pre>
*
* <h3>Postgres ANY</h3>
* With Postgres we would often use the SQL <code>ANY</code> expression and array parameter binding
* rather than <code>IN</code>.
*
* <pre>{@code
*
* query.where()
* .eq("status", Status.NEW)
* .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id = any(?))", orderIds);
* .findList();
*
* }</pre>
* <p>
* Note that we need to cast the Postgres array for UUID types like:
* </p>
* <pre>{@code
*
* " ... = any(?::uuid[])"
*
* }</pre>
*
* @param raw The raw expression that is typically a subquery
* @param values The values which is typically a list or set of id values.
*/
ExpressionList<T> rawOrEmpty(String raw, Collection<Object> values);
/**
* Add a match expression.
*
@@ -47,6 +47,11 @@ public class PlatformConfig {
*/
private DbUuid dbUuid = DbUuid.AUTO_VARCHAR;
/**
* Set to true to force InetAddress to map to Varchar (for Postgres rather than INET)
*/
private boolean databaseInetAddressVarchar;
/**
* Modify the default mapping of standard types such as default precision for DECIMAL etc.
*/
@@ -181,6 +186,20 @@ public class PlatformConfig {
this.idType = idType;
}
/**
* Return true if InetAddress should map to varchar column (rather than Postgres INET).
*/
public boolean isDatabaseInetAddressVarchar() {
return databaseInetAddressVarchar;
}
/**
* Set to true to force InetAddress to map to varchar column.
*/
public void setDatabaseInetAddressVarchar(boolean databaseInetAddressVarchar) {
this.databaseInetAddressVarchar = databaseInetAddressVarchar;
}
/**
* Add a custom type mapping.
* <p>
@@ -235,6 +254,7 @@ public class PlatformConfig {
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
databaseInetAddressVarchar = p.getBoolean("databaseInetAddressVarchar", databaseInetAddressVarchar);
DbUuid dbUuid = p.getEnum(DbUuid.class, "dbuuid", null);
if (dbUuid != null) {
@@ -27,6 +27,9 @@ public class DbPlatformTypeMapping {
private static final DbPlatformType BOOLEAN_LOGICAL = new BooleanLogicalType();
private static final DbPlatformType INET_NATIVE = new DbPlatformType("inet", false);
private static final DbPlatformType INET_VARCHAR = new DbPlatformType("varchar", 50);
private static final DbPlatformType UUID_NATIVE = new DbPlatformType("uuid", false);
@SuppressWarnings("unused")
private static final DbPlatformType UUID_PLACEHOLDER = new DbPlatformType("uuidPlaceholder");
@@ -106,6 +109,7 @@ public class DbPlatformTypeMapping {
put(DbType.JSONBLOB, new DbPlatformType("jsonblob"));
put(DbType.JSONVARCHAR, new DbPlatformType("jsonvarchar", 1000));
put(DbType.UUID, UUID_NATIVE);
put(DbType.INET, INET_NATIVE);
} else {
put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
@@ -121,6 +125,7 @@ public class DbPlatformTypeMapping {
put(DbType.JSONVARCHAR, JSON_VARCHAR_PLACEHOLDER);
// default to native UUID and override on platform configure()
put(DbType.UUID, UUID_NATIVE);
put(DbType.INET, INET_VARCHAR);
}
}
@@ -35,6 +35,8 @@ public enum DbType {
ARRAY(Types.ARRAY),
UUID(ExtraDbTypes.UUID),
INET(ExtraDbTypes.INET),
CDIR(ExtraDbTypes.CDIR),
POINT(ExtraDbTypes.POINT),
POLYGON(ExtraDbTypes.POLYGON),
@@ -40,6 +40,9 @@ public interface ExtraDbTypes {
*/
int JSONBlob = 5005;
int INET = 5020;
int CDIR = 5021;
/**
* Geo Point
*/
@@ -60,6 +60,7 @@ public class PostgresPlatform extends DatabasePlatform {
DbPlatformType dbBytea = new DbPlatformType("bytea", false);
dbTypeMap.put(DbType.UUID, new DbPlatformType("uuid", false));
dbTypeMap.put(DbType.INET, new DbPlatformType("inet", false));
dbTypeMap.put(DbType.HSTORE, new DbPlatformType("hstore", false));
dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false));
dbTypeMap.put(DbType.JSONB, new DbPlatformType("jsonb", false));
@@ -455,6 +455,16 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
return new InExpression(propertyName, values, false);
}
/**
* In where null or empty values means that no predicate is added to the query.
* <p>
* That is, only add the IN predicate if the values are not null or empty.
*/
@Override
public Expression inOrEmpty(String propertyName, Collection<?> values) {
return new InExpression(propertyName, values, false, true);
}
/**
* In - property has a value in the array of values.
*/
@@ -912,6 +912,14 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return this;
}
@Override
public ExpressionList<T> inOrEmpty(String propertyName, Collection<?> values) {
if (notEmpty(values)) {
add(expr.in(propertyName, values));
}
return this;
}
@Override
public ExpressionList<T> in(String propertyName, Object... values) {
add(expr.in(propertyName, values));
@@ -1068,6 +1076,18 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return this;
}
@Override
public ExpressionList<T> rawOrEmpty(String raw, Collection<Object> values) {
if (notEmpty(values)) {
add(expr.raw(raw, values));
}
return this;
}
private boolean notEmpty(Collection<?> values) {
return values != null && !values.isEmpty();
}
@Override
public ExpressionList<T> startsWith(String propertyName, String value) {
add(expr.startsWith(propertyName, value));
@@ -17,8 +17,16 @@ import java.util.List;
class InExpression extends AbstractExpression {
private static final String SQL_TRUE = "1=1";
private static final String SQL_FALSE = "1=0";
private final boolean not;
/**
* Set to true when adding "1=1" predicate (due to null or empty sourceValues).
*/
private final boolean empty;
private final Collection<?> sourceValues;
private List<Object> bindValues;
@@ -26,18 +34,27 @@ class InExpression extends AbstractExpression {
private boolean multiValueSupported;
InExpression(String propertyName, Collection<?> sourceValues, boolean not) {
this(propertyName, sourceValues, not, false);
}
InExpression(String propertyName, Collection<?> sourceValues, boolean not, boolean orEmpty) {
super(propertyName);
this.sourceValues = sourceValues;
this.not = not;
this.empty = orEmpty && (sourceValues == null || sourceValues.isEmpty());
}
InExpression(String propertyName, Object[] array, boolean not) {
super(propertyName);
this.sourceValues = Arrays.asList(array);
this.not = not;
this.empty = false;
}
private List<Object> values() {
if (empty || sourceValues == null) {
return Collections.emptyList();
}
List<Object> vals = new ArrayList<>(sourceValues.size());
for (Object sourceValue : sourceValues) {
assert sourceValue != null : "null is not allowed in in-queries";
@@ -48,8 +65,8 @@ class InExpression extends AbstractExpression {
@Override
public boolean naturalKey(NaturalKeyQueryData<?> data) {
// can't use naturalKey cache for NOT IN
if (not) {
// can't use naturalKey cache for NOT IN or when "empty"
if (not || empty) {
return false;
}
List<Object> copy = data.matchIn(propName, bindValues);
@@ -70,11 +87,16 @@ class InExpression extends AbstractExpression {
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
context.writeIn(propName, values().toArray(), not);
if (!empty) {
context.writeIn(propName, values().toArray(), not);
}
}
@Override
public void addBindValues(SpiExpressionRequest request) {
if (empty) {
return;
}
for (Object value : bindValues) {
if (value == null) {
throw new NullPointerException("null values in 'in(...)' queries must be handled separately!");
@@ -108,10 +130,12 @@ class InExpression extends AbstractExpression {
@Override
public void addSql(SpiExpressionRequest request) {
if (empty) {
request.append(SQL_TRUE);
return;
}
if (bindValues.isEmpty()) {
String expr = not ? "1=1" : "1=0";
request.append(expr);
request.append(not ? SQL_TRUE : SQL_FALSE);
return;
}
@@ -142,10 +166,14 @@ class InExpression extends AbstractExpression {
builder.append("In[");
}
builder.append(propName);
builder.append(" ?");
if (!multiValueSupported) {
// query plan specific to the number of parameters in the IN clause
builder.append(bindValues.size());
if (empty) {
builder.append("empty");
} else {
builder.append(" ?");
if (!multiValueSupported) {
// query plan specific to the number of parameters in the IN clause
builder.append(bindValues.size());
}
}
builder.append("]");
}
@@ -672,6 +672,11 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
return exprList.in(propertyName, values);
}
@Override
public ExpressionList<T> inOrEmpty(String propertyName, Collection<?> values) {
return exprList.inOrEmpty(propertyName, values);
}
@Override
public ExpressionList<T> in(String propertyName, Object... values) {
return exprList.in(propertyName, values);
@@ -802,6 +807,11 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
return exprList.raw(raw, values);
}
@Override
public ExpressionList<T> rawOrEmpty(String raw, Collection<Object> values) {
return exprList.rawOrEmpty(raw, values);
}
@Override
public ExpressionList<T> raw(String raw) {
return exprList.raw(raw);
@@ -69,6 +69,7 @@ public final class BatchControl {
* Size of the largest buffer.
*/
private int bufferMax;
private int topCounter;
private Queue earlyQueue;
private Queue lateQueue;
@@ -246,6 +247,7 @@ public final class BatchControl {
pstmtHolder.clear();
beanHoldMap.clear();
maxDepth = 0;
topCounter = 0;
}
private void flushBuffer(boolean resetTop) throws BatchedSqlException {
@@ -319,10 +321,8 @@ public final class BatchControl {
if (maybe != -1) {
beanDepth = maybe;
} else {
// we can't be certain of the relative ordering for this type so
// flush and reset the batch as we are changing the type of our top level
// bean so just keep it simple and flush and reset the top
flushReset();
// additional "top level" bean type ordered by save() order
beanDepth += ++topCounter;
}
}
@@ -9,6 +9,7 @@ import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
import io.ebeaninternal.server.persist.platform.MultiValueBind;
import io.ebeaninternal.server.type.DataBind;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.PostgresHelper;
import io.ebeaninternal.server.type.RsetDataReader;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.TypeManager;
@@ -374,6 +375,11 @@ public class Binder {
b.setObject(data);
break;
case DbPlatformType.INET:
// data is always a String at this point
b.setObject(PostgresHelper.asInet(data.toString()));
break;
case java.sql.Types.OTHER:
b.setObject(data, dataType);
break;
@@ -82,8 +82,8 @@ abstract class AbstractMultiValueBind extends MultiValueBind {
//case NCLOB:
case NCHAR:
case NVARCHAR:
return "varchar";
case ExtraDbTypes.UUID: // Db Native UUID
case ExtraDbTypes.UUID: // Postgres cast to uuid[]
case ExtraDbTypes.INET: // Postgres cast to inet[]
return "varchar";
default:
@@ -14,6 +14,9 @@ public class PostgresMultiValueBind extends AbstractMultiValueBind {
if (dbType == ExtraDbTypes.UUID) {
return (not) ? " != all(?::uuid[])" : " = any(?::uuid[])";
}
if (dbType == ExtraDbTypes.INET) {
return (not) ? " != all(?::inet[])" : " = any(?::inet[])";
}
String arrayType = getArrayType(dbType);
if (arrayType == null) {
return super.getInExpression(not, type, size);
@@ -334,6 +334,24 @@ public final class ConvertInetAddresses {
return ip.getHostAddress();
}
/**
* Return the host address without the square brackets around IPv6 addresses.
*/
public static String toHostAddress(InetAddress ip) {
return ip.getHostAddress();
}
/**
* Parse the IPv4 or IPv6 address without quare brackets around IPv6 addresses.
*/
public static InetAddress fromHost(String hostAddr) {
if (hostAddr.startsWith("[")) {
// IPv6 address
hostAddr = hostAddr.substring(1, hostAddr.length() - 1);
}
return forString(hostAddr);
}
/**
* Returns an InetAddress representing the literal IPv4 or IPv6 host
* portion of a URL, encoded in the format specified by RFC 3986 section 3.2.2.
@@ -14,6 +14,8 @@ import io.ebean.config.ScalarTypeConverter;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.types.Cdir;
import io.ebean.types.Inet;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.api.ExtraTypeFactory;
import io.ebeaninternal.dbmigration.DbOffline;
@@ -37,6 +39,8 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.URI;
import java.net.URL;
@@ -128,7 +132,6 @@ public final class DefaultTypeManager implements TypeManager {
private final ScalarType<?> dateType = new ScalarTypeDate();
private final ScalarType<?> inetAddressType = new ScalarTypeInetAddress();
private final ScalarType<?> urlType = new ScalarTypeURL();
private final ScalarType<?> uriType = new ScalarTypeURI();
private final ScalarType<?> localeType = new ScalarTypeLocale();
@@ -975,8 +978,21 @@ public final class DefaultTypeManager implements TypeManager {
addType(UUID.class, uuidType);
}
if (offlineMigrationGeneration || (postgres && !config.getPlatformConfig().isDatabaseInetAddressVarchar())) {
addInetAddressType(new ScalarTypeInetAddressPostgres());
} else {
addInetAddressType(new ScalarTypeInetAddress());
}
if (offlineMigrationGeneration || postgres) {
addType(Cdir.class, new ScalarTypeCdir.Postgres());
addType(Inet.class, new ScalarTypeInet.Postgres());
} else {
addType(Cdir.class, new ScalarTypeCdir.Varchar());
addType(Inet.class, new ScalarTypeInet.Varchar());
}
addType(File.class, fileType);
addType(InetAddress.class, inetAddressType);
addType(Locale.class, localeType);
addType(Currency.class, currencyType);
addType(TimeZone.class, timeZoneType);
@@ -1063,4 +1079,10 @@ public final class DefaultTypeManager implements TypeManager {
nativeMap.put(Types.TIMESTAMP, timestampType);
}
private void addInetAddressType(ScalarType scalarType) {
addType(InetAddress.class, scalarType);
addType(Inet4Address.class, scalarType);
addType(Inet6Address.class, scalarType);
}
}
@@ -16,6 +16,12 @@ public class PostgresHelper {
*/
public static final String JSONB_TYPE = "jsonb";
public static final String INET_TYPE = "inet";
public static Object asInet(String value) throws SQLException {
return asObject(INET_TYPE, value);
}
/**
* Construct and return Postgres specific PG object.
*/
@@ -0,0 +1,71 @@
package io.ebeaninternal.server.type;
import io.ebean.config.dbplatform.ExtraDbTypes;
import io.ebean.types.Cdir;
import java.sql.SQLException;
import java.sql.Types;
/**
* ScalarType for Cdir to Varchar or Postgres CDIR.
*/
public abstract class ScalarTypeCdir extends ScalarTypeBaseVarchar<Cdir> {
ScalarTypeCdir() {
super(Cdir.class, false, ExtraDbTypes.INET);
}
@Override
public abstract void bind(DataBind b, Cdir value) throws SQLException;
@Override
public Cdir convertFromDbString(String dbValue) {
return parse(dbValue);
}
@Override
public String convertToDbString(Cdir beanValue) {
return formatValue(beanValue);
}
@Override
public String formatValue(Cdir value) {
return value.getAddress();
}
@Override
public Cdir parse(String value) {
return new Cdir(value);
}
/**
* Cdir to Varchar.
*/
public static class Varchar extends ScalarTypeCdir {
@Override
public void bind(DataBind b, Cdir value) throws SQLException {
if (value == null) {
b.setNull(Types.VARCHAR);
} else {
b.setString(convertToDbString(value));
}
}
}
/**
* Cdir to Postgres CDIR.
*/
public static class Postgres extends ScalarTypeCdir {
@Override
public void bind(DataBind b, Cdir value) throws SQLException {
if (value == null) {
b.setNull(Types.OTHER);
} else {
String strValue = convertToDbString(value);
b.setObject(PostgresHelper.asInet(strValue));
}
}
}
}
@@ -0,0 +1,79 @@
package io.ebeaninternal.server.type;
import io.ebean.config.dbplatform.ExtraDbTypes;
import io.ebean.types.Inet;
import java.sql.SQLException;
import java.sql.Types;
/**
* ScalarType for Inet to Varchar or Postgres INET.
*/
public abstract class ScalarTypeInet extends ScalarTypeBaseVarchar<Inet> {
ScalarTypeInet(int jdbcType) {
super(Inet.class, false, jdbcType);
}
@Override
public abstract void bind(DataBind b, Inet value) throws SQLException;
@Override
public Inet convertFromDbString(String dbValue) {
return parse(dbValue);
}
@Override
public String convertToDbString(Inet beanValue) {
return formatValue(beanValue);
}
@Override
public String formatValue(Inet value) {
return value.getAddress();
}
@Override
public Inet parse(String value) {
return new Inet(value);
}
/**
* Inet to Varchar.
*/
public static class Varchar extends ScalarTypeInet {
Varchar() {
super(Types.VARCHAR);
}
@Override
public void bind(DataBind b, Inet value) throws SQLException {
if (value == null) {
b.setNull(Types.VARCHAR);
} else {
b.setString(convertToDbString(value));
}
}
}
/**
* Inet to Postgres INET.
*/
public static class Postgres extends ScalarTypeInet {
Postgres() {
super(ExtraDbTypes.INET);
}
@Override
public void bind(DataBind b, Inet value) throws SQLException {
if (value == null) {
b.setNull(Types.OTHER);
} else {
String strValue = convertToDbString(value);
b.setObject(PostgresHelper.asInet(strValue));
}
}
}
}
@@ -0,0 +1,57 @@
package io.ebeaninternal.server.type;
import io.ebean.config.dbplatform.ExtraDbTypes;
import io.ebean.text.TextException;
import java.net.InetAddress;
import java.sql.SQLException;
import java.sql.Types;
/**
* ScalarType for InetAddress to Postgres INET.
*/
public class ScalarTypeInetAddressPostgres extends ScalarTypeBaseVarchar<InetAddress> {
public ScalarTypeInetAddressPostgres() {
super(InetAddress.class, false, ExtraDbTypes.INET);
}
@Override
public void bind(DataBind b, InetAddress value) throws SQLException {
if (value == null) {
b.setNull(Types.OTHER);
} else {
String strValue = convertToDbString(value);
b.setObject(PostgresHelper.asInet(strValue));
}
}
@Override
public InetAddress convertFromDbString(String dbValue) {
try {
return parse(dbValue);
} catch (IllegalArgumentException e) {
throw new RuntimeException("Error with InetAddresses [" + dbValue + "] " + e);
}
}
@Override
public String convertToDbString(InetAddress beanValue) {
return formatValue(beanValue);
}
@Override
public String formatValue(InetAddress v) {
return ConvertInetAddresses.toHostAddress(v);
}
@Override
public InetAddress parse(String value) {
try {
return ConvertInetAddresses.fromHost(value);
} catch (IllegalArgumentException e) {
throw new TextException("Error with InetAddresses [{}]", value, e);
}
}
}
@@ -11,7 +11,25 @@ import static org.assertj.core.api.StrictAssertions.assertThat;
public class InExpressionTest extends BaseExpressionTest {
@Test
public void queryPlanHash_given_diffPropertyName_should_differentPlanHash() throws Exception {
public void queryPlanHash_given_diffEmpty_should_differentPlanHash() {
List<Integer> emptyValues = values();
InExpression ex1 = new InExpression("foo", emptyValues, false, true);
InExpression ex2 = new InExpression("foo", emptyValues, false);
InExpression ex3 = new InExpression("foo", emptyValues, false, true);
InExpression ex4 = new InExpression("foo", null, false, true);
ex1.prepareExpression(multi());
ex2.prepareExpression(multi());
different(ex1, ex2);
same(ex1, ex3); // same empty
same(ex1, ex4); // same null
}
@Test
public void queryPlanHash_given_diffPropertyName_should_differentPlanHash() {
List<Integer> values = values(42, 92);
@@ -25,7 +43,7 @@ public class InExpressionTest extends BaseExpressionTest {
}
@Test
public void queryPlanHash_given_diffBindCount_should_differentPlanHash() throws Exception {
public void queryPlanHash_given_diffBindCount_should_differentPlanHash() {
List<Integer> values1 = values(42, 92);
List<Integer> values2 = values(42, 92, 82);
@@ -39,7 +57,7 @@ public class InExpressionTest extends BaseExpressionTest {
}
@Test
public void queryPlanHash_given_diffBindCount_withMultiSupport_samePlanHash() throws Exception {
public void queryPlanHash_given_diffBindCount_withMultiSupport_samePlanHash() {
List<Integer> values1 = values(42, 92);
List<Integer> values2 = values(42, 92, 82);
@@ -53,7 +71,7 @@ public class InExpressionTest extends BaseExpressionTest {
}
@Test
public void queryPlanHash_given_diffNotFlag_should_differentPlanHash() throws Exception {
public void queryPlanHash_given_diffNotFlag_should_differentPlanHash() {
List<Integer> values = values(42, 92);
@@ -67,7 +85,7 @@ public class InExpressionTest extends BaseExpressionTest {
}
@Test
public void queryPlanHash_given_sameNotFlag_should_samePlanHash() throws Exception {
public void queryPlanHash_given_sameNotFlag_should_samePlanHash() {
List<Integer> values = values(42, 92);
@@ -3,22 +3,28 @@ package io.ebeaninternal.server.transaction;
import io.ebean.config.ProfilingConfig;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
public class DefaultProfileHandlerTest {
@Test
public void createProfileStream() throws Exception {
DefaultProfileHandler handler = new DefaultProfileHandler(new ProfilingConfig());
@Test
public void createProfileStream() {
ProfilingConfig profilingConfig = new ProfilingConfig();
profilingConfig.setDirectory("target/profiling");
DefaultProfileHandler handler = new DefaultProfileHandler(profilingConfig);
assertNotNull(handler.createProfileStream(12));
assertNull(handler.createProfileStream(0));
}
@Test
public void createProfileStream_when_specificIncludeIds() throws Exception {
public void createProfileStream_when_specificIncludeIds() {
ProfilingConfig config = new ProfilingConfig();
config.setDirectory("target/profiling");
config.setIncludeProfileIds(new int[]{100,101});
DefaultProfileHandler handler = new DefaultProfileHandler(config);
@@ -1,34 +1,46 @@
package io.ebeaninternal.server.type;
import org.junit.Assert;
import org.junit.Test;
import java.net.InetAddress;
import static org.junit.Assert.assertEquals;
public class ConvertInetAddressTest {
@Test
public void forString() {
InetAddress addr = ConvertInetAddresses.forString("128.1.10.23");
Assert.assertNotNull(addr);
Assert.assertEquals("128.1.10.23", addr.getHostAddress());
assertEquals("128.1.10.23", addr.getHostAddress());
String ip6addr = "2001:db8:85a3:0:0:8a2e:370:7334";
InetAddress addr6 = ConvertInetAddresses.forString(ip6addr);
String uriAddr6 = ConvertInetAddresses.toUriString(addr6);
Assert.assertEquals("[" + ip6addr + "]", uriAddr6);
Assert.assertEquals(ip6addr, addr6.getHostAddress());
assertEquals("[" + ip6addr + "]", uriAddr6);
assertEquals(ip6addr, addr6.getHostAddress());
}
@Test
public void ipv6_fromHost_getHostAddress() {
InetAddress addr2 = ConvertInetAddresses.fromHost("2001:4f8:3:ba:2e0:81ff:fe22:d1f1");
assertEquals("2001:4f8:3:ba:2e0:81ff:fe22:d1f1", addr2.getHostAddress());
}
@Test
public void ipv6_fromHost_getHostAddress_2() {
InetAddress addr2 = ConvertInetAddresses.fromHost("2001:db8:85a3:0:0:8a2e:370:7334");
assertEquals("2001:db8:85a3:0:0:8a2e:370:7334", addr2.getHostAddress());
}
@Test
public void toUriString() {
InetAddress addr = ConvertInetAddresses.forString("128.1.10.23");
Assert.assertEquals("128.1.10.23", addr.getHostAddress());
assertEquals("128.1.10.23", addr.getHostAddress());
String uriAddr = ConvertInetAddresses.toUriString(addr);
Assert.assertEquals("128.1.10.23", uriAddr);
assertEquals("128.1.10.23", uriAddr);
}
}
@@ -1,61 +1,153 @@
package org.tests.basic.type;
import io.ebean.Ebean;
import io.ebean.DB;
import io.ebean.TransactionalTestCase;
import org.tests.model.basic.EWithInetAddr;
import org.junit.Assert;
import io.ebean.types.Cdir;
import io.ebean.types.Inet;
import org.junit.Test;
import org.tests.model.basic.EWithInetAddr;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
public class TestInetAddressType extends TransactionalTestCase {
@Test
public void testIp4() throws UnknownHostException {
insertUpdateDeleteFind("120.12.12.56");
insertUpdateDeleteFind("120.12.12.56", "120.12.12.56");
}
@Test
public void testIp6() throws UnknownHostException {
insertUpdateDeleteFind("2001:db8:85a3:0:0:8a2e:370:7334");
if (isPostgres()) {
insertUpdateDeleteFind("2001:db8:85a3:0:0:8a2e:370:7334", "2001:db8:85a3::8a2e:370:7334");
} else {
insertUpdateDeleteFind("2001:db8:85a3:0:0:8a2e:370:7334", "2001:db8:85a3:0:0:8a2e:370:7334");
}
}
private void insertUpdateDeleteFind(String ipAddress) throws UnknownHostException {
@Test
public void test_inet_queryIn() {
List<Inet> addrs = Inet.listOf("120.12.12.56", "120.12.12.57");
DB.find(EWithInetAddr.class)
.where()
.in("inet2", addrs)
.findList();
}
@Test
public void test_inetAdress_queryIn() throws UnknownHostException {
List<InetAddress> addrs = new ArrayList<>();
addrs.add(InetAddress.getByName("120.12.12.56"));
addrs.add(InetAddress.getByName("120.12.12.57"));
DB.find(EWithInetAddr.class)
.where()
.in("inetAddress", addrs)
.findList();
}
@Test
public void test_inet_queryEq() {
DB.find(EWithInetAddr.class)
.where()
.eq("inet2", new Inet("120.12.12.58"))
.findList();
}
@Test
public void test_inet4address_queryEq() throws UnknownHostException {
DB.find(EWithInetAddr.class)
.where()
.eq("inetAddress", InetAddress.getByName("120.12.12.58"))
.findList();
}
@Test
public void test_inet6address_queryEq() throws UnknownHostException {
DB.find(EWithInetAddr.class)
.where()
.eq("inetAddress", InetAddress.getByName("2001:db8:85a3:0:0:8a2e:370:7334"))
.findList();
}
private void insertUpdateDeleteFind(String ipAddress, String expected) throws UnknownHostException {
EWithInetAddr bean1 = new EWithInetAddr();
bean1.setName("jim");
InetAddress address1 = InetAddress.getByName(ipAddress);
bean1.setInetAddress(address1);
bean1.setInet2(new Inet(ipAddress));
bean1.setCdir(new Cdir(ipAddress));
Ebean.save(bean1);
EWithInetAddr bean2 = Ebean.find(EWithInetAddr.class, bean1.getId());
DB.save(bean1);
EWithInetAddr bean2 = DB.find(EWithInetAddr.class, bean1.getId());
InetAddress address2 = bean2.getInetAddress();
Assert.assertNotNull(address2.getHostAddress());
Assert.assertEquals(address1.getHostAddress(), address2.getHostAddress());
assertNotNull(address2.getHostAddress());
assertThat(address1.getHostAddress()).isEqualTo(address2.getHostAddress());
assertThat(bean2.getInet2().getAddress()).isEqualTo(expected);
assertThat(bean2.getCdir().getAddress()).isEqualTo(expected);
bean2.setName("modJim");
bean2.setInetAddress(InetAddress.getByName("120.12.20.80"));
Ebean.save(bean2);
Ebean.delete(bean2);
bean1.setInet2(new Inet("120.12.20.80"));
bean1.setCdir(new Cdir("120.12.20.80"));
DB.save(bean2);
DB.delete(bean2);
}
@Test
public void use_null() throws UnknownHostException {
public void testIp6_ranges() {
insertFindDeleteRange("2001:4f8:3:ba::/64");
insertFindDeleteRange("2001:4f8:3:ba:2e0:81ff:fe22:d1f1/64");
}
private void insertFindDeleteRange(String ipAddressRange) {
EWithInetAddr bean1 = new EWithInetAddr();
bean1.setName("withRange");
bean1.setInet2(new Inet(ipAddressRange));
bean1.setCdir(new Cdir(ipAddressRange));
DB.save(bean1);
EWithInetAddr bean2 = DB.find(EWithInetAddr.class, bean1.getId());
assertNotNull(bean2.getInet2());
assertThat(bean2.getInet2().getAddress()).isEqualTo(ipAddressRange);
assertThat(bean2.getCdir().getAddress()).isEqualTo(ipAddressRange);
DB.delete(bean2);
}
@Test
public void use_null() {
EWithInetAddr bean1 = new EWithInetAddr();
bean1.setName("jim");
Ebean.save(bean1);
DB.save(bean1);
EWithInetAddr bean2 = Ebean.find(EWithInetAddr.class, bean1.getId());
InetAddress address2 = bean2.getInetAddress();
Assert.assertNull(address2);
EWithInetAddr bean2 = DB.find(EWithInetAddr.class, bean1.getId());
assertNull(bean2.getInetAddress());
assertNull(bean2.getInet2());
}
}
@@ -1,5 +1,8 @@
package org.tests.model.basic;
import io.ebean.types.Cdir;
import io.ebean.types.Inet;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@@ -20,6 +23,10 @@ public class EWithInetAddr {
InetAddress inetAddress;
Inet inet2;
Cdir cdir;
public Long getId() {
return id;
}
@@ -52,4 +59,19 @@ public class EWithInetAddr {
this.inetAddress = inetAddress;
}
public Inet getInet2() {
return inet2;
}
public void setInet2(Inet inet2) {
this.inet2 = inet2;
}
public Cdir getCdir() {
return cdir;
}
public void setCdir(Cdir cdir) {
this.cdir = cdir;
}
}
+14 -14
View File
@@ -1,14 +1,14 @@
package org.tests.query;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.DB;
import io.ebean.Query;
import org.junit.Test;
import org.tests.model.basic.CKeyParent;
import org.tests.model.basic.Order;
import org.tests.model.basic.ResetBasicData;
import org.tests.model.basic.Vehicle;
import org.tests.model.basic.VehicleDriver;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
@@ -27,10 +27,10 @@ public class TestSubQuery extends BaseTestCase {
productIds.add(4);
productIds.add(5);
Query<Order> sq = Ebean.createQuery(Order.class).select("id").where()
Query<Order> sq = DB.find(Order.class).select("id").where()
.in("details.product.id", productIds).query();
Ebean.find(Order.class).where().in("id", sq).findList();
DB.find(Order.class).where().in("id", sq).findList();
}
@Test
@@ -41,19 +41,19 @@ public class TestSubQuery extends BaseTestCase {
List<Integer> productIds = new ArrayList<>();
productIds.add(3);
Query<Order> sq = Ebean.createQuery(Order.class).select("id").where()
Query<Order> sq = DB.createQuery(Order.class).select("id").where()
.isIn("details.product.id", productIds).query();
Ebean.find(Order.class).where().isIn("id", sq).findList();
DB.find(Order.class).where().isIn("id", sq).findList();
}
public void testCompositeKey() {
ResetBasicData.reset();
Query<CKeyParent> sq = Ebean.createQuery(CKeyParent.class).select("id.oneKey")
Query<CKeyParent> sq = DB.createQuery(CKeyParent.class).select("id.oneKey")
.setAutoTune(false).where().query();
Query<CKeyParent> pq = Ebean.find(CKeyParent.class).where().in("id.oneKey", sq).query();
Query<CKeyParent> pq = DB.find(CKeyParent.class).where().in("id.oneKey", sq).query();
pq.findList();
@@ -93,10 +93,10 @@ public class TestSubQuery extends BaseTestCase {
public void testInheritance2() {
ResetBasicData.reset();
Query<VehicleDriver> sq = Ebean.createQuery(VehicleDriver.class).select("vehicle")
Query<VehicleDriver> sq = DB.createQuery(VehicleDriver.class).select("vehicle")
.setAutoTune(false).where().query();
Query<Vehicle> pq = Ebean.find(Vehicle.class).where().in("id", sq).query();
Query<Vehicle> pq = DB.find(Vehicle.class).where().in("id", sq).query();
pq.findList();
@@ -118,10 +118,10 @@ public class TestSubQuery extends BaseTestCase {
public void testInheritance3() {
ResetBasicData.reset();
Query<VehicleDriver> sq = Ebean.createQuery(VehicleDriver.class).select("vehicle")
Query<VehicleDriver> sq = DB.createQuery(VehicleDriver.class).select("vehicle")
.setAutoTune(false).where().eq("vehicle.licenseNumber", "abc").query();
Query<Vehicle> pq = Ebean.find(Vehicle.class).where().in("id", sq).query();
Query<Vehicle> pq = DB.find(Vehicle.class).where().in("id", sq).query();
pq.findList();
@@ -139,10 +139,10 @@ public class TestSubQuery extends BaseTestCase {
public void testInheritance4() {
ResetBasicData.reset();
Query<VehicleDriver> sq = Ebean.createQuery(VehicleDriver.class).select("vehicle.id")
Query<VehicleDriver> sq = DB.createQuery(VehicleDriver.class).select("vehicle.id")
.setAutoTune(false).where().query();
Query<Vehicle> pq = Ebean.find(Vehicle.class).where().in("id", sq).query();
Query<Vehicle> pq = DB.find(Vehicle.class).where().in("id", sq).query();
pq.findList();
+111 -6
View File
@@ -1,12 +1,19 @@
package org.tests.query;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.DB;
import io.ebean.Query;
import org.junit.Test;
import org.tests.model.basic.Country;
import org.tests.model.basic.Order;
import org.tests.model.basic.ResetBasicData;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import static org.assertj.core.api.Assertions.assertThat;
public class TestWhereIn extends BaseTestCase {
@@ -15,25 +22,123 @@ public class TestWhereIn extends BaseTestCase {
ResetBasicData.reset();
Query<Country> query = Ebean.find(Country.class)
Query<Country> query = DB.find(Country.class)
.where().in("code", "NZ", "AU")
.query();
query.findList();
platformAssertIn(sqlOf(query), "");
platformAssertIn(sqlOf(query), "where t0.code");
}
@Test
public void testNotInVarchar() {
ResetBasicData.reset();
Query<Country> query = Ebean.find(Country.class)
Query<Country> query = DB.find(Country.class)
.where().notIn("code", "NZ", "SA", "US")
.query();
query.findList();
platformAssertNotIn(sqlOf(query), "");
platformAssertNotIn(sqlOf(query), "where t0.code");
}
@Test
public void testInOrEmpty_expect_noJoinWhenEmpty() {
ResetBasicData.reset();
Query<Order> query = DB.find(Order.class)
.select("id")
.where().inOrEmpty("customer.billingAddress.id", new ArrayList<>()).query();
query.findList();
assertThat(sqlOf(query)).isEqualTo("select t0.id from o_order t0");
}
@Test
public void testInOrEmpty_expect_joinWhenNotEmpty() {
ResetBasicData.reset();
Query<Order> query = DB.find(Order.class)
.select("id")
.where().inOrEmpty("customer.billingAddress.id", Arrays.asList(1)).query();
query.findList();
assertThat(sqlOf(query)).contains("select t0.id from o_order t0 join o_customer t1 on t1.id = t0.kcustomer_id where t1.billing_address_id ");
}
@Test
public void testInOrEmpty_when_null() {
ResetBasicData.reset();
Query<Country> query = DB.find(Country.class)
.where().inOrEmpty("code", null).query();
query.findList();
assertThat(sqlOf(query)).isEqualTo("select t0.code, t0.name from o_country t0");
}
@Test
public void testInOrEmpty_when_empty() {
ResetBasicData.reset();
Query<Country> query = DB.find(Country.class)
.where().inOrEmpty("code", new ArrayList<>()).query();
query.findList();
assertThat(sqlOf(query)).isEqualTo("select t0.code, t0.name from o_country t0");
}
@Test
public void testIn_when_empty() {
ResetBasicData.reset();
Query<Country> query = DB.find(Country.class)
.where().in("code", new ArrayList<>()).query();
query.findList();
assertThat(sqlOf(query)).contains("where 1=0");
}
@Test
public void testIn_when_null() {
ResetBasicData.reset();
Query<Country> query = DB.find(Country.class)
.where().in("code", (Collection)null).query();
query.findList();
assertThat(sqlOf(query)).contains("where 1=0");
}
@Test
public void testNotIn_when_empty() {
ResetBasicData.reset();
Query<Country> query = DB.find(Country.class)
.where().notIn("code", new ArrayList<>()).query();
query.findList();
assertThat(sqlOf(query)).contains("where 1=1");
}
@Test
public void testNotIn_when_null() {
ResetBasicData.reset();
Query<Country> query = DB.find(Country.class)
.where().notIn("code", (Collection)null).query();
query.findList();
assertThat(sqlOf(query)).contains("where 1=1");
}
}
@@ -6,6 +6,7 @@ import io.ebean.Expr;
import io.ebean.Query;
import io.ebean.annotation.ForPlatform;
import io.ebean.annotation.Platform;
import org.ebeantest.LoggedSqlCollector;
import org.junit.Test;
import org.tests.model.basic.Customer;
import org.tests.model.basic.Order;
@@ -13,6 +14,7 @@ import org.tests.model.basic.OrderDetail;
import org.tests.model.basic.ResetBasicData;
import java.sql.Timestamp;
import java.util.Collections;
import java.util.List;
import static java.util.Arrays.asList;
@@ -65,6 +67,54 @@ public class TestWhereRawClause extends BaseTestCase {
assertThat(sqlOf(query)).contains(" t0.id in (select c.id from o_customer c where c.name in (?,?,?))");
}
@Test
public void testRawOrEmpty_when_notEmpty() {
ResetBasicData.reset();
Query<Customer> query = Ebean.find(Customer.class)
.select("name")
.where()
.rawOrEmpty("id in (select c.id from o_customer c where c.name in (?1))", asList("Rob", "Fiona", "Jack"))
.query();
List<Customer> list = query.findList();
assertThat(list).isNotEmpty();
assertThat(sqlOf(query)).contains(" t0.id in (select c.id from o_customer c where c.name in (?,?,?))");
}
@Test
public void testRawOrEmpty_when_null() {
ResetBasicData.reset();
Query<Customer> query = Ebean.find(Customer.class)
.select("name")
.where()
.rawOrEmpty("id in (select c.id from o_customer c where c.name in (?1))", null)
.query();
List<Customer> list = query.findList();
assertThat(list).isNotEmpty();
assertThat(sqlOf(query)).isEqualTo("select t0.id, t0.name from o_customer t0");
}
@Test
public void testRawOrEmpty_when_empty() {
ResetBasicData.reset();
Query<Customer> query = Ebean.find(Customer.class)
.select("name")
.where()
.rawOrEmpty("id in (select c.id from o_customer c where c.name in (?1))", Collections.emptySet())
.query();
List<Customer> list = query.findList();
assertThat(list).isNotEmpty();
assertThat(sqlOf(query)).isEqualTo("select t0.id, t0.name from o_customer t0");
}
@Test
public void testRaw_bindExpansion() {
@@ -94,6 +144,33 @@ public class TestWhereRawClause extends BaseTestCase {
assertThat(list).isNotEmpty();
}
@Test
@ForPlatform(Platform.POSTGRES)
public void testRawOrEmpty_PostgresArray() {
ResetBasicData.reset();
LoggedSqlCollector.start();
Ebean.find(Customer.class)
.select("name").where().rawOrEmpty("name = any(?)", asList("Rob", "Fiona", "Jack"))
.findList();
Ebean.find(Customer.class)
.select("name").where().rawOrEmpty("name = any(?)", asList())
.findList();
Ebean.find(Customer.class)
.select("name").where().rawOrEmpty("name = any(?)", null)
.findList();
List<String> sql = LoggedSqlCollector.stop();
assertThat(sql.get(0)).isEqualTo("select t0.id, t0.name from o_customer t0 where t0.name = any(?); --bind(Array[3]={Rob,Fiona,Jack})");
assertThat(sql.get(1)).isEqualTo("select t0.id, t0.name from o_customer t0; --bind()");
assertThat(sql.get(2)).isEqualTo("select t0.id, t0.name from o_customer t0; --bind()");
}
@Test
public void testRawWithBindParams() {
@@ -1,10 +1,19 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.DB;
import io.ebean.Ebean;
import io.ebean.Transaction;
import io.ebean.annotation.Transactional;
import org.ebeantest.LoggedSqlCollector;
import org.junit.Test;
import org.tests.model.m2m.MnyB;
import org.tests.model.m2m.MnyTopic;
import org.tests.model.m2m.Role;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class TestBatchModelFlush extends BaseTestCase {
@@ -30,4 +39,59 @@ public class TestBatchModelFlush extends BaseTestCase {
// the rest is flushed on commit
new MnyB("TestBatchModelFlush_5").save();
}
@Test
public void multipleTopLevel_expect_singleFlush() {
LoggedSqlCollector.start();
// 2 unrelated "top level" beans being persisted
MnyB m0 = new MnyB("BatchMultipleTop_0");
MnyB m1 = new MnyB("BatchMultipleTop_1");
Role r0 = new Role("Role_0");
Role r1 = new Role("Role_1");
MnyTopic t0 = new MnyTopic("MnyTopic_0");
MnyTopic t1 = new MnyTopic("MnyTopic_1");
try (Transaction transaction = DB.beginTransaction()) {
transaction.setBatchMode(true);
m0.save();
DB.save(r0);
DB.save(t0);
DB.save(t1);
m1.save();
DB.save(r1);
transaction.commit();
}
List<String> sql = LoggedSqlCollector.stop();
// DEBUG io.ebean.SUM - txn[1001] BatchControl flush [MnyB:100 i:2, Role:101 i:2, MnyTopic:102 i:2]
assertThat(sql).hasSize(9);
// first saved to batch - (depth 100)
assertThat(sql.get(0)).contains("insert into mny_b");
assertThat(sql.get(1)).contains(" -- bind(BatchMultipleTop_0");
assertThat(sql.get(2)).contains(" -- bind(BatchMultipleTop_1");
// second saved to batch - (depth 101)
assertThat(sql.get(3)).contains("insert into mt_role");
assertThat(sql.get(4)).contains(" -- bind(");
assertThat(sql.get(5)).contains(" -- bind(");
// third saved to batch - (depth 102)
assertThat(sql.get(6)).contains("insert into mny_topic");
assertThat(sql.get(7)).contains(" -- bind(MnyTopic_0");
assertThat(sql.get(8)).contains(" -- bind(MnyTopic_1");
DB.delete(t0);
DB.delete(t1);
DB.delete(r0);
DB.delete(r1);
DB.delete(m0);
DB.delete(m1);
}
}