mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
43
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbf46bb0ec | ||
|
|
6aa4337b27 | ||
|
|
99d7a4e4b4 | ||
|
|
b7da2cbd97 | ||
|
|
b4ae721998 | ||
|
|
3bb4126e26 | ||
|
|
de439e7695 | ||
|
|
e5ec72df5c | ||
|
|
98a89156bf | ||
|
|
dc65475dbb | ||
|
|
cc64ff5f10 | ||
|
|
ab87174e5b | ||
|
|
a6fdc42934 | ||
|
|
4c16b85e85 | ||
|
|
9e3d6c6a08 | ||
|
|
d567872813 | ||
|
|
7069d3f600 | ||
|
|
b2f8b7c711 | ||
|
|
4092ea307e | ||
|
|
01f64ef9f9 | ||
|
|
f1a48b182e | ||
|
|
8ac5467856 | ||
|
|
758f84f573 | ||
|
|
2073fefc92 | ||
|
|
5b98d8d9c2 | ||
|
|
8e59e72983 | ||
|
|
b56d68dac7 | ||
|
|
e0c3a92b60 | ||
|
|
213562fcf1 | ||
|
|
d3a09b93c0 | ||
|
|
536ea57369 | ||
|
|
ac1dd4cbab | ||
|
|
bc33e05906 | ||
|
|
8ecc407cb0 | ||
|
|
2672dff512 | ||
|
|
74d907bbce | ||
|
|
53aacabce7 | ||
|
|
ab9cdd8f5b | ||
|
|
b3d439ed11 | ||
|
|
d57657c209 | ||
|
|
dd080c5933 | ||
|
|
0be98d7989 | ||
|
|
fca54dbbe3 |
+1
-1
@@ -293,6 +293,6 @@ ebean.tenant.schemaProvider
|
||||
ebean.updateAllPropertiesInBatch
|
||||
ebean.updateChangesOnly
|
||||
ebean.updatesDeleteMissingChildren
|
||||
ebean.useJavaxValidationNotNull
|
||||
ebean.useValidationNotNull
|
||||
ebean.useJtaTransactionManager
|
||||
|
||||
|
||||
+3
-16
@@ -4,18 +4,13 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean api</name>
|
||||
<description>ebean api</description>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
|
||||
<properties>
|
||||
<jackson-core.version>2.11.3</jackson-core.version>
|
||||
<jackson-databind.version>2.11.3</jackson-databind.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!--
|
||||
@@ -74,7 +69,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson-core.version}</version>
|
||||
<version>${jackson.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
@@ -82,7 +77,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson-databind.version}</version>
|
||||
<version>${jackson.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
@@ -102,14 +97,6 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope to read validation annotations Size etc -->
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>1.1.0.Final</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
|
||||
@@ -196,13 +196,6 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Query<T> forUpdate();
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to withLock().
|
||||
* Execute using "for update" with given lock type (currently Postgres only).
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> forUpdate(Query.LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause with No Wait option.
|
||||
* <p>
|
||||
@@ -211,13 +204,6 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Query<T> forUpdateNoWait();
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to withLock().
|
||||
* Execute using "for update nowait" with given lock type (currently Postgres only).
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> forUpdateNoWait(Query.LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause with Skip Locked option.
|
||||
* <p>
|
||||
@@ -226,13 +212,6 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Query<T> forUpdateSkipLocked();
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to withLock().
|
||||
* Execute using "for update skip locked" with given lock type (currently Postgres only).
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> forUpdateSkipLocked(Query.LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute the query including soft deleted rows.
|
||||
*/
|
||||
|
||||
@@ -3,30 +3,13 @@ package io.ebean;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Defines the configuration options for a "query fetch" or a
|
||||
* "lazy loading fetch". This gives you the ability to use multiple smaller
|
||||
* queries to populate an object graph as opposed to a single large query.
|
||||
* <p>
|
||||
* The primary goal is to provide efficient ways of loading complex object
|
||||
* graphs avoiding SQL Cartesian product and issues around populating object
|
||||
* graphs that have multiple *ToMany relationships.
|
||||
* </p>
|
||||
* <p>
|
||||
* It also provides the ability to control the lazy loading queries (batch size,
|
||||
* selected properties and fetches) to avoid N+1 queries etc.
|
||||
* <p>
|
||||
* There can also be cases loading across a single OneToMany where 2 SQL queries
|
||||
* using Ebean FetchConfig.query() can be more efficient than one SQL query.
|
||||
* When the "One" side is wide (lots of columns) and the cardinality difference
|
||||
* is high (a lot of "Many" beans per "One" bean) then this can be more
|
||||
* efficient loaded as 2 SQL queries.
|
||||
* </p>
|
||||
* Defines how a relationship is fetched via either normal SQL join,
|
||||
* a eager secondary query, via lazy loading or via eagerly hitting L2 cache.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
* // Normal fetch join results in a single SQL query
|
||||
* List<Order> list = DB.find(Order.class).fetch("details").findList();
|
||||
*
|
||||
* // Find Orders join details using a single SQL query
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL queries
|
||||
@@ -37,103 +20,13 @@ import java.io.Serializable;
|
||||
* // This will use 2 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* DB.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("details", FetchConfig.ofQuery())
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using 2 "query joins"
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* DB.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("customer", new FetchConfig().queryFirst(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
|
||||
* // query 3) find customer where id in (?,?,?,?,?) // first 5 customers
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using "query joins" and partial objects
|
||||
* </p>
|
||||
* <p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* DB.find(Order.class)
|
||||
* .select("status, shipDate")
|
||||
* .fetch("details", "quantity, price", new FetchConfig().query())
|
||||
* .fetch("details.product", "sku, name")
|
||||
* .fetch("customer", "name", new FetchConfig().queryFirst(5))
|
||||
* .fetch("customer.contacts")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order (status, shipDate)
|
||||
* // query 2) find orderDetail (quantity, price) fetch product (sku, name) where
|
||||
* // order.id in (?,? ...)
|
||||
* // query 3) find customer (name) fetch contacts (*) fetch shippingAddress (*)
|
||||
* // where id in (?,?,?,?,?)
|
||||
*
|
||||
* // Note: the fetch of "details.product" is automatically included into the
|
||||
* // fetch of "details"
|
||||
* //
|
||||
* // Note: the fetch of "customer.contacts" and "customer.shippingAddress"
|
||||
* // are automatically included in the fetch of "customer"
|
||||
* }</pre>
|
||||
* <p>
|
||||
* You can use query() and lazy together on a single join. The query is executed
|
||||
* immediately and the lazy defines the batch size to use for further lazy
|
||||
* loading (if lazy loading is invoked).
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> list =
|
||||
* DB.find(Order.class)
|
||||
* .fetch("customer", new FetchConfig().query(10).lazy(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find customer where id in (?,?,?,?,?,?,?,?,?,?) // first 10 customers
|
||||
* // .. then if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <p>
|
||||
* Example of controlling the lazy loading query:
|
||||
* </p>
|
||||
* <p>
|
||||
* This gives us the ability to optimise the lazy loading query for a given use
|
||||
* case.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> list = DB.find(Order.class)
|
||||
* .fetch("customer","name", new FetchConfig().lazy(5))
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .where().eq("status",Order.Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order where status = Order.Status.NEW
|
||||
* //
|
||||
* // .. if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @author mario
|
||||
* @author rbygrave
|
||||
@@ -142,66 +35,122 @@ public class FetchConfig implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int lazyBatchSize = -1;
|
||||
private static final int JOIN_MODE = 0;
|
||||
private static final int QUERY_MODE = 1;
|
||||
private static final int LAZY_MODE = 2;
|
||||
private static final int CACHE_MODE = 3;
|
||||
|
||||
private int queryBatchSize = -1;
|
||||
|
||||
private boolean queryAll;
|
||||
|
||||
private boolean cache;
|
||||
private int mode;
|
||||
private int batchSize;
|
||||
private int hashCode;
|
||||
|
||||
/**
|
||||
* Construct the fetch configuration object.
|
||||
*/
|
||||
public FetchConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this path should be lazy loaded using the default batch load
|
||||
* size.
|
||||
*/
|
||||
public FetchConfig lazy() {
|
||||
this.lazyBatchSize = 0;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this path should be lazy loaded with a specified batch size.
|
||||
* Deprecated - migrate to one of the static factory methods like {@link FetchConfig#ofQuery()}
|
||||
*
|
||||
* @param lazyBatchSize the batch size for lazy loading
|
||||
* Construct using default JOIN mode.
|
||||
*/
|
||||
public FetchConfig lazy(int lazyBatchSize) {
|
||||
this.lazyBatchSize = lazyBatchSize;
|
||||
this.queryAll = false;
|
||||
@Deprecated
|
||||
public FetchConfig() {
|
||||
//this.mode = JOIN_MODE;
|
||||
this.batchSize = 100;
|
||||
this.hashCode = 1000;
|
||||
}
|
||||
|
||||
private FetchConfig(int mode, int batchSize) {
|
||||
this.mode = mode;
|
||||
this.batchSize = batchSize;
|
||||
this.hashCode = mode + 10 * batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to eagerly fetch the relationship using L2 cache.
|
||||
* <p>
|
||||
* Any cache misses will be loaded by secondary query to the database.
|
||||
*/
|
||||
public static FetchConfig ofCache() {
|
||||
return new FetchConfig(CACHE_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to eagerly fetch the relationship using a secondary query.
|
||||
*/
|
||||
public static FetchConfig ofQuery() {
|
||||
return new FetchConfig(QUERY_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to eagerly fetch the relationship using a secondary with a given batch size.
|
||||
*/
|
||||
public static FetchConfig ofQuery(int batchSize) {
|
||||
return new FetchConfig(QUERY_MODE, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to lazily load the relationship.
|
||||
*/
|
||||
public static FetchConfig ofLazy() {
|
||||
return new FetchConfig(LAZY_MODE, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to lazily load the relationship specifying the batch size.
|
||||
*/
|
||||
public static FetchConfig ofLazy(int batchSize) {
|
||||
return new FetchConfig(LAZY_MODE, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to fetch the relationship using SQL join.
|
||||
*/
|
||||
public static FetchConfig ofDefault() {
|
||||
return new FetchConfig(JOIN_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* We want to migrate away from mutating FetchConfig to a fully immutable FetchConfig.
|
||||
*/
|
||||
private FetchConfig mutate(int mode, int batchSize) {
|
||||
if (batchSize < 1) {
|
||||
throw new IllegalArgumentException("batch size "+batchSize+" must be > 0");
|
||||
}
|
||||
this.mode = mode;
|
||||
this.batchSize = batchSize;
|
||||
this.hashCode = mode + 10 * batchSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to FetchConfig.ofLazy().
|
||||
*/
|
||||
@Deprecated
|
||||
public FetchConfig lazy() {
|
||||
return mutate(LAZY_MODE, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to FetchConfig.ofLazy(batchSize).
|
||||
*/
|
||||
@Deprecated
|
||||
public FetchConfig lazy(int batchSize) {
|
||||
return mutate(LAZY_MODE, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to FetchConfig.ofQuery().
|
||||
*
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
* <p>
|
||||
* This will use the default batch size for separate query which is 100.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
public FetchConfig query() {
|
||||
this.queryBatchSize = 0;
|
||||
this.queryAll = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the beans fetching the beans from the L2 bean cache
|
||||
* and using the DB for beans not in the cache.
|
||||
*/
|
||||
public FetchConfig cache() {
|
||||
this.cache = true;
|
||||
this.queryBatchSize = 0;
|
||||
this.queryAll = true;
|
||||
return this;
|
||||
return mutate(QUERY_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to FetchConfig.ofQuery(batchSize).
|
||||
*
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
* <p>
|
||||
@@ -213,16 +162,16 @@ public class FetchConfig implements Serializable {
|
||||
* is also used.
|
||||
* </p>
|
||||
*
|
||||
* @param queryBatchSize the batch size used to load beans on this path
|
||||
* @param batchSize the batch size used to load beans on this path
|
||||
*/
|
||||
public FetchConfig query(int queryBatchSize) {
|
||||
this.queryBatchSize = queryBatchSize;
|
||||
// queryAll true as long as a lazy batch size has not already been set
|
||||
this.queryAll = (lazyBatchSize == -1);
|
||||
return this;
|
||||
@Deprecated
|
||||
public FetchConfig query(int batchSize) {
|
||||
return mutate(QUERY_MODE, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to FetchConfig.ofQuery(batchSize).
|
||||
*
|
||||
* Eagerly fetch the first batch of beans on this path.
|
||||
* This is similar to {@link #query(int)} but only fetches the first batch.
|
||||
* <p>
|
||||
@@ -230,61 +179,68 @@ public class FetchConfig implements Serializable {
|
||||
* loaded eagerly but instead use lazy loading.
|
||||
* </p>
|
||||
*
|
||||
* @param queryBatchSize the number of parent beans this path is populated for
|
||||
* @param batchSize the number of parent beans this path is populated for
|
||||
*/
|
||||
public FetchConfig queryFirst(int queryBatchSize) {
|
||||
this.queryBatchSize = queryBatchSize;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
@Deprecated
|
||||
public FetchConfig queryFirst(int batchSize) {
|
||||
return query(batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size for lazy loading.
|
||||
* Deprecated - migrate to FetchConfig.ofCache().
|
||||
*
|
||||
* Eagerly fetch the beans fetching the beans from the L2 bean cache
|
||||
* and using the DB for beans not in the cache.
|
||||
*/
|
||||
public int getLazyBatchSize() {
|
||||
return lazyBatchSize;
|
||||
@Deprecated
|
||||
public FetchConfig cache() {
|
||||
return mutate(CACHE_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size for separate query load.
|
||||
* Return the batch size for fetching.
|
||||
*/
|
||||
public int getQueryBatchSize() {
|
||||
return queryBatchSize;
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the query fetch should fetch 'all' rather than just the
|
||||
* 'first' batch.
|
||||
*/
|
||||
public boolean isQueryAll() {
|
||||
return queryAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this uses L2 bean cache.
|
||||
* Return true if the fetch should use the L2 cache.
|
||||
*/
|
||||
public boolean isCache() {
|
||||
return cache;
|
||||
return mode == CACHE_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the fetch should be a eager secondary query.
|
||||
*/
|
||||
public boolean isQuery() {
|
||||
return mode == QUERY_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the fetch should be a lazy query.
|
||||
*/
|
||||
public boolean isLazy() {
|
||||
return mode == LAZY_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the fetch should try to use SQL join.
|
||||
*/
|
||||
public boolean isJoin() {
|
||||
return mode == JOIN_MODE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
FetchConfig that = (FetchConfig) o;
|
||||
if (lazyBatchSize != that.lazyBatchSize) return false;
|
||||
if (queryBatchSize != that.queryBatchSize) return false;
|
||||
if (cache != that.cache) return false;
|
||||
return queryAll == that.queryAll;
|
||||
return (hashCode == ((FetchConfig) o).hashCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = lazyBatchSize;
|
||||
result = 92821 * result + queryBatchSize;
|
||||
result = 92821 * result + (queryAll ? 1 : 0);
|
||||
result = 92821 * result + (cache ? 1 : 0);
|
||||
return result;
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,7 +514,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, fetchProperties, new FetchConfig().query())
|
||||
* fetch(path, fetchProperties, FetchConfig.ofQuery())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -548,7 +548,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, fetchProperties, new FetchConfig().lazy())
|
||||
* fetch(path, fetchProperties, FetchConfig.ofLazy())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -573,7 +573,7 @@ public interface Query<T> {
|
||||
* // fetch customers (their id, name and status)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* .select("name, status")
|
||||
* .fetch("contacts", "firstName,lastName,email", new FetchConfig().lazy(10))
|
||||
* .fetch("contacts", "firstName,lastName,email", FetchConfig.ofLazy(10))
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
@@ -610,7 +610,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, new FetchConfig().query())
|
||||
* fetch(path, FetchConfig.ofQuery())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -639,7 +639,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, new FetchConfig().lazy())
|
||||
* fetch(path, FetchConfig.ofLazy())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -662,7 +662,7 @@ public interface Query<T> {
|
||||
* // fetch customers (their id, name and status)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* // lazy fetch contacts with a batch size of 100
|
||||
* .fetch("contacts", new FetchConfig().lazy(100))
|
||||
* .fetch("contacts", FetchConfig.ofLazy(100))
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
@@ -844,7 +844,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* DB.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .fetch("contacts", FetchConfig.ofQuery(2))
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .setMaxRows(2000)
|
||||
@@ -1673,12 +1673,6 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> forUpdate();
|
||||
|
||||
/**
|
||||
* Execute using "for update" with given lock type (currently Postgres only).
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> forUpdate(LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause with "no wait" option.
|
||||
* <p>
|
||||
@@ -1688,12 +1682,6 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> forUpdateNoWait();
|
||||
|
||||
/**
|
||||
* Execute using "for update nowait" with given lock type (currently Postgres only).
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> forUpdateNoWait(LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause with "skip locked" option.
|
||||
* <p>
|
||||
@@ -1703,12 +1691,6 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> forUpdateSkipLocked();
|
||||
|
||||
/**
|
||||
* Execute using "for update skip locked" with given lock type (currently Postgres only).
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> forUpdateSkipLocked(LockType lockType);
|
||||
|
||||
/**
|
||||
* Return true if this query has forUpdate set.
|
||||
*/
|
||||
|
||||
@@ -107,7 +107,7 @@ package io.ebean;
|
||||
*
|
||||
* List<OrderAggregate> orders = DB.find(OrderAggregate.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .fetch("order", "status,orderDate", new FetchConfig().query())
|
||||
* .fetch("order", "status,orderDate", FetchConfig.ofQuery())
|
||||
* .fetch("order.customer", "name")
|
||||
* .where().gt("order.id", 0)
|
||||
* .having().gt("totalAmount", 20)
|
||||
|
||||
@@ -931,10 +931,14 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* OneToMany and ManyToMany only set loaded state.
|
||||
*/
|
||||
public void preSetterMany(boolean interceptField, int propertyIndex, Object oldValue, Object newValue) {
|
||||
if (readOnly) {
|
||||
throw new IllegalStateException("This bean is readOnly");
|
||||
if (state == STATE_NEW) {
|
||||
setLoadedProperty(propertyIndex);
|
||||
} else {
|
||||
if (readOnly) {
|
||||
throw new IllegalStateException("This bean is readOnly");
|
||||
}
|
||||
setChangedProperty(propertyIndex);
|
||||
}
|
||||
setLoadedProperty(propertyIndex);
|
||||
}
|
||||
|
||||
private void setChangedPropertyValue(int propertyIndex, boolean setDirtyState, Object origValue) {
|
||||
|
||||
@@ -40,6 +40,13 @@ public class ClassLoadConfig {
|
||||
return isPresent("javax.validation.constraints.NotNull");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if jakarta validation annotations like Size and NotNull are present.
|
||||
*/
|
||||
public boolean isJakartaValidationAnnotationsPresent() {
|
||||
return isPresent("jakarta.validation.constraints.NotNull");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if javax PostConstruct annotation is present (maybe not in java9).
|
||||
* If not we don't support PostConstruct lifecycle events.
|
||||
|
||||
@@ -489,7 +489,7 @@ public class DatabaseConfig {
|
||||
* Should the javax.validation.constraints.NotNull enforce a notNull column in DB.
|
||||
* If set to false, use io.ebean.annotation.NotNull or Column(nullable=true).
|
||||
*/
|
||||
private boolean useJavaxValidationNotNull = true;
|
||||
private boolean useValidationNotNull = true;
|
||||
|
||||
/**
|
||||
* Generally we want to perform L2 cache notification in the background and not impact
|
||||
@@ -2809,7 +2809,7 @@ public class DatabaseConfig {
|
||||
enabledL2Regions = p.get("enabledL2Regions", enabledL2Regions);
|
||||
notifyL2CacheInForeground = p.getBoolean("notifyL2CacheInForeground", notifyL2CacheInForeground);
|
||||
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager);
|
||||
useJavaxValidationNotNull = p.getBoolean("useJavaxValidationNotNull", useJavaxValidationNotNull);
|
||||
useValidationNotNull = p.getBoolean("useValidationNotNull", useValidationNotNull);
|
||||
autoReadOnlyDataSource = p.getBoolean("autoReadOnlyDataSource", autoReadOnlyDataSource);
|
||||
idGeneratorAutomatic = p.getBoolean("idGeneratorAutomatic", idGeneratorAutomatic);
|
||||
|
||||
@@ -3056,20 +3056,21 @@ public class DatabaseConfig {
|
||||
/**
|
||||
* Returns if we use javax.validation.constraints.NotNull
|
||||
*/
|
||||
public boolean isUseJavaxValidationNotNull() {
|
||||
return useJavaxValidationNotNull;
|
||||
public boolean isUseValidationNotNull() {
|
||||
return useValidationNotNull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls if Ebean should ignore <code>&x64;javax.validation.contstraints.NotNull</code>
|
||||
* Controls if Ebean should ignore <code>&x64;javax.validation.contstraints.NotNull</code> or
|
||||
* <code>&x64;jakarta.validation.contstraints.NotNull</code>
|
||||
* with respect to generating a <code>NOT NULL</code> column.
|
||||
* <p>
|
||||
* Normally when Ebean sees javax NotNull annotation it means that column is defined as NOT NULL.
|
||||
* Set this to <code>false</code> and the javax NotNull annotation is effectively ignored (and
|
||||
* we instead use Ebean's own NotNull annotation or JPA Column(nullable=false) annotation.
|
||||
*/
|
||||
public void setUseJavaxValidationNotNull(boolean useJavaxValidationNotNull) {
|
||||
this.useJavaxValidationNotNull = useJavaxValidationNotNull;
|
||||
public void setUseValidationNotNull(boolean useValidationNotNull) {
|
||||
this.useValidationNotNull = useValidationNotNull;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</parent>
|
||||
<!-- <parent>-->
|
||||
<!-- <groupId>org.avaje</groupId>-->
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-parent-12.6.6</tag>
|
||||
<tag>ebean-parent-12.7.1</tag>
|
||||
</scm>
|
||||
|
||||
<name>ebean autotune</name>
|
||||
@@ -26,7 +26,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
<plugin>
|
||||
<groupId>io.repaint.maven</groupId>
|
||||
<artifactId>tiles-maven-plugin</artifactId>
|
||||
<version>2.18</version>
|
||||
<version>2.19</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<tiles>
|
||||
|
||||
+6
-9
@@ -11,12 +11,9 @@ import org.tests.model.basic.Order;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
//import org.tests.model.basic.ResetBasicData;
|
||||
|
||||
public class ProfileOriginTest extends BaseTestCase {
|
||||
|
||||
|
||||
private BeanDescriptor<Order> desc = getBeanDescriptor(Order.class);
|
||||
private final BeanDescriptor<Order> desc = getBeanDescriptor(Order.class);
|
||||
|
||||
@Test
|
||||
public void buildDetail() {
|
||||
@@ -30,7 +27,7 @@ public class ProfileOriginTest extends BaseTestCase {
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
|
||||
assertThat(detail.asString().trim()).isEqualTo("fetch customer (name)");
|
||||
assertThat(detail.asStringDebug().trim()).isEqualTo("fetch customer (name)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -49,7 +46,7 @@ public class ProfileOriginTest extends BaseTestCase {
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
|
||||
assertThat(detail.asString()).isEqualTo("select (orderDate) fetch customer (name)");
|
||||
assertThat(detail.asStringDebug()).isEqualTo("select (orderDate) fetch customer (name)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -67,7 +64,7 @@ public class ProfileOriginTest extends BaseTestCase {
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
|
||||
assertThat(detail.asString().trim()).isEqualTo("select (orderDate,customer)");
|
||||
assertThat(detail.asStringDebug().trim()).isEqualTo("select (orderDate,customer)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -90,7 +87,7 @@ public class ProfileOriginTest extends BaseTestCase {
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
|
||||
assertThat(detail.asString()).isEqualTo("select (orderDate) fetch customer (billingAddress)");
|
||||
assertThat(detail.asStringDebug()).isEqualTo("select (orderDate) fetch customer (billingAddress)");
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +116,7 @@ public class ProfileOriginTest extends BaseTestCase {
|
||||
po.collectUsageInfo(c);
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
assertThat(detail.asString()).isEqualTo("fetch customer (name,note) fetch customer.billingAddress (line1)");
|
||||
assertThat(detail.asStringDebug()).isEqualTo("fetch customer (name,note) fetch customer.billingAddress (line1)");
|
||||
}
|
||||
|
||||
private NodeUsageCollector node(String path) {
|
||||
|
||||
+15
-15
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean bom</name>
|
||||
@@ -81,88 +81,88 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-xml</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-autotune</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>kotlin-querybean-generator</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-postgis</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-redis</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,30 +4,25 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<name>ebean core type</name>
|
||||
<description>ebean scalar types api</description>
|
||||
|
||||
<properties>
|
||||
<jackson-core.version>2.11.3</jackson-core.version>
|
||||
<jackson-databind.version>2.11.3</jackson-databind.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson-core.version}</version>
|
||||
<version>${jackson.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
|
||||
+13
-12
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core</artifactId>
|
||||
@@ -15,14 +15,9 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-parent-12.6.6</tag>
|
||||
<tag>ebean-parent-12.7.1</tag>
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<jackson-core.version>2.11.3</jackson-core.version>
|
||||
<jackson-databind.version>2.11.3</jackson-databind.version>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<!-- Note: to use this profile, you need to download manually the db2jcc4 driver.
|
||||
@@ -92,19 +87,19 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>12.6.6</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -138,6 +133,12 @@
|
||||
<version>1.1.0.Final</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
@@ -157,14 +158,14 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson-core.version}</version>
|
||||
<version>${jackson.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson-databind.version}</version>
|
||||
<version>${jackson.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import io.ebeaninternal.server.deploy.TableJoin;
|
||||
import io.ebeaninternal.server.query.CancelableQuery;
|
||||
import io.ebeaninternal.server.querydefn.NaturalKeyBindParam;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
import io.ebeaninternal.server.querydefn.OrmUpdateProperties;
|
||||
import io.ebeaninternal.server.rawsql.SpiRawSql;
|
||||
|
||||
@@ -30,7 +31,7 @@ import java.util.Set;
|
||||
/**
|
||||
* Object Relational query - Internal extension to Query object.
|
||||
*/
|
||||
public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
|
||||
public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCodes {
|
||||
|
||||
enum Mode {
|
||||
NORMAL(false), LAZYLOAD_MANY(false), LAZYLOAD_BEAN(true), REFRESH_BEAN(true);
|
||||
@@ -289,6 +290,16 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
|
||||
*/
|
||||
boolean selectAllForLazyLoadProperty();
|
||||
|
||||
/**
|
||||
* Set the select properties.
|
||||
*/
|
||||
void selectProperties(OrmQueryProperties other);
|
||||
|
||||
/**
|
||||
* Set the fetch properties for the given path.
|
||||
*/
|
||||
void fetchProperties(String path, OrmQueryProperties other);
|
||||
|
||||
/**
|
||||
* Set the on a secondary query given the label, relativePath and profile location of the parent query.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.FetchConfig;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Query select and fetch properties (that avoids parsing).
|
||||
*/
|
||||
public interface SpiQueryFetch {
|
||||
|
||||
/**
|
||||
* Specify the select properties.
|
||||
*/
|
||||
void selectProperties(Set<String> properties);
|
||||
|
||||
/**
|
||||
* Specify the fetch properties for the given path.
|
||||
*/
|
||||
void fetchProperties(String name, Set<String> properties, FetchConfig config);
|
||||
|
||||
}
|
||||
@@ -131,19 +131,10 @@ public class DatabasePlatformFactory {
|
||||
* Use JDBC DatabaseMetaData to determine the platform.
|
||||
*/
|
||||
private DatabasePlatform byDataSource(DataSource dataSource) {
|
||||
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
DatabaseMetaData metaData = connection.getMetaData();
|
||||
|
||||
return byDatabaseMeta(metaData, connection);
|
||||
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
return byDatabaseMeta(connection.getMetaData(), connection);
|
||||
} catch (SQLException ex) {
|
||||
throw new PersistenceException(ex);
|
||||
|
||||
} finally {
|
||||
JdbcClose.close(connection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +148,7 @@ public class DatabasePlatformFactory {
|
||||
final int minorVersion = metaData.getDatabaseMinorVersion();
|
||||
|
||||
if (dbProductName.contains("oracle")) {
|
||||
return new OraclePlatform();
|
||||
return oracleVersion(majorVersion);
|
||||
} else if (dbProductName.contains("microsoft")) {
|
||||
throw new IllegalArgumentException("For SqlServer please explicitly choose either sqlserver16 or sqlserver17 as the platform via DatabaseConfig.setDatabasePlatformName. Refer to issue #1340 for more details");
|
||||
} else if (dbProductName.contains("h2")) {
|
||||
@@ -188,6 +179,10 @@ public class DatabasePlatformFactory {
|
||||
return new DatabasePlatform();
|
||||
}
|
||||
|
||||
private DatabasePlatform oracleVersion(int majorVersion) {
|
||||
return majorVersion < 12 ? new Oracle11Platform() : new OraclePlatform();
|
||||
}
|
||||
|
||||
private DatabasePlatform mysqlVersion(int majorVersion, int minorVersion) {
|
||||
if (majorVersion <= 5 && minorVersion <= 5) {
|
||||
return new MySql55Platform();
|
||||
|
||||
@@ -34,7 +34,6 @@ import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Version;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
@@ -1140,15 +1139,6 @@ public class DeployBeanProperty {
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<Size> getMetaAnnotationSize() {
|
||||
final List<Size> size = getMetaAnnotations(Size.class);
|
||||
final List<Size.List> lists = getMetaAnnotations(Size.List.class);
|
||||
for (Size.List list : lists) {
|
||||
Collections.addAll(size, list.value());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public Formula getMetaAnnotationFormula(Platform platform) {
|
||||
Formula fallback = null;
|
||||
for (Annotation ann : metaAnnotations) {
|
||||
|
||||
+5
@@ -176,4 +176,9 @@ public abstract class DeployBeanPropertyAssoc<T> extends DeployBeanProperty {
|
||||
public void setFetchPreference(int fetchPreference) {
|
||||
this.fetchPreference = fetchPreference;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setTargetType(Class<?> targetType) {
|
||||
this.targetType = (Class<T>)targetType;
|
||||
}
|
||||
}
|
||||
|
||||
-13
@@ -65,19 +65,6 @@ public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
|
||||
this.manyType = manyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* When generics is not used for manyType you can specify via annotations.
|
||||
* <p>
|
||||
* Really only expect this for Scala due to a Scala compiler bug at the moment.
|
||||
* Otherwise I'd probably not bother support this.
|
||||
* </p>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setTargetType(Class<?> cls) {
|
||||
this.targetType = (Class<T>) cls;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the many type.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package io.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import io.ebean.config.BeanNotRegisteredException;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import io.ebeaninternal.server.deploy.BeanTable;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
|
||||
abstract class AnnotationAssoc extends AnnotationParser {
|
||||
|
||||
final BeanDescriptorManager factory;
|
||||
|
||||
AnnotationAssoc(DeployBeanInfo<?> info, ReadAnnotationConfig readConfig, BeanDescriptorManager factory) {
|
||||
super(info, readConfig);
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
void setTargetType(Class<?> targetType, DeployBeanPropertyAssoc<?> prop) {
|
||||
if (!targetType.equals(void.class)) {
|
||||
prop.setTargetType(targetType);
|
||||
}
|
||||
}
|
||||
|
||||
void setBeanTable(DeployBeanPropertyAssoc<?> prop) {
|
||||
BeanTable assoc = getBeanTable(prop);
|
||||
if (assoc == null) {
|
||||
throw new BeanNotRegisteredException(errorMsgMissingBeanTable(prop.getTargetType(), prop.getFullBeanName()));
|
||||
}
|
||||
prop.setBeanTable(assoc);
|
||||
}
|
||||
|
||||
BeanTable getBeanTable(DeployBeanPropertyAssoc<?> prop) {
|
||||
return factory.getBeanTable(prop.getTargetType());
|
||||
}
|
||||
|
||||
private String errorMsgMissingBeanTable(Class<?> type, String from) {
|
||||
return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered? See https://ebean.io/docs/trouble-shooting#not-registered";
|
||||
}
|
||||
|
||||
}
|
||||
+10
-32
@@ -5,7 +5,6 @@ import io.ebean.annotation.FetchPreference;
|
||||
import io.ebean.annotation.HistoryExclude;
|
||||
import io.ebean.annotation.Where;
|
||||
import io.ebean.bean.BeanCollection.ModifyListenMode;
|
||||
import io.ebean.config.BeanNotRegisteredException;
|
||||
import io.ebean.config.NamingConvention;
|
||||
import io.ebean.config.TableName;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
@@ -44,16 +43,10 @@ import static io.ebean.util.StringHelper.isNull;
|
||||
/**
|
||||
* Read the deployment annotation for Assoc Many beans.
|
||||
*/
|
||||
class AnnotationAssocManys extends AnnotationParser {
|
||||
class AnnotationAssocManys extends AnnotationAssoc {
|
||||
|
||||
private final BeanDescriptorManager factory;
|
||||
|
||||
/**
|
||||
* Create with the DeployInfo.
|
||||
*/
|
||||
AnnotationAssocManys(DeployBeanInfo<?> info, ReadAnnotationConfig readConfig, BeanDescriptorManager factory) {
|
||||
super(info, readConfig);
|
||||
this.factory = factory;
|
||||
super(info, readConfig, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,15 +139,15 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
JoinTable joinTable = get(prop, JoinTable.class);
|
||||
if (joinTable != null) {
|
||||
if (prop.isManyToMany()) {
|
||||
// expected this
|
||||
readJoinTable(joinTable, prop);
|
||||
|
||||
} else {
|
||||
// OneToMany with @JoinTable
|
||||
prop.setO2mJoinTable();
|
||||
readJoinTable(joinTable, prop);
|
||||
manyToManyDefaultJoins(prop);
|
||||
}
|
||||
} else if (prop.isManyToMany()) {
|
||||
checkSelfManyToMany(prop);
|
||||
}
|
||||
|
||||
if (prop.getMappedBy() != null) {
|
||||
@@ -187,6 +180,12 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkSelfManyToMany(DeployBeanPropertyAssocMany<?> prop) {
|
||||
if (prop.getTargetType().equals(descriptor.getBeanType())) {
|
||||
throw new IllegalStateException("@ManyToMany mapping for " + prop.getFullBeanName() + " requires explicit @JoinTable with joinColumns & inverseJoinColumns. Refer issue #2157");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void readElementCollection(DeployBeanPropertyAssocMany<?> prop, ElementCollection elementCollection) {
|
||||
|
||||
@@ -435,13 +434,7 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
prop.setInverseJoin(inverseDest);
|
||||
}
|
||||
|
||||
|
||||
private String errorMsgMissingBeanTable(Class<?> type, String from) {
|
||||
return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered? See https://ebean.io/docs/trouble-shooting#not-registered";
|
||||
}
|
||||
|
||||
private void readToMany(ManyToMany propAnn, DeployBeanPropertyAssocMany<?> manyProp) {
|
||||
|
||||
manyProp.setMappedBy(propAnn.mappedBy());
|
||||
manyProp.setFetchType(propAnn.fetch());
|
||||
setCascadeTypes(propAnn.cascade(), manyProp.getCascadeInfo());
|
||||
@@ -453,7 +446,6 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
}
|
||||
|
||||
private void readToOne(OneToMany propAnn, DeployBeanPropertyAssocMany<?> manyProp) {
|
||||
|
||||
manyProp.setMappedBy(propAnn.mappedBy());
|
||||
manyProp.setFetchType(propAnn.fetch());
|
||||
setCascadeTypes(propAnn.cascade(), manyProp.getCascadeInfo());
|
||||
@@ -462,20 +454,6 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
manyProp.getTableJoin().setType(SqlJoinType.OUTER);
|
||||
}
|
||||
|
||||
private void setTargetType(Class<?> targetType, DeployBeanPropertyAssocMany<?> prop) {
|
||||
if (!targetType.equals(void.class)) {
|
||||
prop.setTargetType(targetType);
|
||||
}
|
||||
}
|
||||
|
||||
private void setBeanTable(DeployBeanPropertyAssocMany<?> manyProp) {
|
||||
BeanTable assoc = factory.getBeanTable(manyProp.getTargetType());
|
||||
if (assoc == null) {
|
||||
throw new BeanNotRegisteredException(errorMsgMissingBeanTable(manyProp.getTargetType(), manyProp.getFullBeanName()));
|
||||
}
|
||||
manyProp.setBeanTable(assoc);
|
||||
}
|
||||
|
||||
private String getM2MJoinTableName(BeanTable lhsTable, BeanTable rhsTable) {
|
||||
|
||||
TableName lhs = new TableName(lhsTable.getBaseTable());
|
||||
|
||||
+12
-34
@@ -4,13 +4,11 @@ import io.ebean.annotation.DbForeignKey;
|
||||
import io.ebean.annotation.FetchPreference;
|
||||
import io.ebean.annotation.TenantId;
|
||||
import io.ebean.annotation.Where;
|
||||
import io.ebean.config.BeanNotRegisteredException;
|
||||
import io.ebean.config.NamingConvention;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import io.ebeaninternal.server.deploy.BeanTable;
|
||||
import io.ebeaninternal.server.deploy.PropertyForeignKey;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
@@ -28,23 +26,19 @@ import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.PrimaryKeyJoinColumn;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Read the deployment annotations for Associated One beans.
|
||||
*/
|
||||
public class AnnotationAssocOnes extends AnnotationParser {
|
||||
public class AnnotationAssocOnes extends AnnotationAssoc {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AnnotationAssocOnes.class);
|
||||
|
||||
private final BeanDescriptorManager factory;
|
||||
|
||||
/**
|
||||
* Create with the deploy Info.
|
||||
*/
|
||||
AnnotationAssocOnes(DeployBeanInfo<?> info, ReadAnnotationConfig readConfig, BeanDescriptorManager factory) {
|
||||
super(info, readConfig);
|
||||
this.factory = factory;
|
||||
super(info, readConfig, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,13 +114,10 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
if (nonNull != null) {
|
||||
prop.setNullable(false);
|
||||
}
|
||||
if (validationAnnotations) {
|
||||
NotNull notNull = get(prop, NotNull.class);
|
||||
if (notNull != null && isEbeanValidationGroups(notNull.groups())) {
|
||||
prop.setNullable(false);
|
||||
// overrides optional attribute of ManyToOne etc
|
||||
prop.getTableJoin().setType(SqlJoinType.INNER);
|
||||
}
|
||||
if (readConfig.isValidationNotNull(prop)) {
|
||||
// overrides optional attribute of ManyToOne etc
|
||||
prop.setNullable(false);
|
||||
prop.getTableJoin().setType(SqlJoinType.INNER);
|
||||
}
|
||||
|
||||
// check for manually defined joins
|
||||
@@ -191,25 +182,11 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
}
|
||||
}
|
||||
|
||||
private String errorMsgMissingBeanTable(Class<?> type, String from) {
|
||||
return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered? Does it have the @Entity annotation? See https://ebean.io/docs/trouble-shooting#not-registered";
|
||||
}
|
||||
|
||||
private BeanTable beanTable(DeployBeanPropertyAssoc<?> prop) {
|
||||
BeanTable assoc = factory.getBeanTable(prop.getPropertyType());
|
||||
if (assoc == null) {
|
||||
throw new BeanNotRegisteredException(errorMsgMissingBeanTable(prop.getPropertyType(), prop.getFullBeanName()));
|
||||
}
|
||||
return assoc;
|
||||
}
|
||||
|
||||
private void readManyToOne(ManyToOne propAnn, DeployBeanProperty prop) {
|
||||
|
||||
DeployBeanPropertyAssocOne<?> beanProp = (DeployBeanPropertyAssocOne<?>) prop;
|
||||
private void readManyToOne(ManyToOne propAnn, DeployBeanPropertyAssocOne<?> beanProp) {
|
||||
|
||||
setCascadeTypes(propAnn.cascade(), beanProp.getCascadeInfo());
|
||||
|
||||
beanProp.setBeanTable(beanTable(beanProp));
|
||||
setTargetType(propAnn.targetEntity(), beanProp);
|
||||
setBeanTable(beanProp);
|
||||
beanProp.setDbInsertable(true);
|
||||
beanProp.setDbUpdateable(true);
|
||||
beanProp.setNullable(propAnn.optional());
|
||||
@@ -232,7 +209,8 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
}
|
||||
|
||||
setCascadeTypes(propAnn.cascade(), prop.getCascadeInfo());
|
||||
prop.setBeanTable(beanTable(prop));
|
||||
setTargetType(propAnn.targetEntity(), prop);
|
||||
setBeanTable(prop);
|
||||
}
|
||||
|
||||
private boolean readOrphanRemoval(OneToOne property) {
|
||||
@@ -261,7 +239,7 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
BeanTable baseBeanTable = factory.getBeanTable(info.getDescriptor().getBeanType());
|
||||
|
||||
String localPrimaryKey = baseBeanTable.getIdColumn();
|
||||
String foreignColumn = beanTable(prop).getIdColumn();
|
||||
String foreignColumn = getBeanTable(prop).getIdColumn();
|
||||
|
||||
prop.getTableJoin().addJoinColumn(new DeployTableJoinColumn(localPrimaryKey, foreignColumn, false, false));
|
||||
}
|
||||
|
||||
+4
-16
@@ -69,8 +69,6 @@ import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.Transient;
|
||||
import javax.persistence.Version;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.sql.Types;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@@ -258,29 +256,19 @@ public class AnnotationFields extends AnnotationParser {
|
||||
}
|
||||
|
||||
private void initValidation(DeployBeanProperty prop) {
|
||||
NotNull notNull = get(prop, NotNull.class);
|
||||
if (notNull != null && isEbeanValidationGroups(notNull.groups())) {
|
||||
// Not null on all validation groups so enable
|
||||
// DDL generation of Not Null Constraint
|
||||
if (readConfig.isValidationNotNull(prop)) {
|
||||
prop.setNullable(false);
|
||||
}
|
||||
|
||||
if (!prop.isLob()) {
|
||||
// take the max size of all @Size annotations
|
||||
int maxSize = -1;
|
||||
for (Size size : prop.getMetaAnnotationSize()) {
|
||||
if (size.max() < Integer.MAX_VALUE) {
|
||||
maxSize = Math.max(maxSize, size.max());
|
||||
}
|
||||
}
|
||||
if (maxSize != -1) {
|
||||
int maxSize = readConfig.maxValidationSize(prop);
|
||||
if (maxSize > 0) {
|
||||
prop.setDbLength(maxSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initTenantId(DeployBeanProperty prop) {
|
||||
if (validationAnnotations) {
|
||||
if (readConfig.checkValidationAnnotations()) {
|
||||
initValidation(prop);
|
||||
}
|
||||
if (has(prop, TenantId.class)) {
|
||||
|
||||
@@ -9,7 +9,6 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import javax.persistence.AttributeOverride;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.validation.groups.Default;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -26,14 +25,11 @@ public abstract class AnnotationParser extends AnnotationBase {
|
||||
|
||||
final Class<?> beanType;
|
||||
|
||||
final boolean validationAnnotations;
|
||||
|
||||
final ReadAnnotationConfig readConfig;
|
||||
|
||||
AnnotationParser(DeployBeanInfo<?> info, ReadAnnotationConfig readConfig) {
|
||||
super(info.getUtil());
|
||||
this.readConfig = readConfig;
|
||||
this.validationAnnotations = readConfig.isJavaxValidationAnnotations();
|
||||
this.info = info;
|
||||
this.beanType = info.getDescriptor().getBeanType();
|
||||
this.descriptor = info.getDescriptor();
|
||||
@@ -127,17 +123,6 @@ public abstract class AnnotationParser extends AnnotationBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the validation groups are {@link Default} (respectively empty)
|
||||
* can be applied to DDL generation.
|
||||
*/
|
||||
boolean isEbeanValidationGroups(Class<?>[] groups) {
|
||||
if (!util.isUseJavaxValidationNotNull()) {
|
||||
return false;
|
||||
}
|
||||
return groups.length == 0 || groups.length == 1 && Default.class.isAssignableFrom(groups[0]);
|
||||
}
|
||||
|
||||
String[] convertColumnNames(String[] columnNames) {
|
||||
for (int i = 0; i < columnNames.length; i++) {
|
||||
columnNames[i] = databasePlatform.convertQuotedIdentifiers(columnNames[i]);
|
||||
|
||||
-8
@@ -145,14 +145,6 @@ public class DeployCreateProperties {
|
||||
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field) {
|
||||
|
||||
Class<?> propertyType = field.getType();
|
||||
|
||||
ManyToOne manyToOne = AnnotationUtil.get(field, ManyToOne.class);
|
||||
if (manyToOne != null) {
|
||||
Class<?> tt = manyToOne.targetEntity();
|
||||
if (!tt.equals(void.class)) {
|
||||
propertyType = tt;
|
||||
}
|
||||
}
|
||||
if (isSpecialScalarType(field)) {
|
||||
return new DeployBeanProperty(desc, propertyType, field.getGenericType());
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public class DeployUtil {
|
||||
|
||||
private final Encryptor bytesEncryptor;
|
||||
|
||||
private final boolean useJavaxValidationNotNull;
|
||||
private final boolean useValidationNotNull;
|
||||
|
||||
public DeployUtil(TypeManager typeMgr, DatabaseConfig config) {
|
||||
this.typeManager = typeMgr;
|
||||
@@ -67,7 +67,7 @@ public class DeployUtil {
|
||||
this.encryptKeyManager = config.getEncryptKeyManager();
|
||||
Encryptor be = config.getEncryptor();
|
||||
this.bytesEncryptor = be != null ? be : new SimpleAesEncryptor();
|
||||
this.useJavaxValidationNotNull = config.isUseJavaxValidationNotNull();
|
||||
this.useValidationNotNull = config.isUseValidationNotNull();
|
||||
}
|
||||
|
||||
public TypeManager getTypeManager() {
|
||||
@@ -286,8 +286,8 @@ public class DeployUtil {
|
||||
return type.equals(String.class);
|
||||
}
|
||||
|
||||
boolean isUseJavaxValidationNotNull() {
|
||||
return useJavaxValidationNotNull;
|
||||
boolean isUseValidationNotNull() {
|
||||
return useValidationNotNull;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
package io.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
class InitMetaValidationAnnotation {
|
||||
|
||||
static void init(ReadAnnotationConfig readConfig) {
|
||||
readConfig.addMetaAnnotation(Size.class);
|
||||
readConfig.addMetaAnnotation(Size.List.class);
|
||||
}
|
||||
}
|
||||
+52
-8
@@ -3,8 +3,10 @@ package io.ebeaninternal.server.deploy.parse;
|
||||
import io.ebean.annotation.Aggregation;
|
||||
import io.ebean.annotation.Formula;
|
||||
import io.ebean.annotation.Where;
|
||||
import io.ebean.config.ClassLoadConfig;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import java.util.HashSet;
|
||||
@@ -21,9 +23,12 @@ class ReadAnnotationConfig {
|
||||
private final boolean disableL2Cache;
|
||||
private final boolean eagerFetchLobs;
|
||||
private final boolean javaxValidationAnnotations;
|
||||
private final boolean jakartaValidationAnnotations;
|
||||
private final boolean jacksonAnnotations;
|
||||
private final boolean idGeneratorAutomatic;
|
||||
|
||||
private final boolean useValidationNotNull;
|
||||
private final ReadValidationAnnotations javaxValidation;
|
||||
private final ReadValidationAnnotations jakartaValidation;
|
||||
private final Set<Class<?>> metaAnnotations = new HashSet<>();
|
||||
|
||||
ReadAnnotationConfig(GeneratedPropertyFactory generatedPropFactory, String asOfViewSuffix, String versionsBetweenSuffix, DatabaseConfig config) {
|
||||
@@ -33,20 +38,32 @@ class ReadAnnotationConfig {
|
||||
this.disableL2Cache = config.isDisableL2Cache();
|
||||
this.eagerFetchLobs = config.isEagerFetchLobs();
|
||||
this.idGeneratorAutomatic = config.isIdGeneratorAutomatic();
|
||||
this.javaxValidationAnnotations = generatedPropFactory.getClassLoadConfig().isJavaxValidationAnnotationsPresent();
|
||||
this.jacksonAnnotations = generatedPropFactory.getClassLoadConfig().isJacksonAnnotationsPresent();
|
||||
this.useValidationNotNull = config.isUseValidationNotNull();
|
||||
ClassLoadConfig classLoadConfig = generatedPropFactory.getClassLoadConfig();
|
||||
this.javaxValidationAnnotations = classLoadConfig.isJavaxValidationAnnotationsPresent();
|
||||
this.jakartaValidationAnnotations = classLoadConfig.isJakartaValidationAnnotationsPresent();
|
||||
this.jacksonAnnotations = classLoadConfig.isJacksonAnnotationsPresent();
|
||||
this.metaAnnotations.add(Column.class);
|
||||
this.metaAnnotations.add(Formula.class);
|
||||
this.metaAnnotations.add(Formula.List.class);
|
||||
this.metaAnnotations.add(Where.class);
|
||||
this.metaAnnotations.add(Where.List.class);
|
||||
this.metaAnnotations.add(Aggregation.class);
|
||||
this.javaxValidation = javaxValidationAnnotations ? new ReadValidationAnnotationsJavax(this) : null;
|
||||
this.jakartaValidation = jakartaValidationAnnotations ? new ReadValidationAnnotationsJakarta(this) : null;
|
||||
if (jacksonAnnotations) {
|
||||
InitMetaJacksonAnnotation.init(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void addMetaAnnotation(Class<?> annotation) {
|
||||
void addMetaAnnotation(Class<?> annotation) {
|
||||
metaAnnotations.add(annotation);
|
||||
}
|
||||
|
||||
boolean checkValidationAnnotations() {
|
||||
return javaxValidationAnnotations || jakartaValidationAnnotations;
|
||||
}
|
||||
|
||||
GeneratedPropertyFactory getGeneratedPropFactory() {
|
||||
return generatedPropFactory;
|
||||
}
|
||||
@@ -71,10 +88,6 @@ class ReadAnnotationConfig {
|
||||
return idGeneratorAutomatic;
|
||||
}
|
||||
|
||||
boolean isJavaxValidationAnnotations() {
|
||||
return javaxValidationAnnotations;
|
||||
}
|
||||
|
||||
boolean isJacksonAnnotations() {
|
||||
return jacksonAnnotations;
|
||||
}
|
||||
@@ -82,4 +95,35 @@ class ReadAnnotationConfig {
|
||||
public Set<Class<?>> getMetaAnnotations() {
|
||||
return metaAnnotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a NotNull validation annotation is on the property.
|
||||
*/
|
||||
boolean isValidationNotNull(DeployBeanProperty property) {
|
||||
if (!useValidationNotNull) {
|
||||
return false;
|
||||
}
|
||||
if (javaxValidation != null && javaxValidation.isValidationNotNull(property)) {
|
||||
return true;
|
||||
}
|
||||
if (jakartaValidation != null && jakartaValidation.isValidationNotNull(property)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the max size of all validation @Size annotations.
|
||||
*/
|
||||
int maxValidationSize(DeployBeanProperty prop) {
|
||||
int maxSize = 0;
|
||||
if (javaxValidation != null) {
|
||||
maxSize = Math.max(maxSize, javaxValidation.maxSize(prop));
|
||||
}
|
||||
if (jakartaValidation != null) {
|
||||
maxSize = Math.max(maxSize, jakartaValidation.maxSize(prop));
|
||||
}
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,12 +14,6 @@ public class ReadAnnotations {
|
||||
|
||||
public ReadAnnotations(GeneratedPropertyFactory generatedPropFactory, String asOfViewSuffix, String versionsBetweenSuffix, DatabaseConfig config) {
|
||||
this.readConfig = new ReadAnnotationConfig(generatedPropFactory, asOfViewSuffix, versionsBetweenSuffix, config);
|
||||
if (readConfig.isJavaxValidationAnnotations()) {
|
||||
InitMetaValidationAnnotation.init(readConfig);
|
||||
}
|
||||
if (readConfig.isJacksonAnnotations()) {
|
||||
InitMetaJacksonAnnotation.init(readConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package io.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
/**
|
||||
* Reads validation NotNull and Size annotations for mapping.
|
||||
*/
|
||||
interface ReadValidationAnnotations {
|
||||
|
||||
/**
|
||||
* Return true if the property has a NotNull validation annotation.
|
||||
*/
|
||||
boolean isValidationNotNull(DeployBeanProperty property);
|
||||
|
||||
/**
|
||||
* Return the max value of the Size validation annotations on the property.
|
||||
*/
|
||||
int maxSize(DeployBeanProperty property);
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package io.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import jakarta.validation.groups.Default;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Jakarta validation annotations reader.
|
||||
*/
|
||||
class ReadValidationAnnotationsJakarta implements ReadValidationAnnotations {
|
||||
|
||||
ReadValidationAnnotationsJakarta(ReadAnnotationConfig readConfig) {
|
||||
readConfig.addMetaAnnotation(Size.class);
|
||||
readConfig.addMetaAnnotation(Size.List.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidationNotNull(DeployBeanProperty property) {
|
||||
NotNull notNull = AnnotationUtil.get(property.getField(), NotNull.class);
|
||||
return (notNull != null && isEbeanValidationGroups(notNull.groups()));
|
||||
}
|
||||
|
||||
private boolean isEbeanValidationGroups(Class<?>[] groups) {
|
||||
return groups.length == 0 || groups.length == 1 && Default.class.isAssignableFrom(groups[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int maxSize(DeployBeanProperty property) {
|
||||
int maxSize = 0;
|
||||
for (Size size : getMetaAnnotationJavaxSize(property)) {
|
||||
if (size.max() < Integer.MAX_VALUE) {
|
||||
maxSize = Math.max(maxSize, size.max());
|
||||
}
|
||||
}
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
private List<Size> getMetaAnnotationJavaxSize(DeployBeanProperty prop) {
|
||||
final List<Size> size = prop.getMetaAnnotations(Size.class);
|
||||
final List<Size.List> lists = prop.getMetaAnnotations(Size.List.class);
|
||||
for (Size.List list : lists) {
|
||||
Collections.addAll(size, list.value());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package io.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import javax.validation.groups.Default;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Javax validation annotations reader.
|
||||
*/
|
||||
class ReadValidationAnnotationsJavax implements ReadValidationAnnotations {
|
||||
|
||||
ReadValidationAnnotationsJavax(ReadAnnotationConfig readConfig) {
|
||||
readConfig.addMetaAnnotation(Size.class);
|
||||
readConfig.addMetaAnnotation(Size.List.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidationNotNull(DeployBeanProperty property) {
|
||||
NotNull notNull = AnnotationUtil.get(property.getField(), NotNull.class);
|
||||
return (notNull != null && isEbeanValidationGroups(notNull.groups()));
|
||||
}
|
||||
|
||||
private boolean isEbeanValidationGroups(Class<?>[] groups) {
|
||||
return groups.length == 0 || groups.length == 1 && Default.class.isAssignableFrom(groups[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int maxSize(DeployBeanProperty prop) {
|
||||
int maxSize = 0;
|
||||
for (Size size : getMetaAnnotationJavaxSize(prop)) {
|
||||
if (size.max() < Integer.MAX_VALUE) {
|
||||
maxSize = Math.max(maxSize, size.max());
|
||||
}
|
||||
}
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
private List<Size> getMetaAnnotationJavaxSize(DeployBeanProperty prop) {
|
||||
final List<Size> size = prop.getMetaAnnotations(Size.class);
|
||||
final List<Size.List> lists = prop.getMetaAnnotations(Size.List.class);
|
||||
for (Size.List list : lists) {
|
||||
Collections.addAll(size, list.value());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
}
|
||||
-15
@@ -501,31 +501,16 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return query.forUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdate(Query.LockType lockType) {
|
||||
return query.forUpdate(lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateNoWait() {
|
||||
return query.forUpdateNoWait();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateNoWait(Query.LockType lockType) {
|
||||
return query.forUpdateNoWait(lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateSkipLocked() {
|
||||
return query.forUpdateSkipLocked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateSkipLocked(Query.LockType lockType) {
|
||||
return query.forUpdateSkipLocked(lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> select(String fetchProperties) {
|
||||
return query.select(fetchProperties);
|
||||
|
||||
@@ -506,31 +506,16 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
return exprList.forUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdate(Query.LockType lockType) {
|
||||
return exprList.forUpdate(lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateNoWait() {
|
||||
return exprList.forUpdateNoWait();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateNoWait(Query.LockType lockType) {
|
||||
return exprList.forUpdateNoWait(lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateSkipLocked() {
|
||||
return exprList.forUpdateSkipLocked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateSkipLocked(Query.LockType lockType) {
|
||||
return exprList.forUpdateSkipLocked(lockType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Path exists - for the given path in a JSON document.
|
||||
*/
|
||||
|
||||
@@ -17,11 +17,11 @@ class ParseFetchConfig {
|
||||
|
||||
if (path.startsWith("lazy")) {
|
||||
if (path.length() == 4) {
|
||||
return new FetchConfig().lazy();
|
||||
return FetchConfig.ofLazy();
|
||||
} else if (path.charAt(4) == '(') {
|
||||
path = path.substring(5);
|
||||
int batchSize = parseBatchSize(path);
|
||||
return new FetchConfig().lazy(batchSize);
|
||||
return FetchConfig.ofLazy(batchSize);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -29,11 +29,11 @@ class ParseFetchConfig {
|
||||
|
||||
if (path.startsWith("query")) {
|
||||
if (path.length() == 5) {
|
||||
return new FetchConfig().query();
|
||||
return FetchConfig.ofQuery();
|
||||
} else if (path.charAt(5) == '(') {
|
||||
path = path.substring(6);
|
||||
int batchSize = parseBatchSize(path);
|
||||
return new FetchConfig().query(batchSize);
|
||||
return FetchConfig.ofQuery(batchSize);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.ebeaninternal.server.loadcontext;
|
||||
|
||||
import io.ebean.FetchConfig;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
@@ -28,9 +27,7 @@ abstract class DLoadBaseContext {
|
||||
|
||||
final boolean hitCache;
|
||||
|
||||
final int firstBatchSize;
|
||||
|
||||
final int secondaryBatchSize;
|
||||
final int batchSize;
|
||||
|
||||
final ObjectGraphNode objectGraphNode;
|
||||
|
||||
@@ -45,38 +42,11 @@ abstract class DLoadBaseContext {
|
||||
this.hitCache = parent.isBeanCacheGet() && desc.isBeanCaching();
|
||||
this.objectGraphNode = parent.getObjectGraphNode(path);
|
||||
this.queryFetch = queryProps != null && queryProps.isQueryFetch();
|
||||
this.firstBatchSize = initFirstBatchSize(defaultBatchSize, queryProps);
|
||||
this.secondaryBatchSize = initSecondaryBatchSize(defaultBatchSize, firstBatchSize, queryProps);
|
||||
this.batchSize = initBatchSize(defaultBatchSize, queryProps);
|
||||
}
|
||||
|
||||
private int initFirstBatchSize(int batchSize, OrmQueryProperties queryProps) {
|
||||
if (queryProps == null) {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
int queryBatchSize = queryProps.getQueryFetchBatch();
|
||||
if (queryBatchSize == -1) {
|
||||
return batchSize;
|
||||
|
||||
} else if (queryBatchSize == 0) {
|
||||
return 100;
|
||||
|
||||
} else {
|
||||
return queryBatchSize;
|
||||
}
|
||||
}
|
||||
|
||||
private int initSecondaryBatchSize(int defaultBatchSize, int firstBatchSize, OrmQueryProperties queryProps) {
|
||||
if (queryProps == null) {
|
||||
return defaultBatchSize;
|
||||
}
|
||||
FetchConfig fetchConfig = queryProps.getFetchConfig();
|
||||
if (fetchConfig.isQueryAll()) {
|
||||
return firstBatchSize;
|
||||
}
|
||||
|
||||
int lazyBatchSize = fetchConfig.getLazyBatchSize();
|
||||
return (lazyBatchSize > 1) ? lazyBatchSize : defaultBatchSize;
|
||||
private int initBatchSize(int batchSize, OrmQueryProperties queryProps) {
|
||||
return queryProps == null ? batchSize : queryProps.getBatchSize();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,7 +54,6 @@ abstract class DLoadBaseContext {
|
||||
* set onto the secondary query.
|
||||
*/
|
||||
void setLabel(SpiQuery<?> query) {
|
||||
|
||||
String label = parent.getPlanLabel();
|
||||
if (label != null) {
|
||||
query.setProfilePath(label, fullPath, parent.getProfileLocation());
|
||||
|
||||
@@ -35,7 +35,7 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
|
||||
super(parent, desc, path, defaultBatchSize, queryProps);
|
||||
// bufferList only required when using query joins (queryFetch)
|
||||
this.bufferList = (!queryFetch) ? null : new ArrayList<>();
|
||||
this.currentBuffer = createBuffer(firstBatchSize);
|
||||
this.currentBuffer = createBuffer(batchSize);
|
||||
this.cache = (queryProps != null) && queryProps.isCache();
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
|
||||
if (bufferList != null) {
|
||||
bufferList.clear();
|
||||
}
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
currentBuffer = createBuffer(batchSize);
|
||||
}
|
||||
|
||||
private void configureQuery(SpiQuery<?> query, String lazyLoadProperty) {
|
||||
@@ -70,7 +70,7 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
|
||||
|
||||
protected void register(EntityBeanIntercept ebi) {
|
||||
if (currentBuffer.isFull()) {
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
currentBuffer = createBuffer(batchSize);
|
||||
}
|
||||
ebi.setBeanLoader(currentBuffer, getPersistenceContext());
|
||||
currentBuffer.add(ebi);
|
||||
@@ -95,10 +95,6 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
|
||||
for (LoadBuffer loadBuffer : bufferList) {
|
||||
if (!loadBuffer.list.isEmpty()) {
|
||||
parent.getEbeanServer().loadBean(new LoadBeanRequest(loadBuffer, parentRequest));
|
||||
if (!queryProps.isQueryFetchAll()) {
|
||||
// Stop - only fetch the first batch ... the rest will be lazy loaded
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (forEach) {
|
||||
clear();
|
||||
|
||||
@@ -188,7 +188,7 @@ public class DLoadContext implements LoadContext {
|
||||
}
|
||||
int maxBatch = 0;
|
||||
for (OrmQueryProperties aSecQuery : secQuery) {
|
||||
int batchSize = aSecQuery.getQueryFetchBatch();
|
||||
int batchSize = aSecQuery.getBatchSize();
|
||||
if (batchSize == 0) {
|
||||
batchSize = defaultQueryBatch;
|
||||
}
|
||||
@@ -300,12 +300,9 @@ public class DLoadContext implements LoadContext {
|
||||
}
|
||||
|
||||
private void registerSecondaryNode(boolean many, OrmQueryProperties props) {
|
||||
int batchSize;
|
||||
if (props.isQueryFetch()) {
|
||||
batchSize = 100;
|
||||
} else {
|
||||
int lazyJoinBatch = props.getLazyFetchBatch();
|
||||
batchSize = lazyJoinBatch > 0 ? lazyJoinBatch : defaultBatchSize;
|
||||
int batchSize = props.getBatchSize();
|
||||
if (batchSize == 0) {
|
||||
batchSize = defaultBatchSize;
|
||||
}
|
||||
String path = props.getPath();
|
||||
if (many) {
|
||||
|
||||
@@ -40,7 +40,7 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
this.docStoreMapped = property.isTargetDocStoreMapped();
|
||||
// bufferList only required when using query joins (queryFetch)
|
||||
this.bufferList = (!queryFetch) ? null : new ArrayList<>();
|
||||
this.currentBuffer = createBuffer(firstBatchSize);
|
||||
this.currentBuffer = createBuffer(batchSize);
|
||||
}
|
||||
|
||||
private LoadBuffer createBuffer(int size) {
|
||||
@@ -58,11 +58,10 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
if (bufferList != null) {
|
||||
bufferList.clear();
|
||||
}
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
currentBuffer = createBuffer(batchSize);
|
||||
}
|
||||
|
||||
private void configureQuery(SpiQuery<?> query) {
|
||||
|
||||
setLabel(query);
|
||||
parent.propagateQueryState(query, docStoreMapped);
|
||||
query.setParentNode(objectGraphNode);
|
||||
@@ -85,9 +84,8 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
}
|
||||
|
||||
public void register(BeanCollection<?> bc) {
|
||||
|
||||
if (currentBuffer.isFull()) {
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
currentBuffer = createBuffer(batchSize);
|
||||
}
|
||||
currentBuffer.add(bc);
|
||||
bc.setLoader(currentBuffer);
|
||||
@@ -105,13 +103,8 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
if (!loadBuffer.list.isEmpty()) {
|
||||
LoadManyRequest req = new LoadManyRequest(loadBuffer, parentRequest);
|
||||
parent.getEbeanServer().loadMany(req);
|
||||
if (!queryProps.isQueryFetchAll()) {
|
||||
// Stop - only fetch the first batch ... the rest will be lazy loaded
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (forEach) {
|
||||
clear();
|
||||
} else {
|
||||
|
||||
@@ -210,18 +210,6 @@ public class SaveManyBeans extends SaveManyBase {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasNewOrDirtyBeans() {
|
||||
if (collection == null) {
|
||||
return false;
|
||||
}
|
||||
for (Object bean : collection) {
|
||||
if (bean instanceof EntityBean && ((EntityBean) bean)._ebean_getIntercept().isNewOrDirty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the Id values of the details to remove 'missing children' for stateless updates.
|
||||
*/
|
||||
@@ -344,14 +332,18 @@ public class SaveManyBeans extends SaveManyBase {
|
||||
transaction.depth(-1);
|
||||
}
|
||||
|
||||
private boolean isChangedProperty() {
|
||||
return parentBean._ebean_getIntercept().isChangedProperty(many.getPropertyIndex());
|
||||
}
|
||||
|
||||
private void removeAssocManyOrphans() {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
if (!(value instanceof BeanCollection<?>)) {
|
||||
// if (!insertedParent && cascade && hasNewOrDirtyBeans()) {
|
||||
// persister.addToFlushQueue(many.deleteByParentId(request.getBeanId(), null), transaction, 0);
|
||||
// }
|
||||
if (!insertedParent && cascade && isChangedProperty()) {
|
||||
persister.addToFlushQueue(many.deleteByParentId(request.getBeanId(), null), transaction, 0);
|
||||
}
|
||||
} else {
|
||||
BeanCollection<?> c = (BeanCollection<?>) value;
|
||||
Set<?> modifyRemovals = c.getModifyRemovals();
|
||||
|
||||
@@ -296,10 +296,10 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
this.cancelled = true;
|
||||
if (pstmt != null) {
|
||||
try {
|
||||
logger.debug("Cancelling query");
|
||||
pstmt.cancel();
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error cancelling query";
|
||||
throw new PersistenceException(msg, e);
|
||||
throw new PersistenceException("Error cancelling query", e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@@ -322,7 +322,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
}
|
||||
|
||||
private boolean prepareBindExecuteQueryWithOption(boolean forwardOnlyHint) throws SQLException {
|
||||
|
||||
ResultSet resultSet = prepareResultSet(forwardOnlyHint);
|
||||
if (resultSet == null) {
|
||||
return false;
|
||||
@@ -334,19 +333,12 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
ResultSet prepareResultSet(boolean forwardOnlyHint) throws SQLException {
|
||||
lock.lock();
|
||||
try {
|
||||
if (cancelled || query.isCancelled()) {
|
||||
// cancelled before we started
|
||||
cancelled = true;
|
||||
return null;
|
||||
if (cancelled) {
|
||||
throw new SQLException("Query cancelled");
|
||||
}
|
||||
|
||||
startNano = System.nanoTime();
|
||||
|
||||
// prepare
|
||||
SpiTransaction t = request.getTransaction();
|
||||
profileOffset = t.profileOffset();
|
||||
Connection conn = t.getInternalConnection();
|
||||
|
||||
if (query.isRawSql()) {
|
||||
ResultSet suppliedResultSet = query.getRawSql().getResultSet();
|
||||
if (suppliedResultSet != null) {
|
||||
@@ -356,6 +348,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
}
|
||||
}
|
||||
|
||||
Connection conn = t.getInternalConnection();
|
||||
if (forwardOnlyHint) {
|
||||
// Use forward only hints for large resultSet processing (Issue 56, MySql specific)
|
||||
pstmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
|
||||
@@ -363,18 +356,13 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
} else {
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
}
|
||||
|
||||
if (query.getTimeout() > 0) {
|
||||
pstmt.setQueryTimeout(query.getTimeout());
|
||||
}
|
||||
if (query.getBufferFetchSizeHint() > 0) {
|
||||
pstmt.setFetchSize(query.getBufferFetchSizeHint());
|
||||
}
|
||||
|
||||
DataBind dataBind = queryPlan.bindEncryptedProperties(pstmt, conn);
|
||||
bindLog = predicates.bind(dataBind);
|
||||
|
||||
// executeQuery
|
||||
bindLog = predicates.bind(queryPlan.bindEncryptedProperties(pstmt, conn));
|
||||
return pstmt.executeQuery();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
|
||||
@@ -401,12 +401,6 @@ public class CQueryEngine {
|
||||
if (cquery != null) {
|
||||
cquery.close();
|
||||
}
|
||||
if (request.getQuery().isFutureFetch()) {
|
||||
// end the transaction for futureFindIds
|
||||
// as it had it's own transaction
|
||||
logger.debug("Future fetch completed!");
|
||||
request.getTransaction().end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,13 @@ import io.ebeaninternal.server.querydefn.SpiFetchGroup;
|
||||
*/
|
||||
class DFetchGroupBuilder<T> implements FetchGroupBuilder<T> {
|
||||
|
||||
private static final FetchConfig FETCH_CACHE = new FetchConfig().cache();
|
||||
private static final FetchConfig DEFAULT_FETCH = FetchConfig.ofDefault();
|
||||
|
||||
private static final FetchConfig FETCH_QUERY = new FetchConfig().query();
|
||||
private static final FetchConfig FETCH_CACHE = FetchConfig.ofCache();
|
||||
|
||||
private static final FetchConfig FETCH_LAZY = new FetchConfig().lazy();
|
||||
private static final FetchConfig FETCH_QUERY = FetchConfig.ofQuery();
|
||||
|
||||
private static final FetchConfig FETCH_LAZY = FetchConfig.ofLazy();
|
||||
|
||||
private final OrmQueryDetail detail;
|
||||
|
||||
@@ -31,13 +33,13 @@ class DFetchGroupBuilder<T> implements FetchGroupBuilder<T> {
|
||||
|
||||
@Override
|
||||
public FetchGroupBuilder<T> fetch(String path) {
|
||||
detail.fetch(path, null, null);
|
||||
detail.fetchProperties(path, null, DEFAULT_FETCH);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchGroupBuilder<T> fetch(String path, FetchGroup nestedGroup) {
|
||||
return fetchNested(path, nestedGroup, null);
|
||||
return fetchNested(path, nestedGroup, DEFAULT_FETCH);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,7 +53,6 @@ class DFetchGroupBuilder<T> implements FetchGroupBuilder<T> {
|
||||
}
|
||||
|
||||
private FetchGroupBuilder<T> fetchNested(String path, FetchGroup nestedGroup, FetchConfig fetchConfig) {
|
||||
|
||||
OrmQueryDetail nestedDetail = ((SpiFetchGroup) nestedGroup).underlying();
|
||||
detail.addNested(path, nestedDetail, fetchConfig);
|
||||
return this;
|
||||
@@ -59,25 +60,25 @@ class DFetchGroupBuilder<T> implements FetchGroupBuilder<T> {
|
||||
|
||||
@Override
|
||||
public FetchGroupBuilder<T> fetchQuery(String path) {
|
||||
detail.fetch(path, null, FETCH_QUERY);
|
||||
detail.fetchProperties(path, null, FETCH_QUERY);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchGroupBuilder<T> fetchCache(String path) {
|
||||
detail.fetch(path, null, FETCH_CACHE);
|
||||
detail.fetchProperties(path, null, FETCH_CACHE);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchGroupBuilder<T> fetchLazy(String path) {
|
||||
detail.fetch(path, null, FETCH_LAZY);
|
||||
detail.fetchProperties(path, null, FETCH_LAZY);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchGroupBuilder<T> fetch(String path, String properties) {
|
||||
detail.fetch(path, properties, null);
|
||||
detail.fetch(path, properties, DEFAULT_FETCH);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+15
-19
@@ -25,6 +25,7 @@ import io.ebean.Transaction;
|
||||
import io.ebean.UpdateQuery;
|
||||
import io.ebean.Version;
|
||||
import io.ebean.service.SpiFetchGroupQuery;
|
||||
import io.ebeaninternal.api.SpiQueryFetch;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import io.ebeaninternal.server.querydefn.SpiFetchGroup;
|
||||
|
||||
@@ -43,13 +44,13 @@ import java.util.stream.Stream;
|
||||
/**
|
||||
* Implementation of FetchGroup query for use to create FetchGroup via query beans.
|
||||
*/
|
||||
class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T> {
|
||||
class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQueryFetch {
|
||||
|
||||
private static final FetchConfig FETCH_CACHE = new FetchConfig().cache();
|
||||
private static final FetchConfig FETCH_CACHE = FetchConfig.ofCache();
|
||||
|
||||
private static final FetchConfig FETCH_QUERY = new FetchConfig().query();
|
||||
private static final FetchConfig FETCH_QUERY = FetchConfig.ofQuery();
|
||||
|
||||
private static final FetchConfig FETCH_LAZY = new FetchConfig().lazy();
|
||||
private static final FetchConfig FETCH_LAZY = FetchConfig.ofLazy();
|
||||
|
||||
private OrmQueryDetail detail = new OrmQueryDetail();
|
||||
|
||||
@@ -569,21 +570,6 @@ class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T> {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdate(LockType lockType) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateNoWait(LockType lockType) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateSkipLocked(LockType lockType) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForUpdate() {
|
||||
return false;
|
||||
@@ -643,4 +629,14 @@ class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T> {
|
||||
public Query<T> orderById(boolean orderById) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectProperties(Set<String> props) {
|
||||
detail.selectProperties(props);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetchProperties(String property, Set<String> columns, FetchConfig config) {
|
||||
detail.fetchProperties(property, columns, config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ public final class SqlTreeBuilder {
|
||||
// Also note that this can include transient properties.
|
||||
// This makes sense for transient properties used to
|
||||
// hold sum() count() type values (with SqlSelect)
|
||||
final Set<String> selectInclude = queryProps.getSelectInclude();
|
||||
final Set<String> selectInclude = queryProps.getIncluded();
|
||||
for (String propName : selectInclude) {
|
||||
if (!propName.isEmpty()) {
|
||||
addProperty(selectProps, desc, queryProps, propName);
|
||||
|
||||
@@ -83,11 +83,11 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
private static final String DEFAULT_QUERY_NAME = "default";
|
||||
|
||||
private static final FetchConfig FETCH_CACHE = new FetchConfig().cache();
|
||||
private static final FetchConfig FETCH_CACHE = FetchConfig.ofCache();
|
||||
|
||||
private static final FetchConfig FETCH_QUERY = new FetchConfig().query();
|
||||
private static final FetchConfig FETCH_QUERY = FetchConfig.ofQuery();
|
||||
|
||||
private static final FetchConfig FETCH_LAZY = new FetchConfig().lazy();
|
||||
private static final FetchConfig FETCH_LAZY = FetchConfig.ofLazy();
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
@@ -751,7 +751,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
@Override
|
||||
public NaturalKeyQueryData<T> naturalKey() {
|
||||
|
||||
if (whereExpressions == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -767,7 +766,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -815,7 +813,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
copy.m2mIncludeJoin = m2mIncludeJoin;
|
||||
copy.profilingListener = profilingListener;
|
||||
copy.profileLocation = profileLocation;
|
||||
|
||||
copy.baseTable = baseTable;
|
||||
copy.rootTableAlias = rootTableAlias;
|
||||
copy.distinct = distinct;
|
||||
@@ -978,21 +975,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return setForUpdateWithMode(LockWait.WAIT, LockType.DEFAULT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdate(LockType lockType) {
|
||||
return setForUpdateWithMode(LockWait.WAIT, lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateNoWait(LockType lockType) {
|
||||
return setForUpdateWithMode(LockWait.NOWAIT, lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateSkipLocked(LockType lockType) {
|
||||
return setForUpdateWithMode(LockWait.SKIPLOCKED, lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> forUpdateNoWait() {
|
||||
return setForUpdateWithMode(LockWait.NOWAIT, LockType.DEFAULT);
|
||||
@@ -1100,7 +1082,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
@Override
|
||||
public ObjectGraphNode setOrigin(CallOrigin callOrigin) {
|
||||
|
||||
// create a 'origin' which links this query to the profiling information
|
||||
ObjectGraphOrigin o = new ObjectGraphOrigin(calculateOriginQueryHash(), callOrigin, beanType.getName());
|
||||
parentNode = new ObjectGraphNode(o, null);
|
||||
@@ -1140,81 +1121,81 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
private String planDescription() {
|
||||
StringBuilder sb = new StringBuilder(300);
|
||||
if (type != null) {
|
||||
sb.append("t:").append(type.ordinal());
|
||||
sb.append(type.ordinal());
|
||||
}
|
||||
if (useDocStore) {
|
||||
sb.append(",ds:");
|
||||
sb.append("/ds");
|
||||
}
|
||||
if (beanDescriptor.getDiscValue() != null) {
|
||||
sb.append(",disc:").append(beanDescriptor.getDiscValue());
|
||||
sb.append("/dv").append(beanDescriptor.getDiscValue());
|
||||
}
|
||||
if (temporalMode != SpiQuery.TemporalMode.CURRENT) {
|
||||
sb.append(",temp:").append(temporalMode.ordinal());
|
||||
sb.append("/tm").append(temporalMode.ordinal());
|
||||
if (versionsStart != null) {
|
||||
sb.append(",vb:");
|
||||
sb.append("v");
|
||||
}
|
||||
}
|
||||
if (forUpdate != null) {
|
||||
sb.append(",forUpd:").append(forUpdate.ordinal());
|
||||
sb.append("/fu").append(forUpdate.ordinal());
|
||||
if (lockType != null) {
|
||||
sb.append(",lt:").append(lockType.ordinal());
|
||||
sb.append("t").append(lockType.ordinal());
|
||||
}
|
||||
}
|
||||
if (id != null) {
|
||||
sb.append(",id:");
|
||||
sb.append("/id");
|
||||
}
|
||||
if (manualId) {
|
||||
sb.append(",manId:");
|
||||
sb.append("/md");
|
||||
}
|
||||
if (distinct) {
|
||||
sb.append(",dist:");
|
||||
sb.append("/dt");
|
||||
}
|
||||
if (allowLoadErrors) {
|
||||
sb.append(",allowLoadErrors:");
|
||||
sb.append("/ae");
|
||||
}
|
||||
if (disableLazyLoading) {
|
||||
sb.append(",disLazy:");
|
||||
sb.append("/dl");
|
||||
}
|
||||
if (baseTable != null) {
|
||||
sb.append(",baseTable:").append(baseTable);
|
||||
sb.append("/bt").append(baseTable);
|
||||
}
|
||||
if (rootTableAlias != null) {
|
||||
sb.append(",root:").append(rootTableAlias);
|
||||
sb.append("/ra").append(rootTableAlias);
|
||||
}
|
||||
if (orderBy != null) {
|
||||
sb.append(",orderBy:").append(orderBy.toStringFormat());
|
||||
sb.append("/ob").append(orderBy.toStringFormat());
|
||||
}
|
||||
if (m2mIncludeJoin != null) {
|
||||
sb.append(",m2m:").append(m2mIncludeJoin.getTable());
|
||||
sb.append("/m2").append(m2mIncludeJoin.getTable());
|
||||
}
|
||||
if (mapKey != null) {
|
||||
sb.append(",mapKey:").append(mapKey);
|
||||
sb.append("/mk").append(mapKey);
|
||||
}
|
||||
if (countDistinctOrder != null) {
|
||||
sb.append(",countDistOrd:").append(countDistinctOrder.name());
|
||||
sb.append("/cd").append(countDistinctOrder.name());
|
||||
}
|
||||
if (detail != null) {
|
||||
sb.append(" detail[");
|
||||
sb.append("/d[");
|
||||
detail.queryPlanHash(sb);
|
||||
sb.append("]");
|
||||
}
|
||||
if (bindParams != null) {
|
||||
sb.append(" bindParams[");
|
||||
sb.append("/b[");
|
||||
bindParams.buildQueryPlanHash(sb);
|
||||
sb.append("]");
|
||||
}
|
||||
if (whereExpressions != null) {
|
||||
sb.append(" where[");
|
||||
sb.append("/w[");
|
||||
whereExpressions.queryPlanHash(sb);
|
||||
sb.append("]");
|
||||
}
|
||||
if (havingExpressions != null) {
|
||||
sb.append(" having[");
|
||||
sb.append("/h[");
|
||||
havingExpressions.queryPlanHash(sb);
|
||||
sb.append("]");
|
||||
}
|
||||
if (updateProperties != null) {
|
||||
sb.append(" update[");
|
||||
sb.append("/u[");
|
||||
updateProperties.buildQueryPlanHash(sb);
|
||||
sb.append("]");
|
||||
}
|
||||
@@ -1241,7 +1222,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
*/
|
||||
@Override
|
||||
public CQueryPlanKey prepare(SpiOrmQueryRequest<T> request) {
|
||||
|
||||
prepareExpressions(request);
|
||||
prepareForPaging();
|
||||
queryPlanKey = createQueryPlanKey();
|
||||
@@ -1252,7 +1232,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
* Prepare the expressions (compile sub-queries etc).
|
||||
*/
|
||||
private void prepareExpressions(BeanQueryRequest<?> request) {
|
||||
|
||||
if (whereExpressions != null) {
|
||||
whereExpressions.prepareExpression(request);
|
||||
}
|
||||
@@ -1267,7 +1246,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
* case, this is not a distinct query
|
||||
*/
|
||||
private void prepareForPaging() {
|
||||
|
||||
// add the rawSql statement - if any
|
||||
if (orderByIsEmpty()) {
|
||||
if (rawSql != null && rawSql.getSql() != null) {
|
||||
@@ -1414,6 +1392,26 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectProperties(Set<String> props) {
|
||||
detail.selectProperties(props);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetchProperties(String property, Set<String> columns, FetchConfig config) {
|
||||
detail.fetchProperties(property, columns, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectProperties(OrmQueryProperties properties) {
|
||||
detail.selectProperties(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetchProperties(String path, OrmQueryProperties other) {
|
||||
detail.fetchProperties(path, other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> select(String columns) {
|
||||
detail.select(columns);
|
||||
@@ -1678,7 +1676,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
if (bindParams == null) {
|
||||
bindParams = new BindParams();
|
||||
}
|
||||
@@ -1972,7 +1969,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
if (namedParams == null) {
|
||||
namedParams = new HashMap<>();
|
||||
}
|
||||
|
||||
return namedParams.computeIfAbsent(name, ONamedParam::new);
|
||||
}
|
||||
|
||||
@@ -2066,8 +2062,8 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
public void cancel() {
|
||||
lock.lock();
|
||||
try {
|
||||
cancelled = true;
|
||||
if (cancelableQuery != null) {
|
||||
if (!cancelled && cancelableQuery != null) {
|
||||
cancelled = true;
|
||||
cancelableQuery.cancel();
|
||||
}
|
||||
} finally {
|
||||
@@ -2095,7 +2091,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
*/
|
||||
@Override
|
||||
public Set<String> validate(BeanType<T> desc) {
|
||||
|
||||
SpiExpressionValidation validation = new SpiExpressionValidation(desc);
|
||||
if (whereExpressions != null) {
|
||||
whereExpressions.validate(validation);
|
||||
|
||||
@@ -59,9 +59,9 @@ public class OrmQueryDetail implements Serializable {
|
||||
* Add a nested OrmQueryDetail to this detail.
|
||||
*/
|
||||
public void addNested(String path, OrmQueryDetail other, FetchConfig config) {
|
||||
fetch(path, other.baseProps.getProperties(), config);
|
||||
fetchProperties(path, other.baseProps, config);
|
||||
for (Map.Entry<String, OrmQueryProperties> entry : other.fetchPaths.entrySet()) {
|
||||
fetch(path + "." + entry.getKey(), entry.getValue().getProperties(), entry.getValue().getFetchConfig());
|
||||
fetchProperties(path + "." + entry.getKey(), entry.getValue(), entry.getValue().getFetchConfig());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,25 +106,20 @@ public class OrmQueryDetail implements Serializable {
|
||||
return p1 == null ? p2 == null : p1.isSameByAutoTune(p2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return asString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the detail in string form.
|
||||
*/
|
||||
public String asString() {
|
||||
public String asStringDebug() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (!baseProps.isEmpty()) {
|
||||
baseProps.append("select ", sb);
|
||||
if (baseProps.hasProperties()) {
|
||||
baseProps.asStringDebug("select ", sb);
|
||||
}
|
||||
if (fetchPaths != null) {
|
||||
for (OrmQueryProperties join : fetchPaths.values()) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(" ");
|
||||
}
|
||||
join.append("fetch ", sb);
|
||||
join.asStringDebug("fetch ", sb);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
@@ -138,8 +133,19 @@ public class OrmQueryDetail implements Serializable {
|
||||
/**
|
||||
* set the properties to include on the base / root entity.
|
||||
*/
|
||||
public void select(String columns) {
|
||||
baseProps = new OrmQueryProperties(null, columns, null);
|
||||
public void select(String properties) {
|
||||
baseProps = new OrmQueryProperties(null, properties, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set select properties that are already parsed.
|
||||
*/
|
||||
public void selectProperties(Set<String> properties) {
|
||||
baseProps = new OrmQueryProperties(null, properties, OrmQueryProperties.DEFAULT_FETCH);
|
||||
}
|
||||
|
||||
void selectProperties(OrmQueryProperties other) {
|
||||
baseProps = new OrmQueryProperties(null, other, OrmQueryProperties.DEFAULT_FETCH);
|
||||
}
|
||||
|
||||
boolean containsProperty(String property) {
|
||||
@@ -150,7 +156,7 @@ public class OrmQueryDetail implements Serializable {
|
||||
* Set the base query properties to be empty.
|
||||
*/
|
||||
public void setEmptyBase() {
|
||||
this.baseProps = new OrmQueryProperties(null, new LinkedHashSet<>());
|
||||
this.baseProps = new OrmQueryProperties(null, Collections.emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,10 +273,24 @@ public class OrmQueryDetail implements Serializable {
|
||||
* @param partialProps the properties on the join property to include
|
||||
*/
|
||||
public void fetch(String path, String partialProps, FetchConfig fetchConfig) {
|
||||
|
||||
fetch(new OrmQueryProperties(path, partialProps, fetchConfig));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set fetch properties that are already parsed.
|
||||
*/
|
||||
public void fetchProperties(String path, Set<String> properties, FetchConfig fetchConfig) {
|
||||
fetch(new OrmQueryProperties(path, properties, fetchConfig));
|
||||
}
|
||||
|
||||
void fetchProperties(String path, OrmQueryProperties other) {
|
||||
fetchProperties(path, other, other.getFetchConfig());
|
||||
}
|
||||
|
||||
void fetchProperties(String path, OrmQueryProperties other, FetchConfig fetchConfig) {
|
||||
fetch(new OrmQueryProperties(path, other, fetchConfig));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add for raw sql etc when the properties are already parsed into a set.
|
||||
*/
|
||||
@@ -316,7 +336,7 @@ public class OrmQueryDetail implements Serializable {
|
||||
if (addId) {
|
||||
parentProp = new OrmQueryProperties(parentPath, assocOne.getTargetIdProperty());
|
||||
} else {
|
||||
parentProp = new OrmQueryProperties(parentPath, new LinkedHashSet<>());
|
||||
parentProp = new OrmQueryProperties(parentPath, Collections.emptySet());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class OrmQueryPlanKey implements CQueryPlanKey {
|
||||
|
||||
@Override
|
||||
public CQueryPlanKey withDeleteByIds() {
|
||||
return new OrmQueryPlanKey(description + ":deleteByIds", 0, 0, null);
|
||||
return new OrmQueryPlanKey(description + "/deleteByIds", 0, 0, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+61
-136
@@ -26,27 +26,20 @@ public class OrmQueryProperties implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8785582703966455658L;
|
||||
|
||||
static final FetchConfig DEFAULT_FETCH = new FetchConfig();
|
||||
static final FetchConfig DEFAULT_FETCH = FetchConfig.ofDefault();
|
||||
|
||||
private final String parentPath;
|
||||
private final String path;
|
||||
|
||||
private final String rawProperties;
|
||||
private final String trimmedProperties;
|
||||
|
||||
private final LinkedHashSet<String> included;
|
||||
|
||||
private final boolean allProperties;
|
||||
private final Set<String> included;
|
||||
private final FetchConfig fetchConfig;
|
||||
private final boolean cache;
|
||||
|
||||
/**
|
||||
* Flag set when this fetch path needs to be a query join.
|
||||
*/
|
||||
private boolean markForQueryJoin;
|
||||
|
||||
private boolean cache;
|
||||
|
||||
private boolean readOnly;
|
||||
|
||||
/**
|
||||
* Included bean joins.
|
||||
*/
|
||||
@@ -84,68 +77,51 @@ public class OrmQueryProperties implements Serializable {
|
||||
public OrmQueryProperties(String path) {
|
||||
this.path = path;
|
||||
this.parentPath = SplitName.parent(path);
|
||||
this.rawProperties = null;
|
||||
this.trimmedProperties = null;
|
||||
this.allProperties = false;
|
||||
this.included = null;
|
||||
this.cache = false;
|
||||
this.fetchConfig = DEFAULT_FETCH;
|
||||
}
|
||||
|
||||
public OrmQueryProperties(String path, String rawProperties) {
|
||||
this(path, rawProperties, null);
|
||||
this(path, rawProperties, DEFAULT_FETCH);
|
||||
}
|
||||
|
||||
public OrmQueryProperties(String path, String rawProperties, FetchConfig fetchConfig) {
|
||||
|
||||
OrmQueryPropertiesParser.Response response = OrmQueryPropertiesParser.parse(rawProperties);
|
||||
|
||||
this.path = path;
|
||||
this.parentPath = SplitName.parent(path);
|
||||
this.rawProperties = rawProperties;
|
||||
this.trimmedProperties = response.properties;
|
||||
OrmQueryPropertiesParser.Response response = OrmQueryPropertiesParser.parse(rawProperties);
|
||||
this.allProperties = response.allProperties;
|
||||
this.included = response.included;
|
||||
this.cache = response.cache;
|
||||
this.readOnly = response.readOnly;
|
||||
if (fetchConfig != null) {
|
||||
this.fetchConfig = fetchConfig;
|
||||
if (fetchConfig.isCache()) {
|
||||
this.cache = true;
|
||||
}
|
||||
this.cache = fetchConfig.isCache();
|
||||
} else {
|
||||
this.fetchConfig = response.fetchConfig;
|
||||
this.cache = false;
|
||||
this.fetchConfig = DEFAULT_FETCH;
|
||||
}
|
||||
}
|
||||
|
||||
public OrmQueryProperties(String path, LinkedHashSet<String> parsedProperties) {
|
||||
if (parsedProperties == null) {
|
||||
throw new IllegalArgumentException("parsedProperties is null");
|
||||
}
|
||||
public OrmQueryProperties(String path, Set<String> included) {
|
||||
this(path, included, DEFAULT_FETCH);
|
||||
}
|
||||
|
||||
OrmQueryProperties(String path, Set<String> included, FetchConfig fetchConfig) {
|
||||
this.path = path;
|
||||
this.parentPath = SplitName.parent(path);
|
||||
// for rawSql parsedProperties can be empty (when only fetching Id property)
|
||||
this.included = parsedProperties;
|
||||
this.rawProperties = join(parsedProperties);
|
||||
this.trimmedProperties = rawProperties;
|
||||
this.cache = false;
|
||||
this.readOnly = false;
|
||||
this.fetchConfig = DEFAULT_FETCH;
|
||||
this.included = included;
|
||||
this.allProperties = false;
|
||||
this.fetchConfig = fetchConfig;
|
||||
this.cache = fetchConfig.isCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Join the set of properties into a comma delimited string.
|
||||
*/
|
||||
private String join(LinkedHashSet<String> parsedProperties) {
|
||||
StringBuilder sb = new StringBuilder(50);
|
||||
boolean first = true;
|
||||
for (String property : parsedProperties) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(property);
|
||||
}
|
||||
return sb.toString();
|
||||
OrmQueryProperties(String path, OrmQueryProperties other, FetchConfig fetchConfig) {
|
||||
this.path = path;
|
||||
this.parentPath = SplitName.parent(path);
|
||||
this.allProperties = other.allProperties;
|
||||
this.included = other.included;
|
||||
this.cache = other.cache;
|
||||
this.fetchConfig = fetchConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,10 +131,8 @@ public class OrmQueryProperties implements Serializable {
|
||||
this.fetchConfig = sourceFetchConfig;
|
||||
this.parentPath = source.parentPath;
|
||||
this.path = source.path;
|
||||
this.rawProperties = source.rawProperties;
|
||||
this.trimmedProperties = source.trimmedProperties;
|
||||
this.allProperties = source.allProperties;
|
||||
this.cache = source.cache;
|
||||
this.readOnly = source.readOnly;
|
||||
this.filterMany = source.filterMany;
|
||||
this.markForQueryJoin = source.markForQueryJoin;
|
||||
this.included = (source.included == null) ? null : new LinkedHashSet<>(source.included);
|
||||
@@ -181,6 +155,7 @@ public class OrmQueryProperties implements Serializable {
|
||||
/**
|
||||
* Move a OrderBy.Property from the main query to this query join.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
void addSecJoinOrderProperty(OrderBy.Property orderProp) {
|
||||
if (orderBy == null) {
|
||||
orderBy = new OrderBy();
|
||||
@@ -196,7 +171,7 @@ public class OrmQueryProperties implements Serializable {
|
||||
* Return the expressions used to filter on this path. This should be a many path to use this
|
||||
* method.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public <T> SpiExpressionList<T> filterMany(Query<T> rootQuery) {
|
||||
if (filterMany == null) {
|
||||
FilterExprPath exprPath = new FilterExprPath(path);
|
||||
@@ -239,9 +214,8 @@ public class OrmQueryProperties implements Serializable {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void configureBeanQuery(SpiQuery<?> query) {
|
||||
|
||||
if (trimmedProperties != null && !trimmedProperties.isEmpty()) {
|
||||
query.select(trimmedProperties);
|
||||
if (hasProperties()) {
|
||||
query.selectProperties(this);
|
||||
}
|
||||
|
||||
if (filterMany != null) {
|
||||
@@ -257,7 +231,7 @@ public class OrmQueryProperties implements Serializable {
|
||||
for (OrmQueryProperties p : secondaryChildren) {
|
||||
String path = p.getPath();
|
||||
path = path.substring(trimPath);
|
||||
query.fetch(path, p.getProperties(), p.getFetchConfig());
|
||||
query.fetchProperties(path, p);
|
||||
query.setFilterMany(path, p.getFilterManyTrimPath(trimPath));
|
||||
}
|
||||
}
|
||||
@@ -268,37 +242,26 @@ public class OrmQueryProperties implements Serializable {
|
||||
}
|
||||
|
||||
public boolean hasSelectClause() {
|
||||
if ("*".equals(trimmedProperties)) {
|
||||
// explicitly selected all properties
|
||||
return true;
|
||||
}
|
||||
// explicitly selected some properties
|
||||
return included != null || filterMany != null;
|
||||
return allProperties || included != null || filterMany != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the properties and configuration are empty.
|
||||
* Return true if explicit properties have been specified.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return rawProperties == null || rawProperties.isEmpty();
|
||||
boolean hasProperties() {
|
||||
return allProperties || included != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(40);
|
||||
append("", sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String append(String prefix, StringBuilder sb) {
|
||||
public void asStringDebug(String prefix, StringBuilder sb) {
|
||||
sb.append(prefix);
|
||||
if (path != null) {
|
||||
sb.append(path).append(" ");
|
||||
}
|
||||
if (!isEmpty()) {
|
||||
sb.append("(").append(rawProperties).append(")");
|
||||
if (allProperties) {
|
||||
sb.append("(*)");
|
||||
} else if (included != null) {
|
||||
sb.append("(").append(String.join(",", included)).append(")");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
boolean isChild(OrmQueryProperties possibleChild) {
|
||||
@@ -315,17 +278,11 @@ public class OrmQueryProperties implements Serializable {
|
||||
secondaryChildren.add(child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the raw properties.
|
||||
*/
|
||||
public String getProperties() {
|
||||
return rawProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this includes all properties on the path.
|
||||
*/
|
||||
public boolean allProperties() {
|
||||
// this is really "default" properties
|
||||
return included == null;
|
||||
}
|
||||
|
||||
@@ -350,10 +307,6 @@ public class OrmQueryProperties implements Serializable {
|
||||
includedBeanJoin.add(propertyName);
|
||||
}
|
||||
|
||||
public Set<String> getSelectInclude() {
|
||||
return included;
|
||||
}
|
||||
|
||||
public Set<String> getSelectQueryJoin() {
|
||||
return secondaryQueryJoins;
|
||||
}
|
||||
@@ -373,11 +326,9 @@ public class OrmQueryProperties implements Serializable {
|
||||
}
|
||||
|
||||
boolean isIncluded(String propName) {
|
||||
|
||||
if (includedBeanJoin != null && includedBeanJoin.contains(propName)) {
|
||||
return false;
|
||||
}
|
||||
// all properties included
|
||||
return included == null || included.contains(propName);
|
||||
}
|
||||
|
||||
@@ -392,53 +343,29 @@ public class OrmQueryProperties implements Serializable {
|
||||
* Return true if this path is a 'query join'.
|
||||
*/
|
||||
public boolean isQueryFetch() {
|
||||
return markForQueryJoin || getQueryFetchBatch() > -1;
|
||||
return markForQueryJoin || cache || fetchConfig.isQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this path is a 'fetch join'.
|
||||
*/
|
||||
boolean isFetchJoin() {
|
||||
return !isQueryFetch() && !isLazyFetch();
|
||||
return !markForQueryJoin && fetchConfig.isJoin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this path is a lazy fetch.
|
||||
*/
|
||||
boolean isLazyFetch() {
|
||||
return getLazyFetchBatch() > -1;
|
||||
return fetchConfig.isLazy();
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return fetchConfig.getBatchSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size to use for the query join.
|
||||
*/
|
||||
public int getQueryFetchBatch() {
|
||||
return fetchConfig.getQueryBatchSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a query join should eagerly fetch 'all' rather than the 'first'.
|
||||
*/
|
||||
public boolean isQueryFetchAll() {
|
||||
return fetchConfig.isQueryAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size to use for lazy loading.
|
||||
*/
|
||||
public int getLazyFetchBatch() {
|
||||
return fetchConfig.getLazyBatchSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this path has the +readonly option.
|
||||
*/
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this path has the +cache option to hit the cache.
|
||||
* Return true if this path should hit the L2 cache.
|
||||
*/
|
||||
public boolean isCache() {
|
||||
return cache;
|
||||
@@ -474,26 +401,24 @@ public class OrmQueryProperties implements Serializable {
|
||||
* Calculate the query plan hash.
|
||||
*/
|
||||
public void queryPlanHash(StringBuilder builder) {
|
||||
|
||||
builder.append("qpp[");
|
||||
builder.append(path);
|
||||
if (included != null){
|
||||
builder.append(" included:").append(included);
|
||||
builder.append("{");
|
||||
if (path != null) {
|
||||
builder.append(path);
|
||||
}
|
||||
if (included != null) {
|
||||
builder.append("/i").append(included);
|
||||
}
|
||||
if (secondaryQueryJoins != null) {
|
||||
builder.append(" secondary:").append(secondaryQueryJoins);
|
||||
builder.append("/s").append(secondaryQueryJoins);
|
||||
}
|
||||
|
||||
if (filterMany != null) {
|
||||
builder.append(" filterMany[");
|
||||
builder.append("/f");
|
||||
filterMany.queryPlanHash(builder);
|
||||
builder.append("]");
|
||||
}
|
||||
|
||||
if (fetchConfig != null) {
|
||||
builder.append(" config:").append(fetchConfig.hashCode());
|
||||
builder.append("/c").append(fetchConfig.hashCode());
|
||||
}
|
||||
builder.append("]");
|
||||
builder.append("}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-157
@@ -1,47 +1,28 @@
|
||||
package io.ebeaninternal.server.querydefn;
|
||||
|
||||
import io.ebean.FetchConfig;
|
||||
import io.ebeaninternal.server.util.DSelectColumnsParser;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Parses the path properties string.
|
||||
*/
|
||||
class OrmQueryPropertiesParser {
|
||||
final class OrmQueryPropertiesParser {
|
||||
|
||||
private static final Response EMPTY = new Response();
|
||||
private static final Response EMPTY = new Response(false, null);
|
||||
private static final Response ALL = new Response(true, null);
|
||||
|
||||
/**
|
||||
* Immutable response of the parsed properties and options.
|
||||
*/
|
||||
static class Response {
|
||||
|
||||
final boolean readOnly;
|
||||
final boolean cache;
|
||||
final FetchConfig fetchConfig;
|
||||
final String properties;
|
||||
final LinkedHashSet<String> included;
|
||||
final boolean allProperties;
|
||||
final Set<String> included;
|
||||
|
||||
Response(boolean readOnly, boolean cache, int queryFetchBatch, int lazyFetchBatch, String properties, LinkedHashSet<String> included) {
|
||||
this.readOnly = readOnly;
|
||||
this.cache = cache;
|
||||
this.properties = properties;
|
||||
private Response(boolean allProperties, Set<String> included) {
|
||||
this.allProperties = allProperties;
|
||||
this.included = included;
|
||||
if (lazyFetchBatch > -1 || queryFetchBatch > -1) {
|
||||
this.fetchConfig = new FetchConfig().lazy(lazyFetchBatch).query(queryFetchBatch);
|
||||
} else {
|
||||
this.fetchConfig = OrmQueryProperties.DEFAULT_FETCH;
|
||||
}
|
||||
}
|
||||
|
||||
Response() {
|
||||
this.readOnly = false;
|
||||
this.cache = false;
|
||||
this.fetchConfig = OrmQueryProperties.DEFAULT_FETCH;
|
||||
this.properties = "";
|
||||
this.included = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,145 +30,21 @@ class OrmQueryPropertiesParser {
|
||||
* Parses the path properties string returning the parsed properties and options.
|
||||
* In general it is comma delimited with some special strings like +lazy(20).
|
||||
*/
|
||||
public static Response parse(String rawProperties) {
|
||||
return new OrmQueryPropertiesParser(rawProperties).parse();
|
||||
}
|
||||
|
||||
private String inputProperties;
|
||||
|
||||
private String outputProperties = "";
|
||||
private boolean allProperties;
|
||||
private boolean readOnly;
|
||||
private boolean cache;
|
||||
private int queryFetchBatch = -1;
|
||||
private int lazyFetchBatch = -1;
|
||||
|
||||
private OrmQueryPropertiesParser(String inputProperties) {
|
||||
this.inputProperties = inputProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the raw string properties input.
|
||||
*/
|
||||
private Response parse() {
|
||||
|
||||
if (inputProperties == null || inputProperties.isEmpty()) {
|
||||
static Response parse(String rawProperties) {
|
||||
if (rawProperties == null || rawProperties.isEmpty()) {
|
||||
return EMPTY;
|
||||
}
|
||||
int pos = inputProperties.indexOf("+readonly");
|
||||
if (pos > -1) {
|
||||
inputProperties = inputProperties.replace("+readonly", "");
|
||||
readOnly = true;
|
||||
if (rawProperties.equals("*")) {
|
||||
return ALL;
|
||||
}
|
||||
pos = inputProperties.indexOf("+cache");
|
||||
if (pos > -1) {
|
||||
inputProperties = inputProperties.replace("+cache", "");
|
||||
cache = true;
|
||||
}
|
||||
pos = inputProperties.indexOf("+query");
|
||||
if (pos > -1) {
|
||||
queryFetchBatch = parseBatchHint(pos, "+query");
|
||||
}
|
||||
pos = inputProperties.indexOf("+lazy");
|
||||
if (pos > -1) {
|
||||
lazyFetchBatch = parseBatchHint(pos, "+lazy");
|
||||
}
|
||||
|
||||
LinkedHashSet<String> included = parseIncluded();
|
||||
String properties = (allProperties) ? "*" : outputProperties;
|
||||
return new Response(readOnly, cache, queryFetchBatch, lazyFetchBatch, properties, included);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the include separating by comma or semicolon.
|
||||
*/
|
||||
private LinkedHashSet<String> parseIncluded() {
|
||||
|
||||
inputProperties = inputProperties.trim();
|
||||
if (inputProperties.isEmpty()) {
|
||||
// default properties
|
||||
return null;
|
||||
}
|
||||
if (inputProperties.equals("*")) {
|
||||
// explicit all properties
|
||||
allProperties = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> res = splitRawSelect(inputProperties);
|
||||
|
||||
StringBuilder sb = new StringBuilder(70);
|
||||
LinkedHashSet<String> propertySet = new LinkedHashSet<>(res.size() * 2);
|
||||
|
||||
int count = 0;
|
||||
String temp;
|
||||
for (String re : res) {
|
||||
temp = re.trim();
|
||||
if (!temp.isEmpty()) {
|
||||
if (count > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(temp);
|
||||
propertySet.add(temp);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (propertySet.isEmpty()) {
|
||||
// default properties
|
||||
return null;
|
||||
}
|
||||
|
||||
if (propertySet.contains("*")) {
|
||||
// explicit all properties
|
||||
allProperties = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
// partial properties
|
||||
outputProperties = sb.toString();
|
||||
return propertySet;
|
||||
return new Response(false, splitRawSelect(rawProperties));
|
||||
}
|
||||
|
||||
/**
|
||||
* Split allowing 'dynamic function based properties'.
|
||||
*/
|
||||
private List<String> splitRawSelect(String inputProperties) {
|
||||
private static Set<String> splitRawSelect(String inputProperties) {
|
||||
return DSelectColumnsParser.parse(inputProperties);
|
||||
}
|
||||
|
||||
private int parseBatchHint(int pos, String option) {
|
||||
|
||||
int startPos = pos + option.length();
|
||||
int endPos = findEndPos(startPos, inputProperties);
|
||||
if (endPos == -1) {
|
||||
inputProperties = inputProperties.replace(option, "");
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
|
||||
String batchParam = inputProperties.substring(startPos + 1, endPos);
|
||||
|
||||
if (endPos + 1 >= inputProperties.length()) {
|
||||
inputProperties = inputProperties.substring(0, pos);
|
||||
} else {
|
||||
inputProperties = inputProperties.substring(0, pos) + inputProperties.substring(endPos + 1);
|
||||
}
|
||||
return Integer.parseInt(batchParam);
|
||||
}
|
||||
}
|
||||
|
||||
private int findEndPos(int pos, String props) {
|
||||
|
||||
if (pos < props.length()) {
|
||||
if (props.charAt(pos) == '(') {
|
||||
int endPara = props.indexOf(')', pos + 1);
|
||||
if (endPara == -1) {
|
||||
throw new RuntimeException("Error could not find ')' in " + props + " after position " + pos);
|
||||
}
|
||||
return endPara;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import io.ebeaninternal.server.util.DSelectColumnsParser;
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -28,11 +29,8 @@ final class DRawSqlColumnsParser {
|
||||
}
|
||||
|
||||
private ColumnMapping parse() {
|
||||
|
||||
List<String> columnList = DSelectColumnsParser.parse(sqlSelect);
|
||||
|
||||
Set<String> columnList = DSelectColumnsParser.parse(sqlSelect);
|
||||
List<ColumnMapping.Column> columns = new ArrayList<>(columnList.size());
|
||||
|
||||
for (String rawColumn : columnList) {
|
||||
columns.add(parseColumn(rawColumn));
|
||||
}
|
||||
@@ -40,7 +38,6 @@ final class DRawSqlColumnsParser {
|
||||
}
|
||||
|
||||
private ColumnMapping.Column parseColumn(String colInfo) {
|
||||
|
||||
String[] split = COLINFO_SPLIT.split(colInfo);
|
||||
if (split.length > 1) {
|
||||
ArrayList<String> tmp = new ArrayList<>(split.length);
|
||||
|
||||
@@ -10,9 +10,14 @@ import java.util.UUID;
|
||||
interface ArrayElementConverter<T> {
|
||||
|
||||
/**
|
||||
* Convert the array element to the logical type.
|
||||
* Convert element it's json serialized form.
|
||||
*/
|
||||
T toElement(Object rawValue);
|
||||
T fromSerialized(Object rawValue);
|
||||
|
||||
/**
|
||||
* Convert the array element from it's DB array form.
|
||||
*/
|
||||
T fromDbArray(Object rawValue);
|
||||
|
||||
default Object[] toDbArray(Object[] objects) {
|
||||
return objects;
|
||||
@@ -46,7 +51,12 @@ interface ArrayElementConverter<T> {
|
||||
class LongConverter implements ArrayElementConverter<Long> {
|
||||
|
||||
@Override
|
||||
public Long toElement(Object rawValue) {
|
||||
public Long fromSerialized(Object rawValue) {
|
||||
return fromDbArray(rawValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long fromDbArray(Object rawValue) {
|
||||
if (rawValue instanceof Long) {
|
||||
return (Long) rawValue;
|
||||
} else {
|
||||
@@ -58,7 +68,12 @@ interface ArrayElementConverter<T> {
|
||||
class IntegerConverter implements ArrayElementConverter<Integer> {
|
||||
|
||||
@Override
|
||||
public Integer toElement(Object rawValue) {
|
||||
public Integer fromSerialized(Object rawValue) {
|
||||
return ((Number) rawValue).intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer fromDbArray(Object rawValue) {
|
||||
if (rawValue instanceof Integer) {
|
||||
return (Integer) rawValue;
|
||||
} else {
|
||||
@@ -70,7 +85,12 @@ interface ArrayElementConverter<T> {
|
||||
class DoubleConverter implements ArrayElementConverter<Double> {
|
||||
|
||||
@Override
|
||||
public Double toElement(Object rawValue) {
|
||||
public Double fromSerialized(Object rawValue) {
|
||||
return fromDbArray(rawValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double fromDbArray(Object rawValue) {
|
||||
if (rawValue instanceof Double) {
|
||||
return (Double) rawValue;
|
||||
} else {
|
||||
@@ -82,21 +102,34 @@ interface ArrayElementConverter<T> {
|
||||
/**
|
||||
* String converter (noop based).
|
||||
*/
|
||||
class StringConverter extends NoopConverter<String> {
|
||||
class StringConverter implements ArrayElementConverter<String> {
|
||||
|
||||
public String fromDbArray(Object rawValue) {
|
||||
return (String) rawValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fromSerialized(Object rawValue) {
|
||||
return (String) rawValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* UUID converter (noop based).
|
||||
* UUID converter.
|
||||
*/
|
||||
class UuidConverter extends NoopConverter<UUID> {
|
||||
}
|
||||
class UuidConverter implements ArrayElementConverter<UUID> {
|
||||
|
||||
class NoopConverter<T> implements ArrayElementConverter<T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T toElement(Object rawValue) {
|
||||
return (T) rawValue;
|
||||
public java.util.UUID fromSerialized(Object rawValue) {
|
||||
return java.util.UUID.fromString((String)rawValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.util.UUID fromDbArray(Object rawValue) {
|
||||
if (rawValue instanceof UUID) {
|
||||
return (java.util.UUID) rawValue;
|
||||
}
|
||||
return java.util.UUID.fromString(rawValue.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +146,12 @@ interface ArrayElementConverter<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object toElement(Object rawValue) {
|
||||
public Object fromSerialized(Object rawValue) {
|
||||
return scalarType.parse((String) rawValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromDbArray(Object rawValue) {
|
||||
return scalarType.toBeanType(rawValue);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
import io.ebean.core.type.ScalarType;
|
||||
|
||||
public class ArrayElementConverterEnum implements ArrayElementConverter<String> {
|
||||
|
||||
final ScalarType<?> scalarType;
|
||||
|
||||
final Class<? extends Enum<?>> valueType1;
|
||||
|
||||
public ArrayElementConverterEnum(ScalarType<?> scalarType, Class<? extends Enum<?>> valueType1) {
|
||||
this.scalarType = scalarType;
|
||||
this.valueType1 = valueType1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toElement(Object rawValue) {
|
||||
// FIXME: Don't understand for what is this.
|
||||
Enum<?>[] enumConstants = valueType1.getEnumConstants();
|
||||
if (scalarType == null) {
|
||||
return rawValue.toString();
|
||||
}
|
||||
return scalarType.format(rawValue);
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@ public class ScalarTypeArrayList extends ScalarTypeArrayBase<List> implements Sc
|
||||
if (element == null) {
|
||||
list.add(null);
|
||||
} else {
|
||||
list.add(converter.toElement(element));
|
||||
list.add(converter.fromDbArray(element));
|
||||
}
|
||||
}
|
||||
return new ModifyAwareList(list);
|
||||
@@ -145,15 +145,27 @@ public class ScalarTypeArrayList extends ScalarTypeArrayBase<List> implements Sc
|
||||
@Override
|
||||
public List parse(String value) {
|
||||
try {
|
||||
return EJson.parseList(value, false);
|
||||
return convert(EJson.parseList(value, false));
|
||||
} catch (IOException e) {
|
||||
throw new TextException("Failed to parse JSON [{}] as List", value, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from the json types to the proper scalar types (uuid, enum, double etc)
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private List convert(List<Object> rawList) {
|
||||
List list = new ArrayList(rawList.size());
|
||||
for (Object rawVal : rawList) {
|
||||
list.add(converter.fromSerialized(rawVal));
|
||||
}
|
||||
return new ModifyAwareList(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List jsonRead(JsonParser parser) throws IOException {
|
||||
return EJson.parseList(parser, parser.getCurrentToken());
|
||||
return convert(EJson.parseList(parser, parser.getCurrentToken()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@@ -101,7 +102,7 @@ public class ScalarTypeArraySet extends ScalarTypeArrayBase<Set> implements Scal
|
||||
protected Set fromArray(Object[] array1) {
|
||||
Set set = new LinkedHashSet();
|
||||
for (Object element : array1) {
|
||||
set.add(converter.toElement(element));
|
||||
set.add(converter.fromDbArray(element));
|
||||
}
|
||||
return new ModifyAwareSet(set);
|
||||
}
|
||||
@@ -140,15 +141,26 @@ public class ScalarTypeArraySet extends ScalarTypeArrayBase<Set> implements Scal
|
||||
@Override
|
||||
public Set parse(String value) {
|
||||
try {
|
||||
return EJson.parseSet(value, false);
|
||||
return convert(EJson.parseList(value, false));
|
||||
} catch (IOException e) {
|
||||
throw new TextException("Failed to parse JSON [{}] as Set", value, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from the json types to the proper scalar types (uuid, enum, double etc)
|
||||
*/
|
||||
private Set convert(List<Object> rawList) {
|
||||
Set asSet = new LinkedHashSet();
|
||||
for (Object rawVal : rawList) {
|
||||
asSet.add(converter.fromSerialized(rawVal));
|
||||
}
|
||||
return new ModifyAwareSet(asSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set jsonRead(JsonParser parser) throws IOException {
|
||||
return EJson.parseSet(parser, parser.getCurrentToken());
|
||||
return convert(EJson.parseList(parser, parser.getCurrentToken()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,9 +37,10 @@ public class ScalarTypeJodaLocalDate extends ScalarTypeBaseDate<LocalDate> {
|
||||
return LocalDate.fromDateFields(date);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public Date convertToDate(LocalDate value) {
|
||||
return new java.sql.Date(convertToMillis(value));
|
||||
return new Date(value .getYear() - 1900, value .getMonthOfYear() - 1, value .getDayOfMonth());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,7 +54,7 @@ public class ScalarTypeJodaLocalDate extends ScalarTypeBaseDate<LocalDate> {
|
||||
@Override
|
||||
public LocalDate toBeanType(Object value) {
|
||||
if (value instanceof java.util.Date) {
|
||||
return convertFromMillis(((java.util.Date) value).getTime());
|
||||
return LocalDate.fromDateFields((java.util.Date)value);
|
||||
}
|
||||
return (LocalDate) value;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebeaninternal.server.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Splits a select clause into 'logical columns' taking into account functions and quotes.
|
||||
@@ -14,7 +14,7 @@ public final class DSelectColumnsParser {
|
||||
|
||||
private int pos;
|
||||
|
||||
public static List<String> parse(String sqlSelect) {
|
||||
public static Set<String> parse(String sqlSelect) {
|
||||
return new DSelectColumnsParser(sqlSelect).parse();
|
||||
}
|
||||
|
||||
@@ -23,9 +23,8 @@ public final class DSelectColumnsParser {
|
||||
this.end = selectClause.length();
|
||||
}
|
||||
|
||||
private List<String> parse() {
|
||||
|
||||
ArrayList<String> columns = new ArrayList<>();
|
||||
private Set<String> parse() {
|
||||
LinkedHashSet<String> columns = new LinkedHashSet<>();
|
||||
while (pos <= end) {
|
||||
columns.add(nextColumnInfo());
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
-- Generated by ebean unknown at 2020-12-07T09:40:50.461215Z
|
||||
-- Generated by ebean unknown at 2021-02-12T03:32:14.253435800Z
|
||||
create table asimple_bean (
|
||||
id bigint generated by default as identity not null,
|
||||
name varchar(255),
|
||||
@@ -486,6 +486,13 @@ create table child_person (
|
||||
constraint pk_child_person primary key (identifier)
|
||||
);
|
||||
|
||||
create table child_with_cache (
|
||||
id bigint generated by default as identity not null,
|
||||
name varchar(255),
|
||||
address varchar(255),
|
||||
constraint pk_child_with_cache primary key (id)
|
||||
);
|
||||
|
||||
create table cke_client (
|
||||
cod_cpny integer not null,
|
||||
cod_client varchar(100) not null,
|
||||
@@ -1168,6 +1175,12 @@ create table ebasic_json_unmapped (
|
||||
constraint pk_ebasic_json_unmapped primary key (id)
|
||||
);
|
||||
|
||||
create table e_basic_log (
|
||||
id bigint generated by default as identity not null,
|
||||
name varchar(255),
|
||||
constraint pk_e_basic_log primary key (id)
|
||||
);
|
||||
|
||||
create table e_basic_ndc (
|
||||
id integer generated by default as identity not null,
|
||||
name varchar(255),
|
||||
@@ -1227,6 +1240,14 @@ create table e_basic_with_ex (
|
||||
constraint pk_e_basic_with_ex primary key (id)
|
||||
);
|
||||
|
||||
create table e_basic_withlog (
|
||||
id bigint generated by default as identity not null,
|
||||
name varchar(255),
|
||||
deleted boolean default false not null,
|
||||
version bigint not null,
|
||||
constraint pk_e_basic_withlog primary key (id)
|
||||
);
|
||||
|
||||
create table e_basicverucon (
|
||||
id integer generated by default as identity not null,
|
||||
name varchar(127),
|
||||
@@ -2256,6 +2277,29 @@ create table looney (
|
||||
constraint pk_looney primary key (id)
|
||||
);
|
||||
|
||||
create table m2_mcache_child (
|
||||
id integer generated by default as identity not null,
|
||||
name varchar(255),
|
||||
constraint pk_m2_mcache_child primary key (id)
|
||||
);
|
||||
|
||||
create table m2_mcache_master (
|
||||
id integer generated by default as identity not null,
|
||||
constraint pk_m2_mcache_master primary key (id)
|
||||
);
|
||||
|
||||
create table m2mcache_set1 (
|
||||
m2_mcache_master_id integer not null,
|
||||
m2_mcache_child_id integer not null,
|
||||
constraint pk_m2mcache_set1 primary key (m2_mcache_master_id,m2_mcache_child_id)
|
||||
);
|
||||
|
||||
create table m2mcache_set2 (
|
||||
m2_mcache_master_id integer not null,
|
||||
m2_mcache_child_id integer not null,
|
||||
constraint pk_m2mcache_set2 primary key (m2_mcache_master_id,m2_mcache_child_id)
|
||||
);
|
||||
|
||||
create table maddress (
|
||||
id uuid not null,
|
||||
street varchar(255),
|
||||
@@ -3230,6 +3274,19 @@ create table e_save_test_c (
|
||||
constraint pk_e_save_test_c primary key (id)
|
||||
);
|
||||
|
||||
create table parent_a (
|
||||
id bigint generated by default as identity not null,
|
||||
child_id bigint,
|
||||
name varchar(255),
|
||||
constraint pk_parent_a primary key (id)
|
||||
);
|
||||
|
||||
create table parent_b (
|
||||
id bigint generated by default as identity not null,
|
||||
child_id bigint,
|
||||
constraint pk_parent_b primary key (id)
|
||||
);
|
||||
|
||||
create table parent_person (
|
||||
identifier integer generated by default as identity not null,
|
||||
name varchar(255),
|
||||
@@ -3361,6 +3418,15 @@ create table person_cache_info (
|
||||
constraint pk_person_cache_info primary key (person_id)
|
||||
);
|
||||
|
||||
create table persona (
|
||||
id bigint generated by default as identity not null,
|
||||
persona varchar(255),
|
||||
person_oid bigint,
|
||||
version integer not null,
|
||||
constraint uq_persona_person_oid unique (person_oid),
|
||||
constraint pk_persona primary key (id)
|
||||
);
|
||||
|
||||
create table phones (
|
||||
id bigint generated by default as identity not null,
|
||||
phone_number varchar(7) not null,
|
||||
@@ -4574,6 +4640,18 @@ alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute_at
|
||||
create index ix_looney_tune_id on looney (tune_id);
|
||||
alter table looney add constraint fk_looney_tune_id foreign key (tune_id) references tune (id) on delete restrict on update restrict;
|
||||
|
||||
create index ix_m2mcache_set1_m2_mcache_master on m2mcache_set1 (m2_mcache_master_id);
|
||||
alter table m2mcache_set1 add constraint fk_m2mcache_set1_m2_mcache_master foreign key (m2_mcache_master_id) references m2_mcache_master (id) on delete restrict on update restrict;
|
||||
|
||||
create index ix_m2mcache_set1_m2_mcache_child on m2mcache_set1 (m2_mcache_child_id);
|
||||
alter table m2mcache_set1 add constraint fk_m2mcache_set1_m2_mcache_child foreign key (m2_mcache_child_id) references m2_mcache_child (id) on delete restrict on update restrict;
|
||||
|
||||
create index ix_m2mcache_set2_m2_mcache_master on m2mcache_set2 (m2_mcache_master_id);
|
||||
alter table m2mcache_set2 add constraint fk_m2mcache_set2_m2_mcache_master foreign key (m2_mcache_master_id) references m2_mcache_master (id) on delete restrict on update restrict;
|
||||
|
||||
create index ix_m2mcache_set2_m2_mcache_child on m2mcache_set2 (m2_mcache_child_id);
|
||||
alter table m2mcache_set2 add constraint fk_m2mcache_set2_m2_mcache_child foreign key (m2_mcache_child_id) references m2_mcache_child (id) on delete restrict on update restrict;
|
||||
|
||||
create index ix_mcontact_customer_id on mcontact (customer_id);
|
||||
alter table mcontact add constraint fk_mcontact_customer_id foreign key (customer_id) references mcustomer (id) on delete restrict on update restrict;
|
||||
|
||||
@@ -4796,6 +4874,12 @@ alter table rawinherit_parent_rawinherit_data add constraint fk_rawinherit_paren
|
||||
create index ix_rawinherit_parent_rawinherit_data_rawinherit_data on rawinherit_parent_rawinherit_data (rawinherit_data_id);
|
||||
alter table rawinherit_parent_rawinherit_data add constraint fk_rawinherit_parent_rawinherit_data_rawinherit_data foreign key (rawinherit_data_id) references rawinherit_data (id) on delete restrict on update restrict;
|
||||
|
||||
create index ix_parent_a_child_id on parent_a (child_id);
|
||||
alter table parent_a add constraint fk_parent_a_child_id foreign key (child_id) references child_with_cache (id) on delete restrict on update restrict;
|
||||
|
||||
create index ix_parent_b_child_id on parent_b (child_id);
|
||||
alter table parent_b add constraint fk_parent_b_child_id foreign key (child_id) references child_with_cache (id) on delete restrict on update restrict;
|
||||
|
||||
create index ix_parent_person_some_bean_id on parent_person (some_bean_id);
|
||||
alter table parent_person add constraint fk_parent_person_some_bean_id foreign key (some_bean_id) references e_basic (id) on delete restrict on update restrict;
|
||||
|
||||
@@ -4829,6 +4913,8 @@ alter table person add constraint fk_person_default_address_oid foreign key (def
|
||||
create index ix_person_cache_email_person_info_person_id on person_cache_email (person_info_person_id);
|
||||
alter table person_cache_email add constraint fk_person_cache_email_person_info_person_id foreign key (person_info_person_id) references person_cache_info (person_id) on delete restrict on update restrict;
|
||||
|
||||
alter table persona add constraint fk_persona_person_oid foreign key (person_oid) references person (oid) on delete restrict on update restrict;
|
||||
|
||||
create index ix_phones_person_id on phones (person_id);
|
||||
alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id) on delete restrict on update restrict;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
-- Generated by ebean unknown at 2020-12-07T09:40:50.461215Z
|
||||
-- Generated by ebean unknown at 2021-02-12T03:32:14.253435800Z
|
||||
alter table bar drop constraint if exists fk_bar_foo_id;
|
||||
drop index if exists ix_bar_foo_id;
|
||||
|
||||
@@ -417,6 +417,18 @@ drop index if exists ix_la_attr_value_attribute_attribute;
|
||||
alter table looney drop constraint if exists fk_looney_tune_id;
|
||||
drop index if exists ix_looney_tune_id;
|
||||
|
||||
alter table m2mcache_set1 drop constraint if exists fk_m2mcache_set1_m2_mcache_master;
|
||||
drop index if exists ix_m2mcache_set1_m2_mcache_master;
|
||||
|
||||
alter table m2mcache_set1 drop constraint if exists fk_m2mcache_set1_m2_mcache_child;
|
||||
drop index if exists ix_m2mcache_set1_m2_mcache_child;
|
||||
|
||||
alter table m2mcache_set2 drop constraint if exists fk_m2mcache_set2_m2_mcache_master;
|
||||
drop index if exists ix_m2mcache_set2_m2_mcache_master;
|
||||
|
||||
alter table m2mcache_set2 drop constraint if exists fk_m2mcache_set2_m2_mcache_child;
|
||||
drop index if exists ix_m2mcache_set2_m2_mcache_child;
|
||||
|
||||
alter table mcontact drop constraint if exists fk_mcontact_customer_id;
|
||||
drop index if exists ix_mcontact_customer_id;
|
||||
|
||||
@@ -639,6 +651,12 @@ drop index if exists ix_rawinherit_parent_rawinherit_data_rawinherit_parent;
|
||||
alter table rawinherit_parent_rawinherit_data drop constraint if exists fk_rawinherit_parent_rawinherit_data_rawinherit_data;
|
||||
drop index if exists ix_rawinherit_parent_rawinherit_data_rawinherit_data;
|
||||
|
||||
alter table parent_a drop constraint if exists fk_parent_a_child_id;
|
||||
drop index if exists ix_parent_a_child_id;
|
||||
|
||||
alter table parent_b drop constraint if exists fk_parent_b_child_id;
|
||||
drop index if exists ix_parent_b_child_id;
|
||||
|
||||
alter table parent_person drop constraint if exists fk_parent_person_some_bean_id;
|
||||
drop index if exists ix_parent_person_some_bean_id;
|
||||
|
||||
@@ -672,6 +690,8 @@ drop index if exists ix_person_default_address_oid;
|
||||
alter table person_cache_email drop constraint if exists fk_person_cache_email_person_info_person_id;
|
||||
drop index if exists ix_person_cache_email_person_info_person_id;
|
||||
|
||||
alter table persona drop constraint if exists fk_persona_person_oid;
|
||||
|
||||
alter table phones drop constraint if exists fk_phones_person_id;
|
||||
drop index if exists ix_phones_person_id;
|
||||
|
||||
@@ -970,6 +990,8 @@ drop table if exists e_save_test_d;
|
||||
|
||||
drop table if exists child_person;
|
||||
|
||||
drop table if exists child_with_cache;
|
||||
|
||||
drop table if exists cke_client;
|
||||
|
||||
drop table if exists cke_user;
|
||||
@@ -1131,6 +1153,8 @@ drop table if exists ebasic_json_node_varchar;
|
||||
|
||||
drop table if exists ebasic_json_unmapped;
|
||||
|
||||
drop table if exists e_basic_log;
|
||||
|
||||
drop table if exists e_basic_ndc;
|
||||
|
||||
drop table if exists ebasic_no_sdchild;
|
||||
@@ -1145,6 +1169,8 @@ drop table if exists e_basic_withlife;
|
||||
|
||||
drop table if exists e_basic_with_ex;
|
||||
|
||||
drop table if exists e_basic_withlog;
|
||||
|
||||
drop table if exists e_basicverucon;
|
||||
|
||||
drop table if exists ecache_child;
|
||||
@@ -1463,6 +1489,14 @@ drop table if exists la_attr_value_attribute;
|
||||
|
||||
drop table if exists looney;
|
||||
|
||||
drop table if exists m2_mcache_child;
|
||||
|
||||
drop table if exists m2_mcache_master;
|
||||
|
||||
drop table if exists m2mcache_set1;
|
||||
|
||||
drop table if exists m2mcache_set2;
|
||||
|
||||
drop table if exists maddress;
|
||||
|
||||
drop table if exists mcontact;
|
||||
@@ -1715,6 +1749,10 @@ drop table if exists rawinherit_parent_rawinherit_data;
|
||||
|
||||
drop table if exists e_save_test_c;
|
||||
|
||||
drop table if exists parent_a;
|
||||
|
||||
drop table if exists parent_b;
|
||||
|
||||
drop table if exists parent_person;
|
||||
|
||||
drop table if exists c_participation;
|
||||
@@ -1745,6 +1783,8 @@ drop table if exists person_cache_email;
|
||||
|
||||
drop table if exists person_cache_info;
|
||||
|
||||
drop table if exists persona;
|
||||
|
||||
drop table if exists phones;
|
||||
|
||||
drop table if exists e_position;
|
||||
|
||||
@@ -8,151 +8,110 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class FetchConfigTest {
|
||||
|
||||
@Test
|
||||
public void testLazy() throws Exception {
|
||||
|
||||
public void testLazy() {
|
||||
FetchConfig config = new FetchConfig().lazy();
|
||||
|
||||
assertThat(config.getLazyBatchSize()).isEqualTo(0);
|
||||
assertThat(config.getQueryBatchSize()).isEqualTo(-1);
|
||||
assertThat(config.isQueryAll()).isEqualTo(false);
|
||||
assertThat(config.getBatchSize()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazy_withParameter() throws Exception {
|
||||
|
||||
public void testLazy_withParameter() {
|
||||
FetchConfig config = new FetchConfig().lazy(50);
|
||||
|
||||
assertThat(config.getLazyBatchSize()).isEqualTo(50);
|
||||
assertThat(config.getQueryBatchSize()).isEqualTo(-1);
|
||||
assertThat(config.isQueryAll()).isEqualTo(false);
|
||||
assertThat(config.getBatchSize()).isEqualTo(50);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuery() throws Exception {
|
||||
|
||||
public void testQuery() {
|
||||
FetchConfig config = new FetchConfig().query();
|
||||
|
||||
assertThat(config.getLazyBatchSize()).isEqualTo(-1);
|
||||
assertThat(config.getQueryBatchSize()).isEqualTo(0);
|
||||
assertThat(config.isQueryAll()).isEqualTo(true);
|
||||
assertThat(config.getBatchSize()).isEqualTo(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuery_withParameter() throws Exception {
|
||||
|
||||
public void testQuery_withParameter() {
|
||||
FetchConfig config = new FetchConfig().query(50);
|
||||
|
||||
assertThat(config.getLazyBatchSize()).isEqualTo(-1);
|
||||
assertThat(config.getQueryBatchSize()).isEqualTo(50);
|
||||
assertThat(config.isQueryAll()).isEqualTo(true);
|
||||
assertThat(config.getBatchSize()).isEqualTo(50);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryFirst() throws Exception {
|
||||
|
||||
public void testQueryFirst() {
|
||||
FetchConfig config = new FetchConfig().queryFirst(50);
|
||||
|
||||
assertThat(config.getLazyBatchSize()).isEqualTo(-1);
|
||||
assertThat(config.getQueryBatchSize()).isEqualTo(50);
|
||||
assertThat(config.isQueryAll()).isEqualTo(false);
|
||||
assertThat(config.getBatchSize()).isEqualTo(50);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryAndLazy_withParameters() throws Exception {
|
||||
|
||||
FetchConfig config = new FetchConfig().query(50).lazy(10);
|
||||
|
||||
assertThat(config.getLazyBatchSize()).isEqualTo(10);
|
||||
assertThat(config.getQueryBatchSize()).isEqualTo(50);
|
||||
assertThat(config.isQueryAll()).isEqualTo(false);
|
||||
public void testQueryAndLazy_withParameters() {
|
||||
FetchConfig config = FetchConfig.ofLazy(10);
|
||||
assertThat(config.getBatchSize()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryAndLazy() throws Exception {
|
||||
|
||||
FetchConfig config = new FetchConfig().query(50).lazy();
|
||||
|
||||
assertThat(config.getLazyBatchSize()).isEqualTo(0);
|
||||
assertThat(config.getQueryBatchSize()).isEqualTo(50);
|
||||
assertThat(config.isQueryAll()).isEqualTo(false);
|
||||
public void testQueryAndLazy() {
|
||||
FetchConfig config = FetchConfig.ofQuery(50);
|
||||
assertThat(config.getBatchSize()).isEqualTo(50);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEquals_when_noOptions() throws Exception {
|
||||
|
||||
public void testEquals_when_noOptions() {
|
||||
assertSame(new FetchConfig(), new FetchConfig());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals_when_query_50_lazy_40() throws Exception {
|
||||
|
||||
assertSame(new FetchConfig().query(50).lazy(40), new FetchConfig().query(50).lazy(40));
|
||||
public void testEquals_when_query_50_lazy_40() {
|
||||
assertSame(new FetchConfig().query(50), FetchConfig.ofQuery(50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals_when_query_50_lazy() throws Exception {
|
||||
|
||||
assertSame(new FetchConfig().query(50).lazy(), new FetchConfig().query(50).lazy());
|
||||
public void testEquals_when_query_50_lazy() {
|
||||
assertSame(new FetchConfig().lazy(), FetchConfig.ofLazy());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals_when_query_50() throws Exception {
|
||||
|
||||
public void testEquals_when_query_50() {
|
||||
assertSame(new FetchConfig().query(50), new FetchConfig().query(50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals_when_queryFirst_50_lazy_40() throws Exception {
|
||||
|
||||
assertSame(new FetchConfig().queryFirst(50).lazy(40), new FetchConfig().queryFirst(50).lazy(40));
|
||||
public void testEquals_when_queryFirst_50_lazy_40() {
|
||||
assertSame(new FetchConfig().queryFirst(50).lazy(40), FetchConfig.ofLazy(40));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals_when_queryFirst_50_lazy() throws Exception {
|
||||
|
||||
public void testEquals_when_queryFirst_50_lazy() {
|
||||
assertSame(new FetchConfig().queryFirst(50).lazy(), new FetchConfig().queryFirst(50).lazy());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals_when_queryFirst_50() throws Exception {
|
||||
|
||||
assertSame(new FetchConfig().queryFirst(50), new FetchConfig().queryFirst(50));
|
||||
public void testEquals_when_queryFirst_50() {
|
||||
assertSame(new FetchConfig().queryFirst(50), FetchConfig.ofQuery(50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEquals_when_query_50() throws Exception {
|
||||
|
||||
public void testNotEquals_when_query_50() {
|
||||
assertDifferent(new FetchConfig().query(50), new FetchConfig().query(40));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEquals_when_query_50_lazy() throws Exception {
|
||||
|
||||
public void testNotEquals_when_query_50_lazy() {
|
||||
assertDifferent(new FetchConfig().query(50), new FetchConfig().query(50).lazy());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEquals_when_query_50_lazy_40() throws Exception {
|
||||
|
||||
public void testNotEquals_when_query_50_lazy_40() {
|
||||
assertDifferent(new FetchConfig().query(50), new FetchConfig().query(50).lazy(40));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEquals_when_queryFirst_50() throws Exception {
|
||||
|
||||
public void testNotEquals_when_queryFirst_50() {
|
||||
assertDifferent(new FetchConfig().queryFirst(50), new FetchConfig().queryFirst(40));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEquals_when_queryFirst_50_lazy() throws Exception {
|
||||
|
||||
public void testNotEquals_when_queryFirst_50_lazy() {
|
||||
assertDifferent(new FetchConfig().queryFirst(50), new FetchConfig().queryFirst(50).lazy());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEquals_when_queryFirst_50_lazy_40() throws Exception {
|
||||
|
||||
public void testNotEquals_when_queryFirst_50_lazy_40() {
|
||||
assertDifferent(new FetchConfig().queryFirst(50), new FetchConfig().queryFirst(50).lazy(40));
|
||||
}
|
||||
|
||||
@@ -161,7 +120,6 @@ public class FetchConfigTest {
|
||||
assertThat(v1.hashCode()).isNotEqualTo(v2.hashCode());
|
||||
}
|
||||
|
||||
|
||||
void assertSame(FetchConfig v1, FetchConfig v2) {
|
||||
assertThat(v1).isEqualTo(v2);
|
||||
assertThat(v1.hashCode()).isEqualTo(v2.hashCode());
|
||||
|
||||
@@ -177,7 +177,7 @@ public class BeanTypeTest {
|
||||
beanType(Order.class).docStore().applyPath(orderQuery);
|
||||
|
||||
OrmQueryDetail detail = orderQuery.getDetail();
|
||||
assertThat(detail.getChunk("customer", false).getSelectInclude()).containsExactly("id", "name");
|
||||
assertThat(detail.getChunk("customer", false).getIncluded()).containsExactly("id", "name");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
|
||||
+7
-7
@@ -76,7 +76,7 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase {
|
||||
public void when_extra_queryFetchToMany_then_same() {
|
||||
|
||||
assertDifferent(detail(query().select("id,name").fetch("customer")),
|
||||
detail(query().select("id,name").fetch("customer").fetch("details", new FetchConfig().query())));
|
||||
detail(query().select("id,name").fetch("customer").fetch("details", FetchConfig.ofQuery())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -84,7 +84,7 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase {
|
||||
|
||||
// with the fetch of customer the foreign key must be added to the root query
|
||||
assertDifferent(detail(query().select("id,name")),
|
||||
detail(query().select("id,name").fetch("customer", new FetchConfig().query())));
|
||||
detail(query().select("id,name").fetch("customer", FetchConfig.ofQuery())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -99,7 +99,7 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase {
|
||||
|
||||
DefaultOrmQuery<Order> query1 = (DefaultOrmQuery<Order>) Ebean.find(Order.class)
|
||||
.select("status, shipDate")
|
||||
.fetch("details", "orderQty, unitPrice", new FetchConfig().query())
|
||||
.fetchQuery("details", "orderQty, unitPrice")
|
||||
.fetch("details.product", "sku, name");
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase {
|
||||
Query<Order> query = Ebean.find(Order.class)
|
||||
.select("status, orderDate")
|
||||
.fetch("customer", "name")
|
||||
.fetch("details", new FetchConfig().query());
|
||||
.fetchQuery("details");
|
||||
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query);
|
||||
OrmQueryDetail detail = queryRequest.getQuery().getDetail();
|
||||
@@ -173,7 +173,7 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase {
|
||||
Query<Order> query = Ebean.find(Order.class)
|
||||
.select("status, orderDate")
|
||||
.fetch("customer", "name")
|
||||
.fetch("details", new FetchConfig().lazy());
|
||||
.fetch("details", FetchConfig.ofLazy());
|
||||
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query);
|
||||
OrmQueryDetail detail = queryRequest.getQuery().getDetail();
|
||||
@@ -201,7 +201,7 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase {
|
||||
Query<Order> query = Ebean.find(Order.class)
|
||||
.select("status, orderDate")
|
||||
.fetch("customer", "name")
|
||||
.fetch("details", new FetchConfig().lazy())
|
||||
.fetchLazy("details")
|
||||
.fetch("details.product");
|
||||
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query);
|
||||
@@ -230,7 +230,7 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase {
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class)
|
||||
.select("status, orderDate")
|
||||
.fetch("details", new FetchConfig().query())
|
||||
.fetchQuery("details")
|
||||
.fetch("details.product")
|
||||
.fetch("customer", "name");
|
||||
|
||||
|
||||
@@ -624,7 +624,7 @@ public class EqlParserTest extends BaseTestCase {
|
||||
public void fetch_query50_asHint() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
Query<Customer> query = parse("fetch billingAddress (+query(50),city)");
|
||||
Query<Customer> query = parse("fetch query(50) billingAddress (city)");
|
||||
query.findList();
|
||||
|
||||
assertSql(query).doesNotContain(", t1.city");
|
||||
@@ -634,7 +634,7 @@ public class EqlParserTest extends BaseTestCase {
|
||||
public void fetch_lazy50_asHint() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
Query<Customer> query = parse("fetch billingAddress (+lazy(50),city) order by id");
|
||||
Query<Customer> query = parse("fetch lazy(50) billingAddress (city) order by id");
|
||||
List<Customer> list = query.findList();
|
||||
|
||||
assertSql(query).doesNotContain(", t1.city");
|
||||
|
||||
@@ -17,30 +17,26 @@ public class ParseFetchConfigTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseLazy() throws Exception {
|
||||
|
||||
public void parseLazy() {
|
||||
FetchConfig lazy = ParseFetchConfig.parse("lazy");
|
||||
assertThat(lazy.getLazyBatchSize()).isEqualTo(0);
|
||||
assertThat(lazy.getBatchSize()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseLazy100() throws Exception {
|
||||
|
||||
public void parseLazy100() {
|
||||
FetchConfig lazy = ParseFetchConfig.parse("lazy(100)");
|
||||
assertThat(lazy.getLazyBatchSize()).isEqualTo(100);
|
||||
assertThat(lazy.getBatchSize()).isEqualTo(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseQuery() throws Exception {
|
||||
|
||||
public void parseQuery() {
|
||||
FetchConfig lazy = ParseFetchConfig.parse("query");
|
||||
assertThat(lazy.getQueryBatchSize()).isEqualTo(0);
|
||||
assertThat(lazy.getBatchSize()).isEqualTo(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseQuery100() throws Exception {
|
||||
|
||||
public void parseQuery100() {
|
||||
FetchConfig lazy = ParseFetchConfig.parse("query(50)");
|
||||
assertThat(lazy.getQueryBatchSize()).isEqualTo(50);
|
||||
assertThat(lazy.getBatchSize()).isEqualTo(50);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-17
@@ -31,23 +31,20 @@ public class DLoadContextTest extends BaseTestCase {
|
||||
DLoadContext graphContext = (DLoadContext) queryRequest.getGraphContext();
|
||||
DLoadBeanContext customer = graphContext.getBeanContext("customer");
|
||||
|
||||
|
||||
assertThat(customer.firstBatchSize).isEqualTo(10);
|
||||
assertThat(customer.secondaryBatchSize).isEqualTo(10);
|
||||
assertThat(customer.batchSize).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void construct_when_fetchQuery_expect_100_batchSize() {
|
||||
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query().fetch("customer", new FetchConfig().query()));
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query().fetch("customer", FetchConfig.ofQuery()));
|
||||
queryRequest.initTransIfRequired();
|
||||
queryRequest.endTransIfRequired();
|
||||
|
||||
DLoadContext graphContext = (DLoadContext) queryRequest.getGraphContext();
|
||||
DLoadBeanContext customer = graphContext.getBeanContext("customer");
|
||||
|
||||
assertThat(customer.firstBatchSize).isEqualTo(100);
|
||||
assertThat(customer.secondaryBatchSize).isEqualTo(100);
|
||||
assertThat(customer.batchSize).isEqualTo(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -60,36 +57,33 @@ public class DLoadContextTest extends BaseTestCase {
|
||||
DLoadContext graphContext = (DLoadContext) queryRequest.getGraphContext();
|
||||
DLoadBeanContext customer = graphContext.getBeanContext("customer");
|
||||
|
||||
assertThat(customer.firstBatchSize).isEqualTo(100);
|
||||
assertThat(customer.secondaryBatchSize).isEqualTo(100);
|
||||
assertThat(customer.batchSize).isEqualTo(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void construct_when_fetchQuery50_expect_50_batchSize() {
|
||||
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query().fetch("customer", new FetchConfig().query(50)));
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query().fetch("customer", FetchConfig.ofQuery(50)));
|
||||
queryRequest.initTransIfRequired();
|
||||
queryRequest.endTransIfRequired();
|
||||
|
||||
DLoadContext graphContext = (DLoadContext) queryRequest.getGraphContext();
|
||||
DLoadBeanContext customer = graphContext.getBeanContext("customer");
|
||||
|
||||
assertThat(customer.firstBatchSize).isEqualTo(50);
|
||||
assertThat(customer.secondaryBatchSize).isEqualTo(50);
|
||||
assertThat(customer.batchSize).isEqualTo(50);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void construct_when_fetchQueryFirst20Lazy5_expect_20_5_batchSize() {
|
||||
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query().fetch("customer", new FetchConfig().queryFirst(20).lazy(5)));
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query().fetchQuery("customer"));
|
||||
queryRequest.initTransIfRequired();
|
||||
queryRequest.endTransIfRequired();
|
||||
|
||||
DLoadContext graphContext = (DLoadContext) queryRequest.getGraphContext();
|
||||
DLoadBeanContext customer = graphContext.getBeanContext("customer");
|
||||
|
||||
assertThat(customer.firstBatchSize).isEqualTo(20);
|
||||
assertThat(customer.secondaryBatchSize).isEqualTo(5);
|
||||
assertThat(customer.batchSize).isEqualTo(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -97,15 +91,14 @@ public class DLoadContextTest extends BaseTestCase {
|
||||
|
||||
BeanPropertyAssocMany<?> many = (BeanPropertyAssocMany<?>)getBeanDescriptor(Order.class).getBeanProperty("details");
|
||||
// the fetch is converted to a query join due to the maxRows
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query().fetch("details").setMaxRows(100));
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query().fetch("details").setMaxRows(50));
|
||||
queryRequest.initTransIfRequired();
|
||||
queryRequest.endTransIfRequired();
|
||||
|
||||
DLoadContext graphContext = (DLoadContext) queryRequest.getGraphContext();
|
||||
DLoadManyContext details = graphContext.getManyContext("details", many);
|
||||
|
||||
assertThat(details.firstBatchSize).isEqualTo(100);
|
||||
assertThat(details.secondaryBatchSize).isEqualTo(100);
|
||||
assertThat(details.batchSize).isEqualTo(100);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -92,7 +92,7 @@ public class OrmQueryDetailParserTest extends BaseTestCase {
|
||||
OrmQueryProperties chunk = detail.getChunk("customer", false);
|
||||
assertThat(chunk.getPath()).isEqualTo("customer");
|
||||
assertThat(chunk.getIncluded()).contains("id", "name", "email");
|
||||
assertThat(chunk.isQueryFetch()).isTrue();
|
||||
//FIXME: assertThat(chunk.isQueryFetch()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -110,7 +110,7 @@ public class OrmQueryDetailParserTest extends BaseTestCase {
|
||||
OrmQueryProperties chunk = detail.getChunk("customer", false);
|
||||
assertThat(chunk.getPath()).isEqualTo("customer");
|
||||
assertThat(chunk.getIncluded()).contains("id", "name", "email");
|
||||
assertThat(chunk.isQueryFetch()).isTrue();
|
||||
//FIXME: assertThat(chunk.isQueryFetch()).isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+18
-86
@@ -11,121 +11,53 @@ public class OrmQueryPropertiesParserTest {
|
||||
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse(null);
|
||||
assertAllDefaults(res);
|
||||
assertThat(res.properties).isEqualTo("");
|
||||
assertThat(res.allProperties).isFalse();
|
||||
assertThat(res.included).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_empty() throws Exception {
|
||||
public void when_empty() {
|
||||
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("");
|
||||
assertAllDefaults(res);
|
||||
assertThat(res.properties).isEqualTo("");
|
||||
assertThat(res.allProperties).isFalse();
|
||||
assertThat(res.included).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_hasStar() throws Exception {
|
||||
public void when_hasStar() {
|
||||
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("*");
|
||||
assertAllDefaults(res);
|
||||
assertThat(res.properties).isEqualTo("*");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_hasCache() throws Exception {
|
||||
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+cache");
|
||||
assertThat(res.cache).isTrue();
|
||||
assertThat(res.allProperties).isTrue();
|
||||
assertThat(res.included).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_hasCache_first() throws Exception {
|
||||
public void when_no_spaces() {
|
||||
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+cache,id");
|
||||
assertThat(res.cache).isTrue();
|
||||
assertThat(res.included).containsExactly("id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_hasCache_last() throws Exception {
|
||||
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("name,+cache");
|
||||
assertThat(res.cache).isTrue();
|
||||
assertThat(res.included).containsExactly("name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_hasCache_middle() throws Exception {
|
||||
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("name,+cache, id");
|
||||
assertThat(res.cache).isTrue();
|
||||
assertThat(res.included).containsExactly("name", "id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_hasReadOnly() throws Exception {
|
||||
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+readonly");
|
||||
assertThat(res.readOnly).isTrue();
|
||||
assertThat(res.included).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_hasLazy() throws Exception {
|
||||
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+lazy");
|
||||
assertThat(res.fetchConfig.getLazyBatchSize()).isEqualTo(0);
|
||||
assertThat(res.included).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_hasLazyValue() throws Exception {
|
||||
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+lazy(20)");
|
||||
assertThat(res.fetchConfig.getLazyBatchSize()).isEqualTo(20);
|
||||
assertThat(res.included).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_hasLazyValue_last() throws Exception {
|
||||
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("name,+lazy(20)");
|
||||
assertThat(res.fetchConfig.getLazyBatchSize()).isEqualTo(20);
|
||||
assertThat(res.included).containsExactly("name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_hasLazyValue_first() throws Exception {
|
||||
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+lazy(20),id,name");
|
||||
assertThat(res.fetchConfig.getLazyBatchSize()).isEqualTo(20);
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("id,name");
|
||||
assertThat(res.allProperties).isFalse();
|
||||
assertThat(res.included).containsExactly("id", "name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_allProperties() throws Exception {
|
||||
public void when_spaced() {
|
||||
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+query(4),+lazy(5)");
|
||||
assertThat(res.fetchConfig.getLazyBatchSize()).isEqualTo(5);
|
||||
assertThat(res.included).isNull();
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("id, name");
|
||||
assertThat(res.allProperties).isFalse();
|
||||
assertThat(res.included).containsExactly("id", "name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_everything_set() throws Exception {
|
||||
public void when_formula() {
|
||||
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("id, name +readonly +lazy(20) +query(30) +cache");
|
||||
assertThat(res.fetchConfig.getLazyBatchSize()).isEqualTo(20);
|
||||
assertThat(res.fetchConfig.getQueryBatchSize()).isEqualTo(30);
|
||||
assertThat(res.readOnly).isTrue();
|
||||
assertThat(res.cache).isTrue();
|
||||
assertThat(res.included).containsExactly("id", "name");
|
||||
OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("a,MD5(id::text) as b,c");
|
||||
assertThat(res.allProperties).isFalse();
|
||||
assertThat(res.included).containsExactly("a", "MD5(id::text) as b", "c");
|
||||
}
|
||||
|
||||
private void assertAllDefaults(OrmQueryPropertiesParser.Response res) {
|
||||
assertThat(res.cache).isFalse();
|
||||
assertThat(res.readOnly).isFalse();
|
||||
assertThat(res.fetchConfig.getLazyBatchSize()).isEqualTo(-1);
|
||||
assertThat(res.fetchConfig.getQueryBatchSize()).isEqualTo(-1);
|
||||
assertThat(res.included).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
+8
-13
@@ -10,21 +10,16 @@ public class OrmQueryPropertiesTest {
|
||||
|
||||
String append(String prefix, OrmQueryProperties p1) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
p1.append(prefix, sb);
|
||||
p1.asStringDebug(prefix, sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void construct_with_propertySet_when_null() {
|
||||
new OrmQueryProperties(null, (LinkedHashSet<String>) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void construct_with_propertySet_when_empty() {
|
||||
|
||||
OrmQueryProperties p1 = new OrmQueryProperties(null, new LinkedHashSet<>());
|
||||
assertThat(p1.getProperties()).isEqualTo("");
|
||||
assertThat(p1.allProperties()).isFalse();
|
||||
assertThat(p1.getIncluded()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -34,7 +29,7 @@ public class OrmQueryPropertiesTest {
|
||||
set.add("name");
|
||||
OrmQueryProperties p1 = new OrmQueryProperties(null, set);
|
||||
|
||||
assertThat(p1.getProperties()).isEqualTo("name");
|
||||
assertThat(p1.getIncluded()).containsOnly("name");
|
||||
assertThat(p1.allProperties()).isFalse();
|
||||
}
|
||||
|
||||
@@ -47,7 +42,7 @@ public class OrmQueryPropertiesTest {
|
||||
set.add("startDate");
|
||||
OrmQueryProperties p1 = new OrmQueryProperties(null, set);
|
||||
|
||||
assertThat(p1.getProperties()).isEqualTo("id,name,startDate");
|
||||
assertThat(p1.getIncluded()).containsOnly("id", "name", "startDate");
|
||||
assertThat(p1.allProperties()).isFalse();
|
||||
}
|
||||
|
||||
@@ -68,8 +63,8 @@ public class OrmQueryPropertiesTest {
|
||||
@Test
|
||||
public void append_when_somePropertiesWithOptions() {
|
||||
|
||||
OrmQueryProperties p1 = new OrmQueryProperties(null, "id,name +cache");
|
||||
assertThat(append("select ", p1)).isEqualTo("select (id,name +cache)");
|
||||
OrmQueryProperties p1 = new OrmQueryProperties(null, "id,name,+cache");
|
||||
//FIXME: assertThat(append("select ", p1)).isEqualTo("select (id,name,+cache)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -82,8 +77,8 @@ public class OrmQueryPropertiesTest {
|
||||
@Test
|
||||
public void append_when_path_and_somePropertiesWithOptions() {
|
||||
|
||||
OrmQueryProperties p1 = new OrmQueryProperties("customer", "id,name +cache");
|
||||
assertThat(append("fetch ", p1)).isEqualTo("fetch customer (id,name +cache)");
|
||||
OrmQueryProperties p1 = new OrmQueryProperties("customer", "id,name,+cache");
|
||||
//FIXME: assertThat(append("fetch ", p1)).isEqualTo("fetch customer (id,name,+cache)");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.text.json.EJson;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -63,4 +68,82 @@ public class ScalarTypeArrayListTest extends BasePlatformArrayTypeFactoryTest {
|
||||
assertBindNullTo_Null(factory.typeFor(UUID.class, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void parse_withUuidType_expect_uuidTypeReturned() {
|
||||
|
||||
ScalarType<?> scalarType = factory.typeFor(UUID.class, true);
|
||||
|
||||
List<UUID> input = new ArrayList<>();
|
||||
input.add(UUID.randomUUID());
|
||||
input.add(UUID.randomUUID());
|
||||
|
||||
String formatToJson = scalarType.format(input);
|
||||
|
||||
Object parsed = scalarType.parse(formatToJson);
|
||||
assertThat(parsed).isEqualTo(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void parse_withIntegerType_expect_longIntegerReturned() {
|
||||
|
||||
ScalarType<?> scalarType = factory.typeFor(Integer.class, true);
|
||||
|
||||
List<Integer> input = new ArrayList<>();
|
||||
input.add(2);
|
||||
input.add(4);
|
||||
|
||||
String formatToJson = scalarType.format(input);
|
||||
|
||||
Object parsed = scalarType.parse(formatToJson);
|
||||
assertThat(parsed).isEqualTo(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void parse_withLongType_expect_longTypeReturned() {
|
||||
|
||||
ScalarType<?> scalarType = factory.typeFor(Long.class, true);
|
||||
|
||||
List<Long> input = new ArrayList<>();
|
||||
input.add(2L);
|
||||
input.add(4L);
|
||||
|
||||
String formatToJson = scalarType.format(input);
|
||||
|
||||
Object parsed = scalarType.parse(formatToJson);
|
||||
assertThat(parsed).isEqualTo(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parse_withDoubleType_expect_longTypeReturned() {
|
||||
|
||||
ScalarType<?> scalarType = factory.typeFor(Double.class, true);
|
||||
|
||||
List<Double> input = new ArrayList<>();
|
||||
input.add(2D);
|
||||
input.add(4D);
|
||||
|
||||
String formatToJson = scalarType.format(input);
|
||||
|
||||
Object parsed = scalarType.parse(formatToJson);
|
||||
assertThat(parsed).isEqualTo(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonRead_withUuidType() throws IOException {
|
||||
|
||||
ScalarType<?> scalarType = factory.typeFor(UUID.class, true);
|
||||
|
||||
List<UUID> input = new ArrayList<>();
|
||||
input.add(UUID.randomUUID());
|
||||
input.add(UUID.randomUUID());
|
||||
String asJson = EJson.write(input);
|
||||
|
||||
JsonParser parser = DB.json().createParser(new StringReader(asJson));
|
||||
|
||||
Object parsed = scalarType.jsonRead(parser);
|
||||
assertThat(parsed).isEqualTo(input);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.text.json.EJson;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -49,4 +57,82 @@ public class ScalarTypeArraySetH2Test extends BasePlatformArrayTypeFactoryTest {
|
||||
assertBindNullTo_Null(factory.typeFor(UUID.class, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void parse_withUuidType_expect_uuidTypeReturned() {
|
||||
|
||||
ScalarType<?> scalarType = factory.typeFor(UUID.class, true);
|
||||
|
||||
Set<UUID> input = new LinkedHashSet<>();
|
||||
input.add(UUID.randomUUID());
|
||||
input.add(UUID.randomUUID());
|
||||
|
||||
String formatToJson = scalarType.format(input);
|
||||
|
||||
Set<UUID> parsed = (Set<UUID>)scalarType.parse(formatToJson);
|
||||
assertThat(parsed).isEqualTo(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void parse_withIntegerType_expect_longIntegerReturned() {
|
||||
|
||||
ScalarType<?> scalarType = factory.typeFor(Integer.class, true);
|
||||
|
||||
Set<Integer> input = new LinkedHashSet<>();
|
||||
input.add(2);
|
||||
input.add(4);
|
||||
|
||||
String formatToJson = scalarType.format(input);
|
||||
|
||||
Set<Integer> parsed = (Set<Integer>)scalarType.parse(formatToJson);
|
||||
assertThat(parsed).isEqualTo(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void parse_withLongType_expect_longTypeReturned() {
|
||||
|
||||
ScalarType<?> scalarType = factory.typeFor(Long.class, true);
|
||||
|
||||
Set<Long> input = new LinkedHashSet<>();
|
||||
input.add(2L);
|
||||
input.add(4L);
|
||||
|
||||
String formatToJson = scalarType.format(input);
|
||||
|
||||
Set<Long> parsed = (Set<Long>)scalarType.parse(formatToJson);
|
||||
assertThat(parsed).isEqualTo(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parse_withDoubleType_expect_longTypeReturned() {
|
||||
|
||||
ScalarType<?> scalarType = factory.typeFor(Double.class, true);
|
||||
|
||||
Set<Double> input = new LinkedHashSet<>();
|
||||
input.add(2D);
|
||||
input.add(4D);
|
||||
|
||||
String formatToJson = scalarType.format(input);
|
||||
|
||||
Object parsed = scalarType.parse(formatToJson);
|
||||
assertThat(parsed).isEqualTo(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonRead_withUuidType() throws IOException {
|
||||
|
||||
ScalarType<?> scalarType = factory.typeFor(UUID.class, true);
|
||||
|
||||
Set<UUID> input = new LinkedHashSet<>();
|
||||
input.add(UUID.randomUUID());
|
||||
input.add(UUID.randomUUID());
|
||||
String asJson = EJson.write(input);
|
||||
|
||||
JsonParser parser = DB.json().createParser(new StringReader(asJson));
|
||||
|
||||
Object parsed = scalarType.jsonRead(parser);
|
||||
assertThat(parsed).isEqualTo(input);
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -6,6 +6,7 @@ import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -24,12 +25,29 @@ public class ScalarTypeJodaLocalDateTest {
|
||||
assertThat(localDate).isEqualTo(localDate1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertToDate_convertFromDate_westOfUtc() {
|
||||
final TimeZone originaDefaultTimezone = TimeZone.getDefault();
|
||||
try {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago"));
|
||||
|
||||
convertDate(new LocalDate());
|
||||
convertDate(new LocalDate(1899, 12, 1));
|
||||
convertDate(new LocalDate(1900, 1, 1));
|
||||
convertDate(new LocalDate(2021, 2, 8));
|
||||
|
||||
} finally {
|
||||
TimeZone.setDefault(originaDefaultTimezone);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertToDate_convertFromDate() {
|
||||
|
||||
convertDate(new LocalDate());
|
||||
convertDate(new LocalDate(1899, 12, 1));
|
||||
convertDate(new LocalDate(1900, 1, 1));
|
||||
convertDate(new LocalDate(2021, 2, 8));
|
||||
}
|
||||
|
||||
private void convertDate(LocalDate localDate) {
|
||||
|
||||
@@ -2,7 +2,7 @@ package io.ebeaninternal.server.util;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -11,49 +11,49 @@ public class DSelectColumnsParserTest {
|
||||
@Test
|
||||
public void parse() {
|
||||
|
||||
List<String> cols = DSelectColumnsParser.parse("a,MD5(id::text) as b,c");
|
||||
Set<String> cols = DSelectColumnsParser.parse("a,MD5(id::text) as b,c");
|
||||
assertThat(cols).containsExactly("a", "MD5(id::text) as b", "c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whitespace_is_trimmed() {
|
||||
|
||||
List<String> cols = DSelectColumnsParser.parse("a , MD5(id::text) as b , c ");
|
||||
Set<String> cols = DSelectColumnsParser.parse("a , MD5(id::text) as b , c ");
|
||||
assertThat(cols).containsExactly("a", "MD5(id::text) as b", "c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedFunctions() {
|
||||
|
||||
List<String> cols = DSelectColumnsParser.parse("a , concat(id,'sd',inner(foo)) as b , c ");
|
||||
Set<String> cols = DSelectColumnsParser.parse("a , concat(id,'sd',inner(foo)) as b , c ");
|
||||
assertThat(cols).containsExactly("a", "concat(id,'sd',inner(foo)) as b", "c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basic() {
|
||||
|
||||
List<String> cols = DSelectColumnsParser.parse("name , status , billingAddress ");
|
||||
Set<String> cols = DSelectColumnsParser.parse("name , status , billingAddress ");
|
||||
assertThat(cols).containsExactly("name", "status", "billingAddress");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basic_noWhitespace() {
|
||||
|
||||
List<String> cols = DSelectColumnsParser.parse("a,b,c");
|
||||
Set<String> cols = DSelectColumnsParser.parse("a,b,c");
|
||||
assertThat(cols).containsExactly("a", "b", "c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formula_noWhitespace() {
|
||||
|
||||
List<String> cols = DSelectColumnsParser.parse("a,concat(x,y),c");
|
||||
Set<String> cols = DSelectColumnsParser.parse("a,concat(x,y),c");
|
||||
assertThat(cols).containsExactly("a", "concat(x,y)", "c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void with_logicalCast_andAsAlias() {
|
||||
|
||||
List<String> cols = DSelectColumnsParser.parse("name , concat(status,'-end')::String as fullName , billingAddress ");
|
||||
Set<String> cols = DSelectColumnsParser.parse("name , concat(status,'-end')::String as fullName , billingAddress ");
|
||||
assertThat(cols).containsExactly("name", "concat(status,'-end')::String as fullName", "billingAddress");
|
||||
}
|
||||
|
||||
|
||||
@@ -144,6 +144,69 @@ public class TestAnnotationBase extends BaseTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class TestJakartaAnnotationBaseEntity extends MappedBaseEntity {
|
||||
@Where(clause = "SELECT 'mysql' from 1", platforms = Platform.MYSQL)
|
||||
@Where(clause = "SELECT 'h2' from 1", platforms = H2)
|
||||
@Where(clause = "SELECT 'other' from 1")
|
||||
private String direct;
|
||||
|
||||
@MetaTest
|
||||
private String meta;
|
||||
|
||||
@MetaTest
|
||||
@Where(clause = "SELECT 'oracle' from 1", platforms = Platform.ORACLE)
|
||||
private String mixed;
|
||||
|
||||
@jakarta.validation.constraints.Size.List({
|
||||
@jakarta.validation.constraints.Size(max = 10, message = "max length for you is 10"),
|
||||
@jakarta.validation.constraints.Size(min = 1),
|
||||
@jakarta.validation.constraints.Size(max = 40, message = "max value for you is 40", groups = ValidationGroupSomething.class)
|
||||
})
|
||||
private String constraintAnnotation;
|
||||
|
||||
@NotNull
|
||||
private String null1;
|
||||
|
||||
|
||||
@NotNull(groups = ValidationGroupSomething.class)
|
||||
private String null2;
|
||||
|
||||
private String null3;
|
||||
|
||||
public String getConstraintAnnotation() {
|
||||
return constraintAnnotation;
|
||||
}
|
||||
|
||||
public void setConstraintAnnotation(String constraintAnnotation) {
|
||||
this.constraintAnnotation = constraintAnnotation;
|
||||
}
|
||||
|
||||
public String getNull1() {
|
||||
return null1;
|
||||
}
|
||||
|
||||
public void setNull1(String null1) {
|
||||
this.null1 = null1;
|
||||
}
|
||||
|
||||
public String getNull2() {
|
||||
return null2;
|
||||
}
|
||||
|
||||
public void setNull2(String null2) {
|
||||
this.null2 = null2;
|
||||
}
|
||||
|
||||
public String getNull3() {
|
||||
return null3;
|
||||
}
|
||||
|
||||
public void setNull3(String null3) {
|
||||
this.null3 = null3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindMaxSize() throws SecurityException {
|
||||
@@ -152,6 +215,13 @@ public class TestAnnotationBase extends BaseTestCase {
|
||||
assertEquals(40, bp.getDbLength());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindJakartaMaxSize() throws SecurityException {
|
||||
BeanDescriptor<TestJakartaAnnotationBaseEntity> descriptor = spiEbeanServer().getBeanDescriptor(TestJakartaAnnotationBaseEntity.class);
|
||||
BeanProperty bp = descriptor.findProperty("constraintAnnotation");
|
||||
assertEquals(40, bp.getDbLength());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void annotationClassIndexes() throws SecurityException {
|
||||
BeanDescriptor<TestAnnotationBaseEntity> descriptor = spiEbeanServer().getBeanDescriptor(TestAnnotationBaseEntity.class);
|
||||
@@ -173,6 +243,20 @@ public class TestAnnotationBase extends BaseTestCase {
|
||||
assertTrue(bp.isNullable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJakartaNotNullWithGroup() throws SecurityException {
|
||||
BeanDescriptor<TestJakartaAnnotationBaseEntity> descriptor = spiEbeanServer().getBeanDescriptor(TestJakartaAnnotationBaseEntity.class);
|
||||
|
||||
BeanProperty bp = descriptor.findProperty("null1");
|
||||
assertFalse(bp.isNullable());
|
||||
|
||||
bp = descriptor.findProperty("null2");
|
||||
assertTrue(bp.isNullable());
|
||||
|
||||
bp = descriptor.findProperty("null3");
|
||||
assertTrue(bp.isNullable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAnnotation() throws NoSuchFieldException, SecurityException {
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ public class TestManyOneInterface extends BaseTestCase {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
IAddress a = new Address();
|
||||
IAddress a = new Address("hello");
|
||||
|
||||
IPerson p = new Person();
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package org.tests.basic.lob;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Query;
|
||||
import org.tests.model.basic.EBasicClobNoVer;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
@@ -21,53 +19,50 @@ public class TestBasicClobNoVer extends BaseTestCase {
|
||||
EBasicClobNoVer entity = new EBasicClobNoVer();
|
||||
entity.setName("test");
|
||||
entity.setDescription("initialClobValue");
|
||||
EbeanServer server = Ebean.getServer(null);
|
||||
server.save(entity);
|
||||
|
||||
|
||||
String sqlNoClob = "select t0.id, t0.name from ebasic_clob_no_ver t0 where t0.id = ?";
|
||||
String sqlWithClob = "select t0.id, t0.name, t0.description from ebasic_clob_no_ver t0 where t0.id = ?";
|
||||
|
||||
DB.save(entity);
|
||||
|
||||
// Clob by default is Fetch Lazy
|
||||
Query<EBasicClobNoVer> defaultQuery = Ebean.find(EBasicClobNoVer.class).setId(entity.getId());
|
||||
Query<EBasicClobNoVer> defaultQuery = DB.find(EBasicClobNoVer.class).setId(entity.getId());
|
||||
defaultQuery.findOne();
|
||||
String sql = sqlOf(defaultQuery, 2);
|
||||
|
||||
Assert.assertTrue("Clob is fetch lazy by default", sql.contains(sqlNoClob));
|
||||
// default SQL select excludes clob
|
||||
String sqlNoClob = "select t0.id, t0.name from ebasic_clob_no_ver t0 where t0.id = ?";
|
||||
assertThat(sql).contains(sqlNoClob);
|
||||
|
||||
|
||||
// Explicitly select * including Clob
|
||||
Query<EBasicClobNoVer> explicitQuery = Ebean.find(EBasicClobNoVer.class).setId(entity.getId()).select("*");
|
||||
Query<EBasicClobNoVer> explicitQuery = DB.find(EBasicClobNoVer.class).setId(entity.getId()).select("*");
|
||||
|
||||
explicitQuery.findOne();
|
||||
sql = sqlOf(explicitQuery, 2);
|
||||
|
||||
Assert.assertTrue("Explicitly include Clob", sql.contains(sqlWithClob));
|
||||
// Explicitly include Clob
|
||||
String sqlWithClob = "select t0.id, t0.name, t0.description from ebasic_clob_no_ver t0 where t0.id = ?";
|
||||
assertThat(sql).contains(sqlWithClob);
|
||||
|
||||
// Update description to test refresh
|
||||
|
||||
EBasicClobNoVer updateBean = new EBasicClobNoVer();
|
||||
updateBean.setId(entity.getId());
|
||||
updateBean.setDescription("modified");
|
||||
Ebean.update(updateBean);
|
||||
DB.update(updateBean);
|
||||
|
||||
|
||||
// Test refresh function
|
||||
|
||||
Assert.assertEquals("initialClobValue", entity.getDescription());
|
||||
assertThat(entity.getDescription()).isEqualTo("initialClobValue");
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
// Refresh query includes all properties
|
||||
server.refresh(entity);
|
||||
DB.refresh(entity);
|
||||
|
||||
// Assert all properties fetched in refresh
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
Assert.assertEquals(1, loggedSql.size());
|
||||
assertThat(loggedSql).hasSize(1);
|
||||
assertThat(trimSql(loggedSql.get(0), 2)).contains(sqlWithClob);
|
||||
Assert.assertEquals("modified", entity.getDescription());
|
||||
|
||||
assertThat(entity.getDescription()).isEqualTo("modified");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ public class TestBasicLazy extends BaseTestCase {
|
||||
new FetchThread(tg, 2).start();
|
||||
new FetchThread(tg, 3).start();
|
||||
|
||||
orders = Ebean.find(Order.class).fetch("customer", new FetchConfig().lazy(100)).findList();
|
||||
orders = Ebean.find(Order.class).fetchLazy("customer").findList();
|
||||
Assert.assertTrue(orders.size() >= 4);
|
||||
|
||||
try {
|
||||
|
||||
@@ -44,7 +44,7 @@ public class TestBatchLazyWithDeleted extends BaseTestCase {
|
||||
Ebean.save(twoC);
|
||||
|
||||
List<UUTwo> list = Ebean.find(UUTwo.class)
|
||||
.fetch("master", new FetchConfig().lazy(5))
|
||||
.fetchLazy("master")
|
||||
.where().startsWith("name", "two-bld-")
|
||||
.order("name")
|
||||
.findList();
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
package org.tests.batchload;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.BeanState;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
public class TestBeanState extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
List<Customer> custs = DB.find(Customer.class).findList();
|
||||
|
||||
Customer customer = DB.find(Customer.class).setId(custs.get(0).getId()).select("name")
|
||||
.setUseCache(false)
|
||||
.findOne();
|
||||
|
||||
BeanState beanState = DB.getBeanState(customer);
|
||||
assertFalse(beanState.isNew());
|
||||
assertFalse(beanState.isDirty());
|
||||
assertFalse(beanState.isNewOrDirty());
|
||||
assertNotNull(beanState.getLoadedProps());
|
||||
|
||||
customer.setName("dirtyNameProp");
|
||||
assertTrue(beanState.isDirty());
|
||||
assertThat(beanState.getChangedProps()).containsOnly("name");
|
||||
|
||||
EntityBeanIntercept ebi = ((EntityBean) customer)._ebean_getIntercept();
|
||||
boolean[] dirtyProperties = ebi.getDirtyProperties();
|
||||
for (int i = 0; i < dirtyProperties.length; i++) {
|
||||
if (dirtyProperties[i]) {
|
||||
String dirtyPropertyName = ebi.getProperty(i);
|
||||
assertEquals("name", dirtyPropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
customer.setStatus(Customer.Status.INACTIVE);
|
||||
|
||||
assertTrue(beanState.isDirty());
|
||||
assertThat(beanState.getChangedProps()).containsOnly("name", "status");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setDisableLazyLoad_expect_lazyLoadingDisabled() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
List<Customer> custs = DB.find(Customer.class).order("id").findList();
|
||||
|
||||
Customer customer = DB.find(Customer.class)
|
||||
.setId(custs.get(0).getId())
|
||||
.select("id")
|
||||
.setUseCache(false)
|
||||
.findOne();
|
||||
|
||||
BeanState beanState = DB.getBeanState(customer);
|
||||
beanState.setDisableLazyLoad(true);
|
||||
assertNull(customer.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getChangedProps_when_setManyProperty() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Customer customer = DB.find(Customer.class).order("id").setMaxRows(1).findOne();
|
||||
|
||||
BeanState beanState = DB.getBeanState(customer);
|
||||
assertThat(beanState.getChangedProps()).isEmpty();
|
||||
|
||||
customer.setContacts(new ArrayList<>());
|
||||
assertThat(beanState.getChangedProps()).containsOnly("contacts");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getChangedProps_when_setManyProperty_onNewBean() {
|
||||
|
||||
Customer customer = new Customer();
|
||||
|
||||
BeanState beanState = DB.getBeanState(customer);
|
||||
assertThat(beanState.getChangedProps()).isEmpty();
|
||||
|
||||
// when new state, then loaded
|
||||
customer.setContacts(new ArrayList<>());
|
||||
assertThat(beanState.getChangedProps()).isEmpty();
|
||||
assertThat(beanState.getLoadedProps()).containsOnly("contacts");
|
||||
|
||||
// set loaded state, then marked as changed
|
||||
beanState.setLoaded();
|
||||
customer.setContacts(new ArrayList<>());
|
||||
assertThat(beanState.getLoadedProps()).containsOnly("contacts");
|
||||
assertThat(beanState.getChangedProps()).containsOnly("contacts");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void readOnly_when_setManyProperty() {
|
||||
|
||||
Customer customer = new Customer();
|
||||
customer.setContacts(new ArrayList<>());
|
||||
|
||||
BeanState beanState = DB.getBeanState(customer);
|
||||
beanState.setLoaded();
|
||||
beanState.setReadOnly(true);
|
||||
|
||||
// act, try to mutate read only bean
|
||||
customer.setContacts(new ArrayList<>());
|
||||
}
|
||||
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void readOnly_when_setProperty() {
|
||||
|
||||
Customer customer = new Customer();
|
||||
customer.setName("a");
|
||||
|
||||
BeanState beanState = DB.getBeanState(customer);
|
||||
beanState.setLoaded();
|
||||
beanState.setReadOnly(true);
|
||||
|
||||
// act, try to mutate read only bean
|
||||
customer.setName("b");
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ public class TestLazyJoin extends BaseTestCase {
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class)
|
||||
.select("status")
|
||||
.fetch("customer", "+lazy(10) name, status")
|
||||
.fetchLazy("customer", "name, status")
|
||||
.fetch("customer.contacts")
|
||||
.order().asc("id");
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ public class TestLazyJoin2 extends BaseTestCase {
|
||||
// This will use 3 SQL queries to build this object graph
|
||||
List<Order> l0 = Ebean.find(Order.class).select("status, shipDate")
|
||||
|
||||
.fetch("details", "orderQty, unitPrice", new FetchConfig().query())
|
||||
.fetchQuery("details", "orderQty, unitPrice")
|
||||
.fetch("details.product", "sku, name")
|
||||
|
||||
.fetch("customer", "name", new FetchConfig().query(10))
|
||||
.fetchQuery("customer", "name")
|
||||
.fetch("customer.contacts", "firstName, lastName, mobile")
|
||||
.fetch("customer.shippingAddress", "line1, city").order().asc("id").findList();
|
||||
|
||||
@@ -43,7 +43,7 @@ public class TestLazyJoin2 extends BaseTestCase {
|
||||
|
||||
List<Order> orders = Ebean.find(Order.class)
|
||||
// .select("status")
|
||||
.fetch("customer", new FetchConfig().query(3).lazy(10)).order().asc("id").findList();
|
||||
.fetchQuery("customer").order().asc("id").findList();
|
||||
// .join("customer.contacts");
|
||||
|
||||
// List<Order> list = query.findList();
|
||||
@@ -59,7 +59,7 @@ public class TestLazyJoin2 extends BaseTestCase {
|
||||
|
||||
Assert.assertNotNull(billingAddress);
|
||||
|
||||
List<Order> list = Ebean.find(Order.class).fetch("customer", "name", new FetchConfig().lazy(5))
|
||||
List<Order> list = Ebean.find(Order.class).fetchLazy("customer", "name")
|
||||
.fetch("customer.contacts", "contactName, phone, email").fetch("customer.shippingAddress")
|
||||
.where().eq("status", Order.Status.NEW).order().asc("id").findList();
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ public class TestLazyLoadEmptyCollection extends TransactionalTestCase {
|
||||
Ebean.save(c);
|
||||
|
||||
List<Customer> list = Ebean.find(Customer.class)
|
||||
.fetch("contacts", new FetchConfig().query(0))
|
||||
.fetch("contacts.notes", new FetchConfig().query(100))
|
||||
.fetchQuery("contacts")
|
||||
.fetchQuery("contacts.notes")
|
||||
.findList();
|
||||
|
||||
for (Customer customer : list) {
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
package org.tests.batchload;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.BeanState;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TestLoadOnDirty extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
List<Customer> custs = Ebean.find(Customer.class).findList();
|
||||
|
||||
Customer customer = Ebean.find(Customer.class).setId(custs.get(0).getId()).select("name")
|
||||
.setUseCache(false)
|
||||
.findOne();
|
||||
|
||||
BeanState beanState = Ebean.getBeanState(customer);
|
||||
Assert.assertTrue(!beanState.isNew());
|
||||
Assert.assertTrue(!beanState.isDirty());
|
||||
Assert.assertTrue(!beanState.isNewOrDirty());
|
||||
Assert.assertNotNull(beanState.getLoadedProps());
|
||||
|
||||
customer.setName("dirtyNameProp");
|
||||
Assert.assertTrue(beanState.isDirty());
|
||||
Assert.assertTrue(beanState.getChangedProps().contains("name"));
|
||||
Assert.assertEquals(1, beanState.getChangedProps().size());
|
||||
|
||||
EntityBeanIntercept ebi = ((EntityBean) customer)._ebean_getIntercept();
|
||||
boolean[] dirtyProperties = ebi.getDirtyProperties();
|
||||
for (int i = 0; i < dirtyProperties.length; i++) {
|
||||
if (dirtyProperties[i]) {
|
||||
String dirtyPropertyName = ebi.getProperty(i);
|
||||
Assert.assertEquals("name", dirtyPropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
customer.setStatus(Customer.Status.INACTIVE);
|
||||
|
||||
Assert.assertTrue(beanState.isDirty());
|
||||
Assert.assertTrue(beanState.getChangedProps().contains("status"));
|
||||
Assert.assertTrue(beanState.getChangedProps().contains("name"));
|
||||
Assert.assertEquals(2, beanState.getChangedProps().size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisableLazyLoad() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
List<Customer> custs = Ebean.find(Customer.class).order("id").findList();
|
||||
|
||||
Customer customer = Ebean.find(Customer.class)
|
||||
.setId(custs.get(0).getId())
|
||||
.select("id")
|
||||
.setUseCache(false)
|
||||
.findOne();
|
||||
|
||||
BeanState beanState = Ebean.getBeanState(customer);
|
||||
beanState.setDisableLazyLoad(true);
|
||||
Assert.assertNull(customer.getName());
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ public class TestQueryJoin extends BaseTestCase {
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class).select("status")
|
||||
// .join("details","+query(10)")
|
||||
.fetch("customer", "+lazy(10) name, status").fetch("customer.contacts").order().asc("id");
|
||||
.fetchLazy("customer", "name, status").fetch("customer.contacts").order().asc("id");
|
||||
// .join("customer.billingAddress");
|
||||
|
||||
List<Order> list = query.findList();
|
||||
|
||||
@@ -29,7 +29,7 @@ public class TestQueryJoinToAssocOne extends BaseTestCase {
|
||||
|
||||
// This will use 2 SQL queries to build this object graph
|
||||
List<Order> l0 = Ebean.find(Order.class)
|
||||
.fetch("details", "orderQty, unitPrice", new FetchConfig().query())
|
||||
.fetchQuery("details", "orderQty, unitPrice")
|
||||
.fetch("details.product", "sku, name")
|
||||
.findList();
|
||||
|
||||
@@ -56,7 +56,7 @@ public class TestQueryJoinToAssocOne extends BaseTestCase {
|
||||
// This will use 2 SQL queries to build this object graph
|
||||
List<Order> l0 = Ebean.find(Order.class)
|
||||
.select("status, shipDate")
|
||||
.fetch("details", "orderQty, unitPrice", new FetchConfig().query())
|
||||
.fetchQuery("details", "orderQty, unitPrice")
|
||||
.fetch("details.product", "sku, name")
|
||||
.findList();
|
||||
|
||||
@@ -83,7 +83,7 @@ public class TestQueryJoinToAssocOne extends BaseTestCase {
|
||||
List<Order> l0 = Ebean.find(Order.class)
|
||||
.setDisableLazyLoading(true)
|
||||
.select("status, shipDate")
|
||||
.fetch("details", "orderQty, unitPrice", new FetchConfig().query())
|
||||
.fetchQuery("details", "orderQty, unitPrice")
|
||||
.fetch("details.product", "sku, name")
|
||||
.order().asc("id")
|
||||
.findList();
|
||||
|
||||
@@ -25,7 +25,7 @@ public class TestSecondQueryNoRows extends BaseTestCase {
|
||||
Customer c = Ebean.find(Customer.class)
|
||||
.setAutoTune(false)
|
||||
.setId(cnew.getId())
|
||||
.fetch("contacts", new FetchConfig().query())
|
||||
.fetchQuery("contacts")
|
||||
.findOne();
|
||||
|
||||
assertNotNull(c);
|
||||
|
||||
@@ -105,7 +105,7 @@ public class TestSecondaryQueries extends TransactionalTestCase {
|
||||
|
||||
Query<Customer> query = Ebean.find(Customer.class)
|
||||
.select("name")
|
||||
.fetch("contacts", "+query")
|
||||
.fetchQuery("contacts")
|
||||
.setId(custId);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
@@ -129,9 +129,9 @@ public class TestSecondaryQueries extends TransactionalTestCase {
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class)
|
||||
.select("status")
|
||||
.fetch("customer", "name, status", new FetchConfig().query())
|
||||
.fetchQuery("customer", "name, status")
|
||||
.fetch("customer.contacts")
|
||||
.fetch("details", new FetchConfig().query())
|
||||
.fetchQuery("details")
|
||||
.where().eq("status", Order.Status.NEW)
|
||||
.query();
|
||||
|
||||
|
||||
@@ -19,8 +19,7 @@ public class TestDeleteO2MOrphans extends BaseTestCase {
|
||||
|
||||
// assert
|
||||
COOne check = findById(id);
|
||||
//FIXME #2127 #2141: assertThat(check.getChildren()).hasSize(2);
|
||||
assertThat(check.getChildren()).hasSize(4);
|
||||
assertThat(check.getChildren()).hasSize(2);
|
||||
DB.delete(check);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.tests.model.array;
|
||||
|
||||
|
||||
import io.ebean.annotation.Cache;
|
||||
import io.ebean.annotation.DbArray;
|
||||
import io.ebean.annotation.NotNull;
|
||||
|
||||
@@ -13,6 +14,7 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Cache
|
||||
public class EArrayBean {
|
||||
|
||||
enum Status {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.tests.model.array;
|
||||
|
||||
|
||||
import io.ebean.annotation.Cache;
|
||||
import io.ebean.annotation.DbArray;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
@@ -11,6 +12,7 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Cache
|
||||
public class EArraySetBean {
|
||||
|
||||
@Id
|
||||
@@ -30,6 +32,9 @@ public class EArraySetBean {
|
||||
@DbArray
|
||||
Set<Double> doubs;
|
||||
|
||||
@DbArray
|
||||
Set<EArrayBean.Status> status;
|
||||
|
||||
@Version
|
||||
Long version;
|
||||
|
||||
@@ -81,6 +86,14 @@ public class EArraySetBean {
|
||||
this.doubs = doubs;
|
||||
}
|
||||
|
||||
public Set<EArrayBean.Status> getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Set<EArrayBean.Status> status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,11 @@ public class TestDbArray_asSet extends BaseTestCase {
|
||||
bean.getOtherIds().add(97L);
|
||||
bean.setDoubs(doubles);
|
||||
|
||||
Set<EArrayBean.Status> status = new LinkedHashSet<>();
|
||||
status.add(EArrayBean.Status.ONE);
|
||||
status.add(EArrayBean.Status.TWO);
|
||||
bean.setStatus(status);
|
||||
|
||||
Ebean.save(bean);
|
||||
|
||||
found = Ebean.find(EArraySetBean.class, bean.getId());
|
||||
@@ -154,4 +159,31 @@ public class TestDbArray_asSet extends BaseTestCase {
|
||||
Ebean.saveAll(all);
|
||||
Ebean.deleteAll(all);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnorePlatform(Platform.HANA)
|
||||
public void hitCache() {
|
||||
|
||||
Set<UUID> uids = new LinkedHashSet<>();
|
||||
uids.add(UUID.randomUUID());
|
||||
uids.add(UUID.randomUUID());
|
||||
|
||||
Set<EArrayBean.Status> statuses = new LinkedHashSet<>();
|
||||
statuses.add(EArrayBean.Status.ONE);
|
||||
statuses.add(EArrayBean.Status.THREE);
|
||||
|
||||
EArraySetBean bean = new EArraySetBean();
|
||||
bean.setName("hitCache");
|
||||
bean.setUids(uids);
|
||||
bean.setStatus(statuses);
|
||||
|
||||
Ebean.save(bean);
|
||||
// load cache
|
||||
Ebean.find(EArraySetBean.class, bean.getId());
|
||||
// hit cache
|
||||
EArraySetBean found = Ebean.find(EArraySetBean.class, bean.getId());
|
||||
|
||||
assertThat(found.getUids()).isEqualTo(uids);
|
||||
assertThat(found.getStatus()).isEqualTo(statuses);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,4 +249,31 @@ public class TestDbArray_basic extends BaseTestCase {
|
||||
assertThat(found.getIntEnums()).containsExactly(null, IntEnum.ZERO, null, IntEnum.TWO);
|
||||
Ebean.delete(bean);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnorePlatform(Platform.HANA)
|
||||
public void hitCache() {
|
||||
|
||||
List<UUID> uids = new ArrayList<>();
|
||||
uids.add(UUID.randomUUID());
|
||||
uids.add(UUID.randomUUID());
|
||||
|
||||
List<EArrayBean.Status> statuses = new ArrayList<>();
|
||||
statuses.add(EArrayBean.Status.ONE);
|
||||
statuses.add(EArrayBean.Status.THREE);
|
||||
|
||||
EArrayBean bean = new EArrayBean();
|
||||
bean.setName("hitCache");
|
||||
bean.setUids(uids);
|
||||
bean.setStatuses(statuses);
|
||||
|
||||
Ebean.save(bean);
|
||||
// load cache
|
||||
Ebean.find(EArrayBean.class, bean.getId());
|
||||
// hit cache
|
||||
EArrayBean found = Ebean.find(EArrayBean.class, bean.getId());
|
||||
|
||||
assertThat(found.getUids()).isEqualTo(uids);
|
||||
assertThat(found.getStatuses()).isEqualTo(statuses);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@ public class Address implements IAddress {
|
||||
|
||||
private String street;
|
||||
|
||||
public Address(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
|
||||
public long getOid() {
|
||||
return oid;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.tests.model.interfaces;
|
||||
|
||||
public interface IPersona {
|
||||
|
||||
String persona();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.tests.model.interfaces;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
public class Persona implements IPersona {
|
||||
|
||||
@Id
|
||||
private long id;
|
||||
|
||||
@Version
|
||||
private int version;
|
||||
|
||||
private final String persona;
|
||||
|
||||
@OneToOne(orphanRemoval = true, fetch = FetchType.LAZY, targetEntity = Person.class)
|
||||
private IPerson person;
|
||||
|
||||
public Persona(String persona) {
|
||||
this.persona = persona;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String persona() {
|
||||
return persona;
|
||||
}
|
||||
|
||||
public void setPerson(IPerson person) {
|
||||
this.person = person;
|
||||
}
|
||||
|
||||
public IPerson getPerson() {
|
||||
return person;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.tests.model.interfaces;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
public class SelfManyMany {
|
||||
|
||||
@Id
|
||||
private long id;
|
||||
|
||||
private final String name;
|
||||
|
||||
@ManyToMany
|
||||
// requires explicit @JoinTable
|
||||
@JoinTable(name = "self_many_bridge",
|
||||
joinColumns = @JoinColumn(name = "self_1_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "self_2_id"))
|
||||
private List<SelfManyMany> related;
|
||||
|
||||
public SelfManyMany(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<SelfManyMany> getRelated() {
|
||||
return related;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.tests.model.interfaces;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestSelfMany extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void self_manyToMany() {
|
||||
|
||||
SelfManyMany m = new SelfManyMany("1");
|
||||
DB.save(m);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.tests.model.interfaces;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestTargetEntity extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
Person person = setup();
|
||||
|
||||
Persona persona = new Persona("junk");
|
||||
persona.setPerson(person);
|
||||
DB.save(persona);
|
||||
|
||||
Persona found = DB.find(Persona.class, persona.getId());
|
||||
assertThat(found).isNotNull();
|
||||
assertThat(found.persona()).isEqualTo("junk");
|
||||
assertThat(found.getPerson().getDefaultAddress().getStreet()).isEqualTo("street");
|
||||
|
||||
DB.delete(persona);
|
||||
DB.delete(person);
|
||||
DB.delete(person.getDefaultAddress());
|
||||
}
|
||||
|
||||
private Person setup() {
|
||||
Address address = new Address("street");
|
||||
DB.save(address);
|
||||
Person person = new Person();
|
||||
person.setDefaultAddress(address);
|
||||
DB.save(person);
|
||||
return person;
|
||||
}
|
||||
}
|
||||
@@ -19,14 +19,14 @@ public class TestQueryFetchJoinWithOrder extends BaseTestCase {
|
||||
ResetBasicData.reset();
|
||||
|
||||
List<Order> list = Ebean.find(Order.class)
|
||||
.fetch("details", new FetchConfig().query())
|
||||
.fetchQuery("details")
|
||||
.order().asc("id")
|
||||
.order().desc("details.id").findList();
|
||||
|
||||
Assert.assertNotNull(list);
|
||||
|
||||
List<Order> list2 = Ebean.find(Order.class)
|
||||
.fetch("customer", new FetchConfig().query(5))
|
||||
.fetchQuery("customer")
|
||||
.fetch("customer.contacts")
|
||||
.order().asc("id")
|
||||
.order().asc("customer.contacts.lastName")
|
||||
|
||||
@@ -29,7 +29,7 @@ public class TestQueryFilterMany extends BaseTestCase {
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Customer customer = Ebean.find(Customer.class)
|
||||
.fetch("orders", new FetchConfig().lazy())
|
||||
.fetchLazy("orders")
|
||||
.filterMany("orders").eq("status", Order.Status.NEW)
|
||||
.where().ieq("name", "Rob")
|
||||
.order().asc("id").setMaxRows(1)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user