mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
82
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b00899513 | ||
|
|
6fe557e237 | ||
|
|
a227f8c469 | ||
|
|
a9d7ea0299 | ||
|
|
0c4a2d5664 | ||
|
|
577dbad9bd | ||
|
|
ae28599825 | ||
|
|
0627976f6d | ||
|
|
7d89b97e2b | ||
|
|
90ee903c52 | ||
|
|
ffa68f6815 | ||
|
|
2cb0794a01 | ||
|
|
67a267f843 | ||
|
|
e57ce7a6c4 | ||
|
|
5d3d73aac8 | ||
|
|
436988694d | ||
|
|
90f786babd | ||
|
|
0d8146d453 | ||
|
|
0eca613b41 | ||
|
|
dcde54fca4 | ||
|
|
49b8efbc30 | ||
|
|
fc70161909 | ||
|
|
44ba6d3bb2 | ||
|
|
d56e071f53 | ||
|
|
ce33c230c7 | ||
|
|
2da6a6960e | ||
|
|
62f88c9e4f | ||
|
|
42f65ead47 | ||
|
|
8e98e88e8a | ||
|
|
5de67e1939 | ||
|
|
3ddd7099b5 | ||
|
|
5d889790c2 | ||
|
|
636acc61e5 | ||
|
|
cb347ff5fa | ||
|
|
db9d39ef61 | ||
|
|
5216014d50 | ||
|
|
c40715733e | ||
|
|
9bcc8a77fe | ||
|
|
7be3a01823 | ||
|
|
0ca4f92b26 | ||
|
|
b99f002968 | ||
|
|
fa451078b7 | ||
|
|
49121a9c1f | ||
|
|
33f69902dc | ||
|
|
cf783fbbb7 | ||
|
|
cf62ea4c2f | ||
|
|
049bf76cc4 | ||
|
|
75a84af3f8 | ||
|
|
93680f5d19 | ||
|
|
faf7df1c69 | ||
|
|
34dcc98908 | ||
|
|
3c63b79324 | ||
|
|
2d93d592c1 | ||
|
|
57836af5b5 | ||
|
|
ba871d6684 | ||
|
|
583fc11945 | ||
|
|
3ba4660bbb | ||
|
|
37b86f2191 | ||
|
|
da8766533f | ||
|
|
ae31117b8f | ||
|
|
cf825f7ac4 | ||
|
|
a0609b1726 | ||
|
|
32bcd5e853 | ||
|
|
f082fce1ff | ||
|
|
7fc58a1842 | ||
|
|
f2ffbb2c5b | ||
|
|
5c0fb7c8cd | ||
|
|
04c9db1e42 | ||
|
|
8f7de950e2 | ||
|
|
53dd810b9a | ||
|
|
290ca6ba90 | ||
|
|
992f5797a7 | ||
|
|
798976fbd2 | ||
|
|
c315067ff0 | ||
|
|
a4f0e3936a | ||
|
|
fc96685ed0 | ||
|
|
5b10d06348 | ||
|
|
ca73eff519 | ||
|
|
646de50ae8 | ||
|
|
e2558a1e24 | ||
|
|
ad596a2043 | ||
|
|
0a60cd4e58 |
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>7.1.1</version>
|
||||
<version>7.2.3</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
@@ -152,7 +152,7 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-agent</artifactId>
|
||||
<version>4.9.1</version>
|
||||
<version>4.9.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.7.2</version>
|
||||
<version>3.8.11.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -219,7 +219,7 @@
|
||||
<plugin>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
|
||||
<version>4.9.1</version>
|
||||
<version>4.9.2</version>
|
||||
<executions>
|
||||
<!-- Not going to enhance Model bean -->
|
||||
<execution>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebeanservice.docstore.api.DocQueryRequest;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -26,13 +27,16 @@ public interface DocumentStore {
|
||||
* that will fetch a lot of beans. The default bulkBatchSize is used.
|
||||
* </p>
|
||||
*
|
||||
* @param query The query used to update the associated document store.
|
||||
* @param query The query that selects object to send to the document store.
|
||||
*/
|
||||
<T> void indexByQuery(Query<T> query);
|
||||
|
||||
/**
|
||||
* Update the associated document store index using the result of the query additionally specifying a
|
||||
* bulkBatchSize to use for sending the messages to ElasticSearch.
|
||||
*
|
||||
* @param query The query that selects object to send to the document store.
|
||||
* @param bulkBatchSize The batch size to use when bulk sending to the document store.
|
||||
*/
|
||||
<T> void indexByQuery(Query<T> query, int bulkBatchSize);
|
||||
|
||||
@@ -40,28 +44,68 @@ public interface DocumentStore {
|
||||
* Update the document store for all beans of this type.
|
||||
* <p>
|
||||
* This is the same as indexByQuery where the query has no predicates and so fetches all rows.
|
||||
* </p>
|
||||
*/
|
||||
void indexAll(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the bean by fetching it's content from the document store.
|
||||
* If the document is not found null is returned.
|
||||
* <p>
|
||||
* Typically this is called indirectly by findUnique() on the query.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer =
|
||||
* server.find(Customer.class)
|
||||
* .setUseDocStore(true)
|
||||
* .setId(42)
|
||||
* .findUnique();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Nullable
|
||||
<T> T getById(Class<T> beanType, Object id);
|
||||
<T> T find(DocQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the query against the document store returning the list.
|
||||
* Execute the find list query. This request is prepared to execute secondary queries.
|
||||
* <p>
|
||||
* Typically this is called indirectly by findList() on the query that has setUseDocStore(true).
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> newCustomers =
|
||||
* server.find(Customer.class)
|
||||
* .setUseDocStore(true)
|
||||
* .where().eq("status, Customer.Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
<T> List<T> findList(Query<T> query);
|
||||
<T> List<T> findList(DocQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the query against the document store returning the paged list.
|
||||
* <p>
|
||||
* The query should have <code>firstRow</code> or <code>maxRows</code> set prior to calling this method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Typically this is called indirectly by findPagedList() on the query that has setUseDocStore(true).
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Customer> newCustomers =
|
||||
* server.find(Customer.class)
|
||||
* .setUseDocStore(true)
|
||||
* .where().eq("status, Customer.Status.NEW)
|
||||
* .setMaxRows(50)
|
||||
* .findPagedList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
<T> PagedList<T> findPagedList(Query<T> query);
|
||||
<T> PagedList<T> findPagedList(DocQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the query against the document store with the expectation of a large set of results
|
||||
@@ -69,8 +113,59 @@ public interface DocumentStore {
|
||||
* <p>
|
||||
* For example, with the ElasticSearch doc store this uses SCROLL.
|
||||
* </p>
|
||||
* <p>
|
||||
* Typically this is called indirectly by findEach() on the query that has setUseDocStore(true).
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* server.find(Order.class)
|
||||
* .setUseDocStore(true)
|
||||
* .where()... // perhaps add predicates
|
||||
* .findEach(new QueryEachConsumer<Order>() {
|
||||
* @Override
|
||||
* public void accept(Order bean) {
|
||||
* // process the bean
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
<T> void findEach(Query<T> query, QueryEachConsumer<T> consumer);
|
||||
<T> void findEach(DocQueryRequest<T> query, QueryEachConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query against the document store with the expectation of a large set of results
|
||||
* that are processed in a scrolling resultSet fashion.
|
||||
* <p>
|
||||
* Unlike findEach() this provides the opportunity to stop iterating through the large query.
|
||||
* </p>
|
||||
* <p>
|
||||
* For example, with the ElasticSearch doc store this uses SCROLL.
|
||||
* </p>
|
||||
* <p>
|
||||
* Typically this is called indirectly by findEachWhile() on the query that has setUseDocStore(true).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* server.find(Order.class)
|
||||
* .setUseDocStore(true)
|
||||
* .where()... // perhaps add predicates
|
||||
* .findEachWhile(new QueryEachWhileConsumer<Order>() {
|
||||
* @Override
|
||||
* public void accept(Order bean) {
|
||||
* // process the bean
|
||||
*
|
||||
* // return true to continue, false to stop
|
||||
* // boolean shouldContinue = ...
|
||||
* return shouldContinue;
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
<T> void findEachWhile(DocQueryRequest<T> query, QueryEachWhileConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Process the queue entries sending updates to the document store or queuing them for later processing.
|
||||
@@ -79,17 +174,36 @@ public interface DocumentStore {
|
||||
|
||||
/**
|
||||
* Drop the index from the document store (similar to DDL drop table).
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* DocumentStore documentStore = server.docStore();
|
||||
*
|
||||
* documentStore.dropIndex("product_copy");
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
void dropIndex(String indexName);
|
||||
|
||||
/**
|
||||
* Create an index given a mapping file as a resource in the classPath (similar to DDL create table).
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* DocumentStore documentStore = server.docStore();
|
||||
*
|
||||
* // uses product_copy.mapping.json resource
|
||||
* // ... to define mappings for the index
|
||||
*
|
||||
* documentStore.createIndex("product_copy", null);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param indexName the name of the new index
|
||||
* @param alias the alias of the index
|
||||
* @param mappingResource the path of the mapping file as a resource in the classpath
|
||||
*/
|
||||
void createIndex(String indexName, String alias, String mappingResource);
|
||||
void createIndex(String indexName, String alias);
|
||||
|
||||
/**
|
||||
* Copy the index to a new index.
|
||||
@@ -97,9 +211,14 @@ public interface DocumentStore {
|
||||
* This copy process does not use the database but instead will copy from the source index to a destination index.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* long copyCount = documentStore.copyIndex(Product.class, "product_copy");
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The bean type of the source index
|
||||
* @param newIndex The name of the index to copy to
|
||||
*
|
||||
* @return the number of documents copied to the new index
|
||||
*/
|
||||
long copyIndex(Class<?> beanType, String newIndex);
|
||||
@@ -111,11 +230,41 @@ public interface DocumentStore {
|
||||
* To support this the document needs to have a <code>@WhenModified</code> property.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* long copyCount = documentStore.copyIndex(Product.class, "product_copy", sinceMillis);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The bean type of the source index
|
||||
* @param newIndex The name of the index to copy to
|
||||
*
|
||||
* @return the number of documents copied to the new index
|
||||
*/
|
||||
long copyIndex(Class<?> beanType, String newIndex, long sinceEpochMillis);
|
||||
|
||||
/**
|
||||
* Copy from a source index to a new index taking only the documents
|
||||
* matching the given query.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // predicates to select the source documents to copy
|
||||
* Query<Product> query = server.find(Product.class)
|
||||
* .where()
|
||||
* .ge("whenModified", new Timestamp(since))
|
||||
* .ge("name", "A")
|
||||
* .lt("name", "D")
|
||||
* .query();
|
||||
*
|
||||
* // copy from the source index to "product_copy" index
|
||||
* long copyCount = documentStore.copyIndex(query, "product_copy", 1000);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param query The query to select the source documents to copy
|
||||
* @param newIndex The target index to copy the documents to
|
||||
* @param bulkBatchSize The ElasticSearch bulk batch size, if 0 uses the default.
|
||||
* @return The number of documents copied to the new index.
|
||||
*/
|
||||
long copyIndex(Query<?> query, String newIndex, int bulkBatchSize);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* An expression that is part of a WHERE or HAVING clause.
|
||||
*/
|
||||
public interface Expression extends Serializable {
|
||||
public interface Expression {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.search.Match;
|
||||
import com.avaje.ebean.search.MultiMatch;
|
||||
import com.avaje.ebean.search.TextCommonTerms;
|
||||
import com.avaje.ebean.search.TextQueryString;
|
||||
import com.avaje.ebean.search.TextSimple;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -285,6 +291,31 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression raw(String raw);
|
||||
|
||||
/**
|
||||
* Create a Text Match expression (currently doc store/Elastic only).
|
||||
*/
|
||||
Expression textMatch(String propertyName, String search, Match options);
|
||||
|
||||
/**
|
||||
* Create a Text Multi match expression (currently doc store/Elastic only).
|
||||
*/
|
||||
Expression textMultiMatch(String query, MultiMatch options);
|
||||
|
||||
/**
|
||||
* Create a text simple query expression (currently doc store/Elastic only).
|
||||
*/
|
||||
Expression textSimple(String search, TextSimple options);
|
||||
|
||||
/**
|
||||
* Create a text query string expression (currently doc store/Elastic only).
|
||||
*/
|
||||
Expression textQueryString(String search, TextQueryString options);
|
||||
|
||||
/**
|
||||
* Create a text common terms expression (currently doc store/Elastic only).
|
||||
*/
|
||||
Expression textCommonTerms(String search, TextCommonTerms options);
|
||||
|
||||
/**
|
||||
* And - join two expressions with a logical and.
|
||||
*/
|
||||
@@ -319,4 +350,13 @@ public interface ExpressionFactory {
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
*/
|
||||
<T> Junction<T> disjunction(Query<T> query, ExpressionList<T> parent);
|
||||
|
||||
/**
|
||||
* Return a Text query junction for MUST, SHOULD or MUST NOT.
|
||||
* <p>
|
||||
* This is doc store Elastic only.
|
||||
* </p>
|
||||
*/
|
||||
<T> Junction<T> junction(Junction.Type type, Query<T> query, ExpressionList<T> parent);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.search.Match;
|
||||
import com.avaje.ebean.search.MultiMatch;
|
||||
import com.avaje.ebean.search.TextCommonTerms;
|
||||
import com.avaje.ebean.search.TextQueryString;
|
||||
import com.avaje.ebean.search.TextSimple;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -30,7 +34,7 @@ import java.util.Set;
|
||||
*
|
||||
* @see Query#where()
|
||||
*/
|
||||
public interface ExpressionList<T> extends Serializable {
|
||||
public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Return the query that owns this expression list.
|
||||
@@ -380,6 +384,32 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
Query<T> setUseQueryCache(boolean useCache);
|
||||
|
||||
/**
|
||||
* Set to true if this query should execute against the doc store.
|
||||
* <p>
|
||||
* When setting this you may also consider disabling lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
Query<T> setUseDocStore(boolean useDocsStore);
|
||||
|
||||
/**
|
||||
* Set true if you want to disable lazy loading.
|
||||
* <p>
|
||||
* That is, once the object graph is returned further lazy loading is disabled.
|
||||
* </p>
|
||||
*/
|
||||
Query<T> setDisableLazyLoading(boolean disableLazyLoading);
|
||||
|
||||
/**
|
||||
* Disable read auditing for this query.
|
||||
* <p>
|
||||
* This is intended to be used when the query is not a user initiated query and instead
|
||||
* part of the internal processing in an application to load a cache or document store etc.
|
||||
* In these cases we don't want the query to be part of read auditing.
|
||||
* </p>
|
||||
*/
|
||||
Query<T> setDisableReadAuditing();
|
||||
|
||||
/**
|
||||
* Add expressions to the having clause.
|
||||
* <p>
|
||||
@@ -802,6 +832,47 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
ExpressionList<T> raw(String raw);
|
||||
|
||||
/**
|
||||
* Add a match expression.
|
||||
*
|
||||
* @param propertyName The property name for the match
|
||||
* @param search The search value
|
||||
*/
|
||||
ExpressionList<T> match(String propertyName, String search);
|
||||
|
||||
/**
|
||||
* Add a match expression with options.
|
||||
*
|
||||
* @param propertyName The property name for the match
|
||||
* @param search The search value
|
||||
*/
|
||||
ExpressionList<T> match(String propertyName, String search, Match options);
|
||||
|
||||
/**
|
||||
* Add a multi-match expression.
|
||||
*/
|
||||
ExpressionList<T> multiMatch(String search, String... properties);
|
||||
|
||||
/**
|
||||
* Add a multi-match expression using options.
|
||||
*/
|
||||
ExpressionList<T> multiMatch(String search, MultiMatch options);
|
||||
|
||||
/**
|
||||
* Add a simple query string expression.
|
||||
*/
|
||||
ExpressionList<T> textSimple(String search, TextSimple options);
|
||||
|
||||
/**
|
||||
* Add a query string expression.
|
||||
*/
|
||||
ExpressionList<T> textQueryString(String search, TextQueryString options);
|
||||
|
||||
/**
|
||||
* Add common terms expression.
|
||||
*/
|
||||
ExpressionList<T> textCommonTerms(String search, TextCommonTerms options);
|
||||
|
||||
/**
|
||||
* And - join two expressions with a logical and.
|
||||
*/
|
||||
@@ -818,20 +889,168 @@ public interface ExpressionList<T> extends Serializable {
|
||||
ExpressionList<T> not(Expression exp);
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by AND's.
|
||||
* Start a list of expressions that will be joined by AND's
|
||||
* returning the expression list the expressions are added to.
|
||||
* <p>
|
||||
* This is exactly the same as conjunction();
|
||||
* </p>
|
||||
* <p>
|
||||
* Use endJunction() to end the AND junction.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that a where() clause defaults to an AND junction so
|
||||
* typically you only explicitly need to use the and() junction
|
||||
* when it is nested inside an or() or not() junction.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Example: Nested and()
|
||||
*
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .and() // nested and
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end AND junction
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction() // end AND junction
|
||||
* .orderBy().asc("name")
|
||||
* .findList();
|
||||
* }</pre>
|
||||
*/
|
||||
Junction<T> and();
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
* This is exactly the same as disjunction();
|
||||
*
|
||||
* <p>
|
||||
* Use endJunction() to end the OR junction.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Example: Use or() to join
|
||||
* // two nested and() expressions
|
||||
*
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .and()
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end AND junction
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction() // end AND junction
|
||||
* .orderBy().asc("name")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Junction<T> or();
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be wrapped by NOT.
|
||||
* <p>
|
||||
* Use endJunction() to end expressions being added to the
|
||||
* NOT expression list.
|
||||
* </p>
|
||||
*
|
||||
* <pre>@{code
|
||||
*
|
||||
* .where()
|
||||
* .not()
|
||||
* .gt("id", 1)
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end the not expressions
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <pre>@{code
|
||||
*
|
||||
* // Example: nested not()
|
||||
*
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .not()
|
||||
* .gt("id", 1)
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end the not expressions
|
||||
* .orderBy()
|
||||
* .asc("name")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Junction<T> not();
|
||||
|
||||
/**
|
||||
* Start (and return) a list of expressions that will be joined by AND's.
|
||||
* <p>
|
||||
* This is the same as and().
|
||||
* </p>
|
||||
*/
|
||||
Junction<T> conjunction();
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
* Start (and return) a list of expressions that will be joined by OR's.
|
||||
* <p>
|
||||
* This is the same as or().
|
||||
* </p>
|
||||
*/
|
||||
Junction<T> disjunction();
|
||||
|
||||
/**
|
||||
* End a Conjunction or Disjunction returning the parent expression list.
|
||||
* Start a list of expressions that will be joined by MUST.
|
||||
* <p>
|
||||
* Alternatively you can always use where() to return the top level expression
|
||||
* list.
|
||||
* This automatically makes the query a useDocStore(true) query that
|
||||
* will execute against the document store (ElasticSearch etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* This is logically similar to and().
|
||||
* </p>
|
||||
*/
|
||||
Junction<T> must();
|
||||
|
||||
/**
|
||||
* Start a list of expressions that will be joined by SHOULD.
|
||||
* <p>
|
||||
* This automatically makes the query a useDocStore(true) query that
|
||||
* will execute against the document store (ElasticSearch etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* This is logically similar to or().
|
||||
* </p>
|
||||
*/
|
||||
Junction<T> should();
|
||||
|
||||
/**
|
||||
* Start a list of expressions that will be joined by MUST NOT.
|
||||
* <p>
|
||||
* This automatically makes the query a useDocStore(true) query that
|
||||
* will execute against the document store (ElasticSearch etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* This is logically similar to not().
|
||||
* </p>
|
||||
*/
|
||||
Junction<T> mustNot();
|
||||
|
||||
/**
|
||||
* End a junction returning the parent expression list.
|
||||
* <p>
|
||||
* Ends a and(), or(), not(), must(), mustNot() or should() junction
|
||||
* such that you get the parent expression.
|
||||
* </p>
|
||||
* <p>
|
||||
* Alternatively you can always use where() to return the top level expression list.
|
||||
* </p>
|
||||
*/
|
||||
ExpressionList<T> endJunction();
|
||||
|
||||
@@ -9,70 +9,129 @@ package com.avaje.ebean;
|
||||
* <p>
|
||||
* Note: where() always takes you to the top level WHERE expression list.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* <pre>{@code
|
||||
* Query q =
|
||||
* Ebean.find(Person.class)
|
||||
* .where().disjunction()
|
||||
* .like("name", "Rob%")
|
||||
* .eq("status", Status.NEW)
|
||||
*
|
||||
* // where() returns us to the top level expression list
|
||||
* .where().gt("id", 10);
|
||||
*
|
||||
* .where()
|
||||
* .or()
|
||||
* .like("name", "Rob%")
|
||||
* .eq("status", Status.NEW)
|
||||
*
|
||||
* // where() returns us to the top level expression list
|
||||
* .where().gt("id", 10);
|
||||
*
|
||||
* // read as...
|
||||
* // where ( ((name like Rob%) or (status = NEW)) AND (id > 10) )
|
||||
* </pre>
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Note: endJunction() takes you to the parent expression list
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* <pre>{@code
|
||||
* Query q =
|
||||
* Ebean.find(Person.class)
|
||||
* .where().disjunction()
|
||||
* .like("name", "Rob%")
|
||||
* .eq("status", Status.NEW)
|
||||
* .endJunction()
|
||||
*
|
||||
* // endJunction().. takes us to the 'parent' expression list
|
||||
* // which in this case is the top level (same as where())
|
||||
*
|
||||
* .gt("id", 10);
|
||||
*
|
||||
* .where()
|
||||
* .or()
|
||||
* .like("name", "Rob%")
|
||||
* .eq("status", Status.NEW)
|
||||
* .endJunction()
|
||||
*
|
||||
* // endJunction().. takes us to the 'parent' expression list
|
||||
* // which in this case is the top level (same as where())
|
||||
*
|
||||
* .gt("id", 10);
|
||||
*
|
||||
* // read as...
|
||||
* // where ( ((name like Rob%) or (status = NEW)) AND (id > 10) )
|
||||
* </pre>
|
||||
*
|
||||
* // where ( ((name like Rob%) or (status = NEW)) AND (id > 10) )
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Example of a nested disjunction.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Query<Customer> q =
|
||||
*
|
||||
* <pre>{@code
|
||||
* Query<Customer> q =
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .disjunction()
|
||||
* .conjunction()
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction()
|
||||
* .conjunction()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction()
|
||||
* .order().asc("name");
|
||||
*
|
||||
* .or()
|
||||
* .and()
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction()
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction()
|
||||
* .order().asc("name");
|
||||
*
|
||||
* q.findList();
|
||||
* String s = q.getGeneratedSql();
|
||||
*
|
||||
*
|
||||
* // this produces an expression like:
|
||||
*
|
||||
* ( name like ? and c.anniversary = ? ) or (c.status = ? and c.id > ? )
|
||||
*
|
||||
* </pre>
|
||||
* ( name like ? and c.anniversary = ? ) or (c.status = ? and c.id > ? )
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public interface Junction<T> extends Expression, ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* The type of Junction used in full text expressions.
|
||||
*/
|
||||
enum Type {
|
||||
|
||||
/**
|
||||
* AND group.
|
||||
*/
|
||||
AND(" and ", ""),
|
||||
|
||||
/**
|
||||
* OR group.
|
||||
*/
|
||||
OR(" or ", ""),
|
||||
|
||||
/**
|
||||
* NOT group.
|
||||
*/
|
||||
NOT(" and ", "not "),
|
||||
|
||||
/**
|
||||
* Text search AND group.
|
||||
*/
|
||||
MUST("must", ""),
|
||||
|
||||
/**
|
||||
* Text search NOT group.
|
||||
*/
|
||||
MUST_NOT("must_not", ""),
|
||||
|
||||
/**
|
||||
* Text search OR group.
|
||||
*/
|
||||
SHOULD("should", "");
|
||||
|
||||
String prefix;
|
||||
String literal;
|
||||
|
||||
Type(String literal, String prefix) {
|
||||
this.literal = literal;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the literal value for this type.
|
||||
*/
|
||||
public String literal() {
|
||||
return literal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the prefix value for this type.
|
||||
*/
|
||||
public String prefix() {
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -270,6 +270,19 @@ public abstract class Model {
|
||||
return db().delete(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bean permanently without soft delete.
|
||||
* <p>
|
||||
* This is used when the bean contains a <code>@SoftDelete</code> property and we
|
||||
* want to perform a hard/permanent delete.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#deletePermanent(Object)
|
||||
*/
|
||||
public boolean deletePermanent() {
|
||||
return db().deletePermanent(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an update using this entity against the specified server.
|
||||
*/
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.avaje.ebean;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -1042,6 +1041,27 @@ public interface Query<T> {
|
||||
*/
|
||||
ExpressionList<T> where();
|
||||
|
||||
/**
|
||||
* Add Full text search expressions for Document store queries.
|
||||
* <p>
|
||||
* This is currently ElasticSearch only and provides the full text
|
||||
* expressions such as Match and Multi-Match.
|
||||
* </p>
|
||||
* <p>
|
||||
* This automatically makes this query a "Doc Store" query and will execute
|
||||
* against the document store (ElasticSearch).
|
||||
* </p>
|
||||
* <p>
|
||||
* Expressions added here are added to the "query" section of an ElasticSearch
|
||||
* query rather than the "filter" section.
|
||||
* </p>
|
||||
* <p>
|
||||
* Expressions added to the where() are added to the "filter" section of an
|
||||
* ElasticSearch query.
|
||||
* </p>
|
||||
*/
|
||||
ExpressionList<T> text();
|
||||
|
||||
/**
|
||||
* This applies a filter on the 'many' property list rather than the root
|
||||
* level objects.
|
||||
@@ -1373,9 +1393,4 @@ public interface Query<T> {
|
||||
*/
|
||||
Set<String> validate();
|
||||
|
||||
/**
|
||||
* Return the query in JSON form for ElasticSearch doc store.
|
||||
*/
|
||||
String asElasticQuery();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.annotation.DocStoreEvent;
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
import com.avaje.ebean.config.DocStoreConfig;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
@@ -92,7 +92,7 @@ public interface Transaction extends Closeable {
|
||||
* to control how that is sent to the document store.
|
||||
* </p>
|
||||
*/
|
||||
void setDocStoreUpdateMode(DocStoreEvent updateMode);
|
||||
void setDocStoreMode(DocStoreMode mode);
|
||||
|
||||
/**
|
||||
* Set the batch size to use for sending messages to the document store.
|
||||
@@ -104,7 +104,7 @@ public interface Transaction extends Closeable {
|
||||
* Setting this overrides the default of {@link DocStoreConfig#getBulkBatchSize()}
|
||||
* </p>
|
||||
*/
|
||||
void setDocStoreUpdateBatchSize(int batchSize);
|
||||
void setDocStoreBatchSize(int batchSize);
|
||||
|
||||
/**
|
||||
* Explicitly turn off or on the cascading nature of save() and delete(). This
|
||||
|
||||
@@ -18,27 +18,7 @@ public @interface DocMapping {
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Set this to true to indicate that this property should be un-analysed.
|
||||
* Mapping options.
|
||||
*/
|
||||
boolean code() default false;
|
||||
|
||||
/**
|
||||
* Set this to true to get an additional un-analysed 'raw' field to use for sorting etc.
|
||||
*/
|
||||
boolean sortable() default false;
|
||||
|
||||
/**
|
||||
* Set to true to have the property additionally stored separately from _source.
|
||||
*/
|
||||
boolean store() default false;
|
||||
|
||||
/**
|
||||
* Set a boost value specific to this property.
|
||||
*/
|
||||
float boost() default 1;
|
||||
|
||||
/**
|
||||
* Set a value to use instead of null.
|
||||
*/
|
||||
String nullValue() default "";
|
||||
DocProperty options();
|
||||
}
|
||||
|
||||
@@ -36,4 +36,75 @@ public @interface DocProperty {
|
||||
* Set a value to use instead of null.
|
||||
*/
|
||||
String nullValue() default "";
|
||||
|
||||
/**
|
||||
* Set this to false to exclude this from the _all property.
|
||||
*/
|
||||
boolean includeInAll() default true;
|
||||
|
||||
/**
|
||||
* The analyzer to use.
|
||||
*/
|
||||
String analyzer() default "";
|
||||
|
||||
/**
|
||||
* The analyzer to use for searches.
|
||||
*/
|
||||
String searchAnalyzer() default "";
|
||||
|
||||
/**
|
||||
* The index options for this property.
|
||||
*/
|
||||
Option options() default Option.DEFAULT;
|
||||
|
||||
/**
|
||||
* Set this to false such that doc values are not stored separately for this property.
|
||||
*/
|
||||
boolean docValues() default true;
|
||||
|
||||
/**
|
||||
* Set a copyTo field.
|
||||
*/
|
||||
String copyTo() default "";
|
||||
|
||||
/**
|
||||
* Set to false to disable the field from indexing, it will only be get/set in _source.
|
||||
*/
|
||||
boolean enabled() default true;
|
||||
|
||||
/**
|
||||
* Set to false such that norms are not stored.
|
||||
*/
|
||||
boolean norms() default true;
|
||||
|
||||
/**
|
||||
* Index options for a property.
|
||||
*/
|
||||
enum Option {
|
||||
|
||||
/**
|
||||
* Only index the doc number.
|
||||
*/
|
||||
DOCS,
|
||||
|
||||
/**
|
||||
* Doc number and term frequencies are indexed.
|
||||
*/
|
||||
FREQS,
|
||||
|
||||
/**
|
||||
* Doc number, term frequencies and term positions are indexed.
|
||||
*/
|
||||
POSITIONS,
|
||||
|
||||
/**
|
||||
* Doc number, term frequencies, term positions and start/end offsets are indexed.
|
||||
*/
|
||||
OFFSETS,
|
||||
|
||||
/**
|
||||
* Use the default which means analysed string properties use POSITIONS as the default and all other types use DOCS.
|
||||
*/
|
||||
DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,22 +45,22 @@ public @interface DocStore {
|
||||
/**
|
||||
* Specify the behavior when bean Insert, Update, Delete events occur.
|
||||
*/
|
||||
DocStoreEvent persist() default DocStoreEvent.DEFAULT;
|
||||
DocStoreMode persist() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Insert occurs.
|
||||
*/
|
||||
DocStoreEvent insert() default DocStoreEvent.DEFAULT;
|
||||
DocStoreMode insert() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Update occurs.
|
||||
*/
|
||||
DocStoreEvent update() default DocStoreEvent.DEFAULT;
|
||||
DocStoreMode update() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Delete occurs.
|
||||
*/
|
||||
DocStoreEvent delete() default DocStoreEvent.DEFAULT;
|
||||
DocStoreMode delete() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify to include only some properties in the doc store document.
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ package com.avaje.ebean.annotation;
|
||||
* for later processing rather than look to update ElasticSearch at that time.
|
||||
* </p>
|
||||
*/
|
||||
public enum DocStoreEvent {
|
||||
public enum DocStoreMode {
|
||||
|
||||
/**
|
||||
* Add the event to the queue for processing later (delaying the update to the document store).
|
||||
@@ -31,6 +31,11 @@ public interface BeanCollection<E> extends Serializable {
|
||||
ALL
|
||||
}
|
||||
|
||||
/**
|
||||
* Load bean from another collection.
|
||||
*/
|
||||
void loadFrom(BeanCollection<?> other);
|
||||
|
||||
/**
|
||||
* Add a bean to the list/set with modifyListen notification.
|
||||
*/
|
||||
|
||||
@@ -12,7 +12,7 @@ public interface PersistenceContext {
|
||||
/**
|
||||
* Put the entity bean into the PersistenceContext.
|
||||
*/
|
||||
void put(Object id, Object bean);
|
||||
void put(Class<?> rootType, Object id, Object bean);
|
||||
|
||||
/**
|
||||
* Put the entity bean into the PersistenceContext if one is not already
|
||||
@@ -22,19 +22,19 @@ public interface PersistenceContext {
|
||||
* returns null.
|
||||
* </p>
|
||||
*/
|
||||
Object putIfAbsent(Object id, Object bean);
|
||||
Object putIfAbsent(Class<?> rootType, Object id, Object bean);
|
||||
|
||||
/**
|
||||
* Return an object given its type and unique id.
|
||||
*/
|
||||
Object get(Class<?> beanType, Object uid);
|
||||
Object get(Class<?> rootType, Object uid);
|
||||
|
||||
/**
|
||||
* Get the bean from the persistence context also checked to see if it had
|
||||
* been previously deleted (if so then you also can't hit the L2 cache to
|
||||
* fetch the bean for this particular persistence context).
|
||||
*/
|
||||
WithOption getWithOption(Class<?> beanType, Object uid);
|
||||
WithOption getWithOption(Class<?> rootType, Object uid);
|
||||
|
||||
/**
|
||||
* Clear all the references.
|
||||
@@ -44,22 +44,22 @@ public interface PersistenceContext {
|
||||
/**
|
||||
* Clear all the references for a given type of entity bean.
|
||||
*/
|
||||
void clear(Class<?> beanType);
|
||||
void clear(Class<?> rootType);
|
||||
|
||||
/**
|
||||
* Clear the reference to a specific entity bean.
|
||||
*/
|
||||
void clear(Class<?> beanType, Object uid);
|
||||
void clear(Class<?> rootType, Object uid);
|
||||
|
||||
/**
|
||||
* Clear the reference as a result of an entity being deleted.
|
||||
*/
|
||||
void deleted(Class<?> beanType, Object id);
|
||||
void deleted(Class<?> rootType, Object id);
|
||||
|
||||
/**
|
||||
* Return the number of beans of the given type in the persistence context.
|
||||
*/
|
||||
int size(Class<?> beanType);
|
||||
int size(Class<?> rootType);
|
||||
|
||||
/**
|
||||
* Wrapper on a bean to also indicate if a bean has been deleted.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
/**
|
||||
* Utility to find the root bean type.
|
||||
*/
|
||||
public class PersistenceContextUtil {
|
||||
|
||||
/**
|
||||
* Find and return the root bean type for the given class.
|
||||
*/
|
||||
public static Class<?> root(Class<?> beanType) {
|
||||
Class<?> parent = beanType.getSuperclass();
|
||||
while (parent != null && parent.isAnnotationPresent(Entity.class)) {
|
||||
beanType = parent;
|
||||
parent = parent.getSuperclass();
|
||||
}
|
||||
return beanType;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
@@ -64,6 +65,15 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
list.add((E) bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void loadFrom(BeanCollection<?> other) {
|
||||
if (list == null) {
|
||||
list = new ArrayList<E>();
|
||||
}
|
||||
list.addAll((Collection<? extends E>) other.getActualDetails());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalAdd(Object bean) {
|
||||
if (list == null) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
@@ -51,6 +52,14 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
return !touched && (map == null || map.isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void loadFrom(BeanCollection<?> other) {
|
||||
BeanMap<K,E> otherMap = (BeanMap<K,E>)other;
|
||||
internalPutNull();
|
||||
map.putAll(otherMap.getActualMap());
|
||||
}
|
||||
|
||||
public void internalPutNull() {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
@@ -57,6 +58,15 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
set.add((E) bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void loadFrom(BeanCollection<?> other) {
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<E>();
|
||||
}
|
||||
set.addAll((Collection<? extends E>) other.getActualDetails());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void internalAddWithCheck(Object bean) {
|
||||
if (set == null || !set.contains(bean)) {
|
||||
|
||||
@@ -1,42 +1,70 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.annotation.DocStoreEvent;
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
|
||||
/**
|
||||
* Configuration for the Document store (ElasticSearch) integration.
|
||||
* Configuration for the Document store integration (e.g. ElasticSearch).
|
||||
*/
|
||||
public class DocStoreConfig {
|
||||
|
||||
/**
|
||||
* True when the Document store integration is active/on.
|
||||
*/
|
||||
boolean active;
|
||||
protected boolean active;
|
||||
|
||||
/**
|
||||
* When true the Document store should drop and re-create any document mapping (like DDL).
|
||||
* Set to true means Ebean will generate mapping files on startup.
|
||||
*/
|
||||
boolean dropCreate;
|
||||
protected boolean generateMapping;
|
||||
|
||||
/**
|
||||
* When true the Document store should drop and re-create document indexes.
|
||||
*/
|
||||
protected boolean dropCreate;
|
||||
|
||||
/**
|
||||
* When true the Document store should create any document indexes that don't already exist.
|
||||
*/
|
||||
protected boolean create;
|
||||
|
||||
/**
|
||||
* The URL of the Document store server. For example: http://localhost:9200.
|
||||
*/
|
||||
String url;
|
||||
protected String url;
|
||||
|
||||
/**
|
||||
* The default mode used by indexes.
|
||||
*/
|
||||
DocStoreEvent persist = DocStoreEvent.UPDATE;
|
||||
protected DocStoreMode persist = DocStoreMode.UPDATE;
|
||||
|
||||
/**
|
||||
* The default batch size to use for the Bulk API calls.
|
||||
*/
|
||||
int bulkBatchSize = 1000;
|
||||
protected int bulkBatchSize = 1000;
|
||||
|
||||
/**
|
||||
* Resource path for the Document store mapping files.
|
||||
*/
|
||||
protected String mappingPath;
|
||||
|
||||
/**
|
||||
* Suffix used for mapping files.
|
||||
*/
|
||||
protected String mappingSuffix;
|
||||
|
||||
/**
|
||||
* Location of resources that mapping files are generated into.
|
||||
*/
|
||||
protected String pathToResources = "src/main/resources";
|
||||
|
||||
/**
|
||||
* Return true if the Document store (ElasticSearch) integration is active.
|
||||
*/
|
||||
public boolean isActive() {
|
||||
String systemValue = System.getProperty("ebean.docstore.active");
|
||||
if (systemValue != null) {
|
||||
return Boolean.parseBoolean(systemValue);
|
||||
}
|
||||
return active;
|
||||
}
|
||||
|
||||
@@ -48,24 +76,134 @@ public class DocStoreConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the document store should recreate mappings.
|
||||
* Return the URL to the Document store.
|
||||
*/
|
||||
public String getUrl() {
|
||||
String systemValue = System.getProperty("ebean.docstore.url");
|
||||
if (systemValue != null) {
|
||||
return systemValue;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL to the Document store server.
|
||||
* <p>
|
||||
* For a local ElasticSearch server this would be: http://localhost:9200
|
||||
*/
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Ebean should generate mapping files on server startup.
|
||||
*/
|
||||
public boolean isGenerateMapping() {
|
||||
return generateMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if Ebean should generate mapping files on server startup.
|
||||
*/
|
||||
public void setGenerateMapping(boolean generateMapping) {
|
||||
this.generateMapping = generateMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the document store should recreate mapped indexes.
|
||||
*/
|
||||
public boolean isDropCreate() {
|
||||
return dropCreate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the document store should recreate mappings.
|
||||
* Set to true if the document store should recreate mapped indexes.
|
||||
*/
|
||||
public void setDropCreate(boolean dropCreate) {
|
||||
this.dropCreate = dropCreate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create true if the document store should create mapped indexes that don't yet exist.
|
||||
* This is only used if dropCreate is false.
|
||||
*/
|
||||
public boolean isCreate() {
|
||||
return create;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the document store should create mapped indexes that don't yet exist.
|
||||
* This is only used if dropCreate is false.
|
||||
*/
|
||||
public void setCreate(boolean create) {
|
||||
this.create = create;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default batch size to use for calls to the Bulk API.
|
||||
*/
|
||||
public int getBulkBatchSize() {
|
||||
return bulkBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default batch size to use for calls to the Bulk API.
|
||||
* <p>
|
||||
* The batch size can be set on a transaction via {@link com.avaje.ebean.Transaction#setDocStoreBatchSize(int)}.
|
||||
* </p>
|
||||
*/
|
||||
public void setBulkBatchSize(int bulkBatchSize) {
|
||||
this.bulkBatchSize = bulkBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mapping path.
|
||||
*/
|
||||
public String getMappingPath() {
|
||||
return mappingPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mapping path.
|
||||
*/
|
||||
public void setMappingPath(String mappingPath) {
|
||||
this.mappingPath = mappingPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mapping suffix.
|
||||
*/
|
||||
public String getMappingSuffix() {
|
||||
return mappingSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mapping suffix.
|
||||
*/
|
||||
public void setMappingSuffix(String mappingSuffix) {
|
||||
this.mappingSuffix = mappingSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the relative file system path to resources when generating mapping files.
|
||||
*/
|
||||
public String getPathToResources() {
|
||||
return pathToResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the relative file system path to resources when generating mapping files.
|
||||
*/
|
||||
public void setPathToResources(String pathToResources) {
|
||||
this.pathToResources = pathToResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default behavior for when Insert, Update and Delete events occur on beans that have an associated
|
||||
* Document store.
|
||||
*/
|
||||
public DocStoreEvent getPersist() {
|
||||
public DocStoreMode getPersist() {
|
||||
return persist;
|
||||
}
|
||||
|
||||
@@ -87,44 +225,10 @@ public class DocStoreConfig {
|
||||
* you don't want Ebean to do anything when the data changes.
|
||||
* </p>
|
||||
*/
|
||||
public void setPersist(DocStoreEvent persist) {
|
||||
public void setPersist(DocStoreMode persist) {
|
||||
this.persist = persist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL to the Document store.
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL to the Document store server.
|
||||
*
|
||||
* For a local ElasticSearch server this would be: http://localhost:9200
|
||||
*/
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the default batch size to use for calls to the Bulk API.
|
||||
*/
|
||||
public int getBulkBatchSize() {
|
||||
return bulkBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default batch size to use for calls to the Bulk API.
|
||||
* <p>
|
||||
* The batch size can be set on a transaction via {@link com.avaje.ebean.Transaction#setDocStoreUpdateBatchSize(int)}.
|
||||
* </p>
|
||||
*/
|
||||
public void setBulkBatchSize(int bulkBatchSize) {
|
||||
this.bulkBatchSize = bulkBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load settings specified in properties files.
|
||||
*/
|
||||
@@ -132,7 +236,13 @@ public class DocStoreConfig {
|
||||
|
||||
active = properties.getBoolean("docstore.active", active);
|
||||
url = properties.get("docstore.url", url);
|
||||
persist = properties.getEnum(DocStoreEvent.class, "docstore.persist", persist);
|
||||
persist = properties.getEnum(DocStoreMode.class, "docstore.persist", persist);
|
||||
bulkBatchSize = properties.getInt("docstore.bulkBatchSize", bulkBatchSize);
|
||||
generateMapping = properties.getBoolean("docstore.generateMapping", generateMapping);
|
||||
dropCreate = properties.getBoolean("docstore.dropCreate", dropCreate);
|
||||
create = properties.getBoolean("docstore.create", create);
|
||||
mappingPath = properties.get("docstore.mappingPath", mappingPath);
|
||||
mappingSuffix = properties.get("docstore.mappingSuffix", mappingSuffix);
|
||||
pathToResources = properties.get("docstore.pathToResources", pathToResources);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2250,14 +2250,14 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is broken out for the same reason as above - preserve existing behaviour but let it be overridden.
|
||||
* This is broken out to allow overridden behaviour.
|
||||
*/
|
||||
protected void loadDocStoreSettings(PropertiesWrapper p) {
|
||||
docStoreConfig.loadSettings(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is broken out for the same reason as above - preserve existing behaviour but let it be overridden.
|
||||
* This is broken out to allow overridden behaviour.
|
||||
*/
|
||||
protected void loadAutoTuneSettings(PropertiesWrapper p) {
|
||||
autoTuneConfig.loadSettings(p);
|
||||
@@ -2287,7 +2287,7 @@ public class ServerConfig {
|
||||
if (docStoreConfig == null) {
|
||||
docStoreConfig = new DocStoreConfig();
|
||||
}
|
||||
docStoreConfig.loadSettings(p);
|
||||
loadDocStoreSettings(p);
|
||||
|
||||
explicitTransactionBeginMode = p.getBoolean("explicitTransactionBeginMode", explicitTransactionBeginMode);
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.util.CamelCaseHelper;
|
||||
|
||||
/**
|
||||
* Converts between Camel Case and Underscore based names for both table and
|
||||
* column names (and is the default naming convention in Ebean).
|
||||
@@ -141,21 +143,6 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention {
|
||||
* Convert and return the from string from underscore to camel case.
|
||||
*/
|
||||
protected String toCamelFromUnderscore(String underscore) {
|
||||
|
||||
StringBuilder result = new StringBuilder(underscore.length());
|
||||
String[] vals = underscore.split("_");
|
||||
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
String lower = vals[i].toLowerCase();
|
||||
if (i > 0) {
|
||||
char c = Character.toUpperCase(lower.charAt(0));
|
||||
result.append(c);
|
||||
result.append(lower.substring(1));
|
||||
} else {
|
||||
result.append(lower);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
return CamelCaseHelper.toCamelFromUnderscore(underscore);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public class DB2Platform extends DatabasePlatform {
|
||||
this.maxTableNameLength = 18;
|
||||
this.maxConstraintNameLength = 18;
|
||||
this.sqlLimiter = new Db2SqlLimiter();
|
||||
this.platformDdl = new DB2Ddl(dbTypeMap, dbIdentity);
|
||||
this.platformDdl = new DB2Ddl(this);
|
||||
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
@@ -18,7 +18,6 @@ public class DatabasePlatform {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DatabasePlatform.class);
|
||||
|
||||
|
||||
/**
|
||||
* Behavior used when ending a query only transaction (at read committed isolation level).
|
||||
*/
|
||||
@@ -72,6 +71,11 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected DbTypeMap dbTypeMap = new DbTypeMap();
|
||||
|
||||
/**
|
||||
* Default values for DB columns.
|
||||
*/
|
||||
protected DbDefaultValue dbDefaultValue = new DbDefaultValue();
|
||||
|
||||
/**
|
||||
* Set to true if the DB has native UUID type support.
|
||||
*/
|
||||
@@ -291,6 +295,13 @@ public class DatabasePlatform {
|
||||
return dbTypeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mapping for DB column default values.
|
||||
*/
|
||||
public DbDefaultValue getDbDefaultValue() {
|
||||
return dbDefaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column alias prefix.
|
||||
*/
|
||||
@@ -425,6 +436,20 @@ public class DatabasePlatform {
|
||||
return sqlLimiter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB TRUE literal (from the registered boolean ScalarType)
|
||||
*/
|
||||
public void setDbTrueLiteral(String dbTrueLiteral) {
|
||||
this.dbDefaultValue.setTrue(dbTrueLiteral);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB FALSE literal (from the registered boolean ScalarType)
|
||||
*/
|
||||
public void setDbFalseLiteral(String dbFalseLiteral) {
|
||||
this.dbDefaultValue.setFalse(dbFalseLiteral);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert backticks to the platform specific open quote and close quote
|
||||
* <p>
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* DB Column default values mapping to database platform specific literals.
|
||||
*/
|
||||
public class DbDefaultValue {
|
||||
|
||||
/**
|
||||
* The key for FALSE.
|
||||
*/
|
||||
public static final String FALSE = "false";
|
||||
|
||||
/**
|
||||
* The key for TRUE.
|
||||
*/
|
||||
public static final String TRUE = "true";
|
||||
|
||||
/**
|
||||
* The key for the NOW / current timestamp.
|
||||
*/
|
||||
public static final String NOW = "now";
|
||||
|
||||
protected Map<String,String> map = new LinkedHashMap<String,String>();
|
||||
|
||||
/**
|
||||
* Set the DB now function.
|
||||
*/
|
||||
public void setNow(String dbFunction) {
|
||||
put(NOW, dbFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB false literal.
|
||||
*/
|
||||
public void setFalse(String dbFalseLiteral) {
|
||||
put(FALSE, dbFalseLiteral);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB true literal.
|
||||
*/
|
||||
public void setTrue(String dbTrueLiteral) {
|
||||
put(TRUE, dbTrueLiteral);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an translation entry.
|
||||
*/
|
||||
public void put(String dbLiteral, String dbTranslated) {
|
||||
map.put(dbLiteral, dbTranslated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the DB default literal to platform specific type or function.
|
||||
* <p>
|
||||
* This is intended for the DB column default clause in DDL.
|
||||
* </p>
|
||||
*/
|
||||
public String convert(String dbDefaultLiteral) {
|
||||
if (dbDefaultLiteral == null) {
|
||||
return null;
|
||||
}
|
||||
String val = map.get(dbDefaultLiteral);
|
||||
return val != null ? val : dbDefaultLiteral;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,9 +14,10 @@ public class H2Platform extends DatabasePlatform {
|
||||
super();
|
||||
this.name = "h2";
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
this.platformDdl = new H2Ddl(this.dbTypeMap, dbIdentity);
|
||||
this.platformDdl = new H2Ddl(this);
|
||||
this.historySupport = new H2HistorySupport();
|
||||
this.nativeUuidType = true;
|
||||
this.dbDefaultValue.setNow("now()");
|
||||
|
||||
// only support getGeneratedKeys with non-batch JDBC
|
||||
// so generally use SEQUENCE instead of IDENTITY for H2
|
||||
|
||||
@@ -15,7 +15,7 @@ public class HsqldbPlatform extends DatabasePlatform {
|
||||
super();
|
||||
this.name = "hsqldb";
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
this.platformDdl = new HsqldbDdl(dbTypeMap, dbIdentity);
|
||||
this.platformDdl = new HsqldbDdl(this);
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
|
||||
@@ -25,7 +25,7 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
|
||||
this.idInExpandedForm = true;
|
||||
this.selectCountWithAlias = true;
|
||||
this.sqlLimiter = new MsSqlServer2005SqlLimiter();
|
||||
this.platformDdl = new MsSqlServerDdl(dbTypeMap, dbIdentity);
|
||||
this.platformDdl = new MsSqlServerDdl(this);
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
@@ -25,7 +25,7 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
this.likeClause = "like ? escape''";
|
||||
this.selectCountWithAlias = true;
|
||||
this.dbEncrypt = new MySqlDbEncrypt();
|
||||
this.platformDdl = new MySqlDdl(this.dbTypeMap, this.dbIdentity);
|
||||
this.platformDdl = new MySqlDdl(this);
|
||||
this.historySupport = new MySqlHistorySupport();
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
|
||||
@@ -18,7 +18,7 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
this.maxConstraintNameLength = 30;
|
||||
this.dbEncrypt = new OracleDbEncrypt();
|
||||
this.sqlLimiter = new RownumSqlLimiter();
|
||||
this.platformDdl = new Oracle10Ddl(this.dbTypeMap, this.dbIdentity);
|
||||
this.platformDdl = new Oracle10Ddl(this);
|
||||
this.historySupport = new OracleDbHistorySupport();
|
||||
|
||||
// Not using getGeneratedKeys as instead we will
|
||||
|
||||
@@ -27,7 +27,7 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
|
||||
this.dbEncrypt = new PostgresDbEncrypt();
|
||||
this.historySupport = new PostgresHistorySupport();
|
||||
this.platformDdl = new PostgresDdl(this.dbTypeMap, this.dbIdentity);
|
||||
this.platformDdl = new PostgresDdl(this);
|
||||
|
||||
// Use Identity and getGeneratedKeys
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
|
||||
@@ -9,7 +9,7 @@ public class SQLitePlatform extends DatabasePlatform {
|
||||
public SQLitePlatform() {
|
||||
super();
|
||||
this.name = "sqlite";
|
||||
this.platformDdl = new SQLiteDdl(dbTypeMap, dbIdentity);
|
||||
this.platformDdl = new SQLiteDdl(this);
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
|
||||
@@ -123,6 +123,9 @@ public class BaseTableDdl implements TableDdl {
|
||||
// defined on the columns
|
||||
writePrimaryKeyConstraint(apply, createTable.getPkName(), toColumnNames(pk));
|
||||
}
|
||||
if (platformDdl.isInlineForeignKeys()) {
|
||||
writeInlineForeignKeys(writer, createTable);
|
||||
}
|
||||
|
||||
apply.newLine().append(")");
|
||||
addTableCommentInline(apply, createTable);
|
||||
@@ -151,8 +154,9 @@ public class BaseTableDdl implements TableDdl {
|
||||
apply.end();
|
||||
writer.dropAll().end();
|
||||
|
||||
writeAddForeignKeys(writer, createTable);
|
||||
|
||||
if (!platformDdl.isInlineForeignKeys()) {
|
||||
writeAddForeignKeys(writer, createTable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -235,6 +239,43 @@ public class BaseTableDdl implements TableDdl {
|
||||
platformDdl.createWithHistory(writer, table);
|
||||
}
|
||||
|
||||
protected void writeInlineForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
|
||||
|
||||
for (Column column : createTable.getColumn()) {
|
||||
String references = column.getReferences();
|
||||
if (hasValue(references)) {
|
||||
writeInlineForeignKey(write, column);
|
||||
}
|
||||
}
|
||||
writeInlineCompoundForeignKeys(write, createTable);
|
||||
}
|
||||
|
||||
protected void writeInlineForeignKey(DdlWrite write, Column column) throws IOException {
|
||||
|
||||
String references = column.getReferences();
|
||||
int pos = references.lastIndexOf('.');
|
||||
if (pos == -1) {
|
||||
throw new IllegalStateException("Expecting period '.' character for table.column split but not found in [" + references + "]");
|
||||
}
|
||||
String refTableName = references.substring(0, pos);
|
||||
String refColumnName = references.substring(pos + 1);
|
||||
String fkConstraint = platformDdl.tableInlineForeignKey(new String[]{column.getName()}, refTableName, new String[]{refColumnName});
|
||||
write.apply().append(",").newLine().append(" ").append(fkConstraint);
|
||||
}
|
||||
|
||||
protected void writeInlineCompoundForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
|
||||
|
||||
List<ForeignKey> foreignKey = createTable.getForeignKey();
|
||||
for (ForeignKey key : foreignKey) {
|
||||
String refTableName = key.getRefTableName();
|
||||
String[] cols = toColumnNamesSplit(key.getColumnNames());
|
||||
String[] refColumns = toColumnNamesSplit(key.getRefColumnNames());
|
||||
|
||||
String fkConstraint = platformDdl.tableInlineForeignKey(cols, refTableName, refColumns);
|
||||
write.apply().append(",").newLine().append(" ").append(fkConstraint);
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeAddForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
|
||||
|
||||
String tableName = createTable.getName();
|
||||
@@ -309,7 +350,10 @@ public class BaseTableDdl implements TableDdl {
|
||||
|
||||
protected void alterTableAddForeignKey(DdlBuffer buffer, String fkName, String tableName, String[] columns, String refTable, String[] refColumns) throws IOException {
|
||||
|
||||
buffer.append(platformDdl.alterTableAddForeignKey(tableName, fkName, columns, refTable, refColumns)).endOfStatement();
|
||||
String fkConstraint = platformDdl.alterTableAddForeignKey(tableName, fkName, columns, refTable, refColumns);
|
||||
if (fkConstraint != null && !fkConstraint.isEmpty()) {
|
||||
buffer.append(fkConstraint).endOfStatement();
|
||||
}
|
||||
}
|
||||
|
||||
protected void appendColumns(String[] columns, DdlBuffer buffer) throws IOException {
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
/**
|
||||
* DB2 platform specific DDL.
|
||||
*/
|
||||
public class DB2Ddl extends PlatformDdl {
|
||||
|
||||
public DB2Ddl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
public DB2Ddl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.identitySuffix = " generated by default as identity";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
/**
|
||||
* H2 platform specific DDL.
|
||||
*/
|
||||
public class H2Ddl extends PlatformDdl {
|
||||
|
||||
public H2Ddl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
public H2Ddl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.historyDdl = new H2HistoryDdl();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
/**
|
||||
* Hsqldb platform specific DDL.
|
||||
*/
|
||||
public class HsqldbDdl extends PlatformDdl {
|
||||
|
||||
public HsqldbDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
public HsqldbDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.identitySuffix = " generated by default as identity (start with 1) ";
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import com.avaje.ebean.dbmigration.migration.AlterColumn;
|
||||
|
||||
@@ -12,8 +11,8 @@ import java.io.IOException;
|
||||
*/
|
||||
public class MsSqlServerDdl extends PlatformDdl {
|
||||
|
||||
public MsSqlServerDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
public MsSqlServerDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.identitySuffix = " identity(1,1)";
|
||||
this.foreignKeyRestrict = "";
|
||||
this.inlineUniqueOneToOne = false;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import com.avaje.ebean.dbmigration.migration.AlterColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.Column;
|
||||
@@ -14,8 +13,8 @@ import java.io.IOException;
|
||||
*/
|
||||
public class MySqlDdl extends PlatformDdl {
|
||||
|
||||
public MySqlDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
public MySqlDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.alterColumn = "modify";
|
||||
this.dropUniqueConstraint = "drop index";
|
||||
this.historyDdl = new MySqlHistoryDdl();
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
/**
|
||||
* Oracle platform specific DDL.
|
||||
*/
|
||||
public class Oracle10Ddl extends PlatformDdl {
|
||||
|
||||
public Oracle10Ddl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
public Oracle10Ddl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.dropTableIfExists = "drop table ";
|
||||
this.dropSequenceIfExists = "drop sequence ";
|
||||
this.dropTableCascade = " cascade constraints purge";
|
||||
|
||||
@@ -2,8 +2,9 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.DbConstraintNaming;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbDefaultValue;
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.IdType;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.BaseDdlHandler;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
|
||||
@@ -85,9 +86,17 @@ public class PlatformDdl {
|
||||
|
||||
protected DbConstraintNaming naming;
|
||||
|
||||
public PlatformDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
this.dbIdentity = dbIdentity;
|
||||
this.typeConverter = new PlatformTypeConverter(platformTypes);
|
||||
/**
|
||||
* Generally not desired as then they are not named (used with SQLite).
|
||||
*/
|
||||
protected boolean inlineForeignKeys;
|
||||
|
||||
protected final DbDefaultValue dbDefaultValue;
|
||||
|
||||
public PlatformDdl(DatabasePlatform platform) {
|
||||
this.dbIdentity = platform.getDbIdentity();
|
||||
this.dbDefaultValue = platform.getDbDefaultValue();
|
||||
this.typeConverter = new PlatformTypeConverter(platform.getDbTypeMap());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,6 +137,14 @@ public class PlatformDdl {
|
||||
return inlineComments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if foreign key reference constraints need to inlined with create table.
|
||||
* Ideally we don't do this as then the constraints are not named. Do this for SQLite.
|
||||
*/
|
||||
public boolean isInlineForeignKeys() {
|
||||
return inlineForeignKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write all the table columns converting to platform types as necessary.
|
||||
*/
|
||||
@@ -152,6 +169,12 @@ public class PlatformDdl {
|
||||
buffer.append(" ");
|
||||
buffer.append(lowerColumnName(column.getName()), 29);
|
||||
buffer.append(platformType);
|
||||
if (!typeContainsDefault(platformType)) {
|
||||
String defaultValue = convertDefaultValue(column.getDefaultValue());
|
||||
if (defaultValue != null) {
|
||||
buffer.append(" default ").append(defaultValue);
|
||||
}
|
||||
}
|
||||
if (isTrue(column.isNotnull()) || isTrue(column.isPrimaryKey())) {
|
||||
buffer.append(" not null");
|
||||
}
|
||||
@@ -160,6 +183,20 @@ public class PlatformDdl {
|
||||
// so that the database can potentially provide a nice SQL error
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the type definition already contains a default value.
|
||||
*/
|
||||
private boolean typeContainsDefault(String platformType) {
|
||||
return platformType.toLowerCase().contains(" default");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the DB column default literal to platform specific.
|
||||
*/
|
||||
private String convertDefaultValue(String dbDefault) {
|
||||
return dbDefaultValue.convert(dbDefault);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the drop foreign key clause.
|
||||
*/
|
||||
@@ -255,6 +292,20 @@ public class PlatformDdl {
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign key constraint when used inline with create table.
|
||||
*/
|
||||
public String tableInlineForeignKey(String[] columns, String refTable, String[] refColumns) {
|
||||
|
||||
StringBuilder buffer = new StringBuilder(90);
|
||||
buffer.append("foreign key");
|
||||
appendColumns(columns, buffer);
|
||||
buffer.append(" references ").append(lowerTableName(refTable));
|
||||
appendColumns(refColumns, buffer);
|
||||
appendWithSpace(foreignKeyRestrict, buffer);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add foreign key.
|
||||
*/
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
/**
|
||||
* Postgres specific DDL.
|
||||
*/
|
||||
public class PostgresDdl extends PlatformDdl {
|
||||
|
||||
public PostgresDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
public PostgresDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.historyDdl = new PostgresHistoryDdl();
|
||||
this.dropTableCascade = " cascade";
|
||||
this.columnSetType = "type ";
|
||||
|
||||
@@ -1,16 +1,34 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* DB2 platform specific DDL.
|
||||
*/
|
||||
public class SQLiteDdl extends PlatformDdl {
|
||||
|
||||
public SQLiteDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
this.identitySuffix = " autoincrement";
|
||||
public SQLiteDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.identitySuffix = "";
|
||||
this.inlineForeignKeys = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableComment(DdlBuffer apply, String tableName, String tableComment) throws IOException {
|
||||
// not supported
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addColumnComment(DdlBuffer apply, String table, String column, String comment) throws IOException {
|
||||
// not supported
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterTableAddForeignKey(String tableName, String fkName, String[] columns, String refTable, String[] refColumns) {
|
||||
// not supported
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -230,6 +230,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
}
|
||||
|
||||
MColumn col = new MColumn(p.getDbColumn(), ctx.getColumnDefn(p));
|
||||
col.setDefaultValue(p.getDbColumnDefault());
|
||||
col.setComment(p.getDbComment());
|
||||
col.setDraftOnly(p.isDraftOnly());
|
||||
|
||||
|
||||
@@ -5,11 +5,9 @@ import com.avaje.ebean.event.BeanFindController;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.text.json.JsonReadOptions;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocumentMapping;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
@@ -17,6 +15,11 @@ import java.util.Collection;
|
||||
*/
|
||||
public interface BeanType<T> {
|
||||
|
||||
/**
|
||||
* Return the short name of the bean type.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the full name of the bean type.
|
||||
*/
|
||||
@@ -53,12 +56,12 @@ public interface BeanType<T> {
|
||||
Property getWhenCreatedProperty();
|
||||
|
||||
/**
|
||||
* Return the SpiProperty for a property to read values from a bean.
|
||||
* Return the Property to read values from a bean.
|
||||
*/
|
||||
Property getProperty(String propertyName);
|
||||
|
||||
/**
|
||||
* Return the SpiExpressionPath for a given property path.
|
||||
* Return the ExpressionPath for a given property path.
|
||||
* <p>
|
||||
* This can return a property or nested property path.
|
||||
* </p>
|
||||
@@ -150,8 +153,27 @@ public interface BeanType<T> {
|
||||
BeanDocType<T> docStore();
|
||||
|
||||
/**
|
||||
* Read the JSON content returning the bean.
|
||||
* Add the discriminator value to the query if needed.
|
||||
*/
|
||||
T jsonRead(JsonParser parser, JsonReadOptions readOptions, Object objectMapper) throws IOException;
|
||||
void addInheritanceWhere(SpiQuery<?> query);
|
||||
|
||||
/**
|
||||
* Return the root bean type for an inheritance hierarchy.
|
||||
*/
|
||||
BeanType<?> root();
|
||||
|
||||
/**
|
||||
* Return true if this bean type has an inheritance hierarchy.
|
||||
*/
|
||||
boolean hasInheritance();
|
||||
|
||||
/**
|
||||
* Return the discriminator column.
|
||||
*/
|
||||
String getDiscColumn();
|
||||
|
||||
/**
|
||||
* Create a bean given the discriminator value.
|
||||
*/
|
||||
T createBeanUsingDisc(Object discValue);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.avaje.ebean.plugin;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.text.StringParser;
|
||||
|
||||
/**
|
||||
* A dot notation expression path.
|
||||
*/
|
||||
@@ -10,11 +13,64 @@ public interface ExpressionPath {
|
||||
*/
|
||||
boolean containsMany();
|
||||
|
||||
/**
|
||||
* Return the value from a given entity bean.
|
||||
*/
|
||||
Object pathGet(Object bean);
|
||||
|
||||
/**
|
||||
* Set a value to the bean for this expression path.
|
||||
*
|
||||
* @param bean the bean to set the value on
|
||||
* @param value the value to set
|
||||
*/
|
||||
void set(Object bean, Object value);
|
||||
void pathSet(Object bean, Object value);
|
||||
|
||||
/**
|
||||
* Convert the value to the expected type.
|
||||
* <p>
|
||||
* Typically useful for converting strings to the appropriate number type etc.
|
||||
* </p>
|
||||
*/
|
||||
Object convert(Object value);
|
||||
|
||||
/**
|
||||
* Return the default StringParser for the scalar property.
|
||||
*/
|
||||
StringParser getStringParser();
|
||||
|
||||
/**
|
||||
* For DateTime capable scalar types convert the long systemTimeMillis into
|
||||
* an appropriate java time (Date,Timestamp,Time,Calendar, JODA type etc).
|
||||
*/
|
||||
Object parseDateTime(long systemTimeMillis);
|
||||
|
||||
/**
|
||||
* Return true if the last type is "DateTime capable" - can support
|
||||
* {@link #parseDateTime(long)}.
|
||||
*/
|
||||
boolean isDateTimeCapable();
|
||||
|
||||
/**
|
||||
* Return the underlying JDBC type or 0 if this is not a scalar type.
|
||||
*/
|
||||
int getJdbcType();
|
||||
|
||||
/**
|
||||
* Return true if this is an ManyToOne or OneToOne associated bean property.
|
||||
*/
|
||||
boolean isAssocId();
|
||||
|
||||
/**
|
||||
* Return the Id expression string.
|
||||
* <p>
|
||||
* Typically used to produce id = ? expression strings.
|
||||
* </p>
|
||||
*/
|
||||
String getAssocIdExpression(String propName, String bindOperator);
|
||||
|
||||
/**
|
||||
* Return the Id values for the given bean value.
|
||||
*/
|
||||
Object[] getAssocIdValues(EntityBean bean);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.avaje.ebean.search;
|
||||
|
||||
/**
|
||||
* Options for the text match and multi match expressions.
|
||||
*/
|
||||
public abstract class AbstractMatch {
|
||||
|
||||
protected boolean operatorAnd;
|
||||
|
||||
protected String analyzer;
|
||||
|
||||
protected double boost;
|
||||
|
||||
protected String minShouldMatch;
|
||||
|
||||
protected int maxExpansions;
|
||||
|
||||
protected String zeroTerms;
|
||||
|
||||
protected double cutoffFrequency;
|
||||
|
||||
protected String fuzziness;
|
||||
|
||||
protected int prefixLength;
|
||||
|
||||
protected String rewrite;
|
||||
|
||||
/**
|
||||
* Return true if using the AND operator otherwise using the OR operator.
|
||||
*/
|
||||
public boolean isOperatorAnd() {
|
||||
return operatorAnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the boost.
|
||||
*/
|
||||
public double getBoost() {
|
||||
return boost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum should match.
|
||||
*/
|
||||
public String getMinShouldMatch() {
|
||||
return minShouldMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the zero terms option.
|
||||
*/
|
||||
public String getZeroTerms() {
|
||||
return zeroTerms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cutoff frequency.
|
||||
*/
|
||||
public double getCutoffFrequency() {
|
||||
return cutoffFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the max expansions.
|
||||
*/
|
||||
public int getMaxExpansions() {
|
||||
return maxExpansions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the analyzer.
|
||||
*/
|
||||
public String getAnalyzer() {
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fuzziness.
|
||||
*/
|
||||
public String getFuzziness() {
|
||||
return fuzziness;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the prefix length.
|
||||
*/
|
||||
public int getPrefixLength() {
|
||||
return prefixLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rewrite option.
|
||||
*/
|
||||
public String getRewrite() {
|
||||
return rewrite;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.avaje.ebean.search;
|
||||
|
||||
/**
|
||||
* Options for the text match expression.
|
||||
*/
|
||||
public class Match extends AbstractMatch {
|
||||
|
||||
protected boolean phrase;
|
||||
|
||||
protected boolean phrasePrefix;
|
||||
|
||||
public Match() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to be a "Phrase" type expression.
|
||||
*/
|
||||
public Match phrase() {
|
||||
phrase = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to be a "Phrase Prefix" type expression.
|
||||
*/
|
||||
public Match phrasePrefix() {
|
||||
phrasePrefix = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the AND operator (rather than OR).
|
||||
*/
|
||||
public Match opAnd() {
|
||||
operatorAnd = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the OR operator (rather than AND).
|
||||
*/
|
||||
public Match opOr() {
|
||||
operatorAnd = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the zero terms.
|
||||
*/
|
||||
public Match zeroTerms(String zeroTerms) {
|
||||
this.zeroTerms = zeroTerms;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cutoff frequency.
|
||||
*/
|
||||
public Match cutoffFrequency(double cutoffFrequency) {
|
||||
this.cutoffFrequency = cutoffFrequency;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the max expansions (for phrase prefix only).
|
||||
*/
|
||||
public Match maxExpansions(int maxExpansions) {
|
||||
this.maxExpansions = maxExpansions;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Analyzer to use for this expression.
|
||||
*/
|
||||
public Match analyzer(String analyzer) {
|
||||
this.analyzer = analyzer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the boost.
|
||||
*/
|
||||
public Match boost(double boost) {
|
||||
this.boost = boost;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rewrite to use.
|
||||
*/
|
||||
public Match minShouldMatch(String minShouldMatch) {
|
||||
this.minShouldMatch = minShouldMatch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rewrite to use.
|
||||
*/
|
||||
public Match rewrite(String rewrite) {
|
||||
this.rewrite = rewrite;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a phrase query.
|
||||
*/
|
||||
public boolean isPhrase() {
|
||||
return phrase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a phrase prefix query.
|
||||
*/
|
||||
public boolean isPhrasePrefix() {
|
||||
return phrasePrefix;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.avaje.ebean.search;
|
||||
|
||||
/**
|
||||
* Options for the text match expression.
|
||||
*/
|
||||
public class MultiMatch extends AbstractMatch {
|
||||
|
||||
/**
|
||||
* The MultiMatch type.
|
||||
*/
|
||||
public enum Type {
|
||||
BEST_FIELDS,
|
||||
MOST_FIELDS,
|
||||
CROSS_FIELDS,
|
||||
PHRASE,
|
||||
PHRASE_PREFIX
|
||||
}
|
||||
|
||||
protected final String[] fields;
|
||||
|
||||
protected Type type = Type.BEST_FIELDS;
|
||||
|
||||
protected double tieBreaker;
|
||||
|
||||
/**
|
||||
* Create with the given fields.
|
||||
*/
|
||||
public static MultiMatch fields(String... fields) {
|
||||
return new MultiMatch(fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a set of fields.
|
||||
*/
|
||||
public MultiMatch(String... fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of query.
|
||||
*/
|
||||
public MultiMatch type(Type type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tieBreaker to use.
|
||||
*/
|
||||
public MultiMatch tieBreaker(double tieBreaker) {
|
||||
this.tieBreaker = tieBreaker;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the AND operator (rather than OR).
|
||||
*/
|
||||
public MultiMatch opAnd() {
|
||||
operatorAnd = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the OR operator (rather than AND).
|
||||
*/
|
||||
public MultiMatch opOr() {
|
||||
operatorAnd = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum should match value.
|
||||
*/
|
||||
public MultiMatch minShouldMatch(String minShouldMatch) {
|
||||
this.minShouldMatch = minShouldMatch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the boost.
|
||||
*/
|
||||
public MultiMatch boost(double boost) {
|
||||
this.boost = boost;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the zero terms.
|
||||
*/
|
||||
public MultiMatch zeroTerms(String zeroTerms) {
|
||||
this.zeroTerms = zeroTerms;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cutoff frequency.
|
||||
*/
|
||||
public MultiMatch cutoffFrequency(double cutoffFrequency) {
|
||||
this.cutoffFrequency = cutoffFrequency;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the max expansions (for phrase prefix only).
|
||||
*/
|
||||
public MultiMatch maxExpansions(int maxExpansions) {
|
||||
this.maxExpansions = maxExpansions;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Analyzer to use for this expression.
|
||||
*/
|
||||
public MultiMatch analyzer(String analyzer) {
|
||||
this.analyzer = analyzer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rewrite to use.
|
||||
*/
|
||||
public MultiMatch rewrite(String rewrite) {
|
||||
this.rewrite = rewrite;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type.
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fields to search.
|
||||
*/
|
||||
public String[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tie breaker.
|
||||
*/
|
||||
public double getTieBreaker() {
|
||||
return tieBreaker;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.avaje.ebean.search;
|
||||
|
||||
/**
|
||||
* Text common terms query.
|
||||
* <p>
|
||||
* This maps to an ElasticSearch "common terms query".
|
||||
* </p>
|
||||
|
||||
* <pre>{@code
|
||||
*
|
||||
* TextCommonTerms options = new TextCommonTerms()
|
||||
* .cutoffFrequency(0.001)
|
||||
* .minShouldMatch("50%")
|
||||
* .lowFreqOperatorAnd(true)
|
||||
* .highFreqOperatorAnd(true);
|
||||
*
|
||||
* List<Customer> customers = server.find(Customer.class)
|
||||
* .text()
|
||||
* .textCommonTerms("the brown", options)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // ElasticSearch expression
|
||||
*
|
||||
* "common": {
|
||||
* "body": {
|
||||
* "query": "the brown",
|
||||
* "cutoff_frequency": 0.001,
|
||||
* "low_freq_operator": "and",
|
||||
* "high_freq_operator": "and",
|
||||
* "minimum_should_match": "50%"
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public class TextCommonTerms {
|
||||
|
||||
protected double cutoffFrequency;
|
||||
|
||||
protected boolean lowFreqOperatorAnd;
|
||||
protected boolean highFreqOperatorAnd;
|
||||
|
||||
protected String minShouldMatch;
|
||||
protected String minShouldMatchLowFreq;
|
||||
protected String minShouldMatchHighFreq;
|
||||
|
||||
/**
|
||||
* Set the cutoff frequency.
|
||||
*/
|
||||
public TextCommonTerms cutoffFrequency(double cutoffFrequency) {
|
||||
this.cutoffFrequency = cutoffFrequency;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if low frequency terms should use AND operator.
|
||||
*/
|
||||
public TextCommonTerms lowFreqOperatorAnd(boolean opAnd) {
|
||||
this.lowFreqOperatorAnd = opAnd;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if high frequency terms should use AND operator.
|
||||
*/
|
||||
public TextCommonTerms highFreqOperatorAnd(boolean opAnd) {
|
||||
this.highFreqOperatorAnd = opAnd;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum should match.
|
||||
*/
|
||||
public TextCommonTerms minShouldMatch(String minShouldMatch) {
|
||||
this.minShouldMatch = minShouldMatch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum should match for low frequency terms.
|
||||
*/
|
||||
public TextCommonTerms minShouldMatchLowFreq(String minShouldMatchLowFreq) {
|
||||
this.minShouldMatchLowFreq = minShouldMatchLowFreq;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum should match for high frequency terms.
|
||||
*/
|
||||
public TextCommonTerms minShouldMatchHighFreq(String minShouldMatchHighFreq) {
|
||||
this.minShouldMatchHighFreq = minShouldMatchHighFreq;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if low freq should use the AND operator.
|
||||
*/
|
||||
public boolean isLowFreqOperatorAnd() {
|
||||
return lowFreqOperatorAnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if high freq should use the AND operator.
|
||||
*/
|
||||
public boolean isHighFreqOperatorAnd() {
|
||||
return highFreqOperatorAnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cutoff frequency.
|
||||
*/
|
||||
public double getCutoffFrequency() {
|
||||
return cutoffFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum to match.
|
||||
*/
|
||||
public String getMinShouldMatch() {
|
||||
return minShouldMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum to match for high frequency.
|
||||
*/
|
||||
public String getMinShouldMatchHighFreq() {
|
||||
return minShouldMatchHighFreq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum to match for low frequency.
|
||||
*/
|
||||
public String getMinShouldMatchLowFreq() {
|
||||
return minShouldMatchLowFreq;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
package com.avaje.ebean.search;
|
||||
|
||||
/**
|
||||
* Text query string options.
|
||||
* <p>
|
||||
* This maps to an ElasticSearch "query string query".
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* TextQueryString options = new TextQueryString()
|
||||
* .analyzeWildcard(true)
|
||||
* .fields("name")
|
||||
* .lenient(true)
|
||||
* .opAnd();
|
||||
*
|
||||
* List<Customer> customers = server.find(Customer.class)
|
||||
* .text()
|
||||
* .textSimple("quick brown", options)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // just use default options
|
||||
* TextQueryString options = new TextQueryString();
|
||||
*
|
||||
* List<Customer> customers = server.find(Customer.class)
|
||||
* .text()
|
||||
* .textSimple("quick brown", options)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
public class TextQueryString {
|
||||
|
||||
public static final int DEFAULT_FUZZY_MAX_EXPANSIONS = 50;
|
||||
public static final int DEFAULT_MAX_DETERMINIZED_STATES = 10000;
|
||||
|
||||
protected final String[] fields;
|
||||
|
||||
/**
|
||||
* Only used when multiple fields set.
|
||||
*/
|
||||
protected boolean useDisMax = true;
|
||||
|
||||
/**
|
||||
* Only used when multiple fields set.
|
||||
*/
|
||||
protected double tieBreaker;
|
||||
|
||||
protected String defaultField;
|
||||
|
||||
protected boolean operatorAnd;
|
||||
|
||||
protected String analyzer;
|
||||
|
||||
protected boolean allowLeadingWildcard = true;
|
||||
|
||||
protected boolean lowercaseExpandedTerms = true;
|
||||
|
||||
protected boolean enablePositionIncrements = true;
|
||||
|
||||
protected int fuzzyMaxExpansions = DEFAULT_FUZZY_MAX_EXPANSIONS;
|
||||
|
||||
protected String fuzziness;
|
||||
|
||||
protected int fuzzyPrefixLength;
|
||||
|
||||
protected double phraseSlop;
|
||||
|
||||
protected double boost;
|
||||
|
||||
protected boolean analyzeWildcard;
|
||||
|
||||
protected boolean autoGeneratePhraseQueries;
|
||||
|
||||
protected int maxDeterminizedStates = DEFAULT_MAX_DETERMINIZED_STATES;
|
||||
|
||||
protected String minShouldMatch;
|
||||
|
||||
protected boolean lenient;
|
||||
|
||||
protected String locale;
|
||||
|
||||
protected String timeZone;
|
||||
|
||||
protected String rewrite;
|
||||
|
||||
/**
|
||||
* Create with given fields.
|
||||
*/
|
||||
public static TextQueryString fields(String... fields) {
|
||||
return new TextQueryString(fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with the fields to use.
|
||||
*/
|
||||
public TextQueryString(String... fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the AND operator (rather than OR).
|
||||
*/
|
||||
public TextQueryString opAnd() {
|
||||
this.operatorAnd = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the OR operator (rather than AND).
|
||||
*/
|
||||
public TextQueryString opOr() {
|
||||
this.operatorAnd = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the locale.
|
||||
*/
|
||||
public TextQueryString locale(String locale) {
|
||||
this.locale = locale;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set lenient mode.
|
||||
*/
|
||||
public TextQueryString lenient(boolean lenient) {
|
||||
this.lenient = lenient;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum should match.
|
||||
*/
|
||||
public TextQueryString minShouldMatch(String minShouldMatch) {
|
||||
this.minShouldMatch = minShouldMatch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the analyzer.
|
||||
*/
|
||||
public TextQueryString analyzer(String analyzer) {
|
||||
this.analyzer = analyzer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set useDisMax option (when multiple fields only).
|
||||
*/
|
||||
public TextQueryString useDisMax(boolean useDisMax) {
|
||||
this.useDisMax = useDisMax;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set tieBreaker option (when multiple fields only).
|
||||
*/
|
||||
public TextQueryString tieBreaker(double tieBreaker) {
|
||||
this.tieBreaker = tieBreaker;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default field.
|
||||
*/
|
||||
public TextQueryString defaultField(String defaultField) {
|
||||
this.defaultField = defaultField;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set allow leading wildcard mode.
|
||||
*/
|
||||
public TextQueryString allowLeadingWildcard(boolean allowLeadingWildcard) {
|
||||
this.allowLeadingWildcard = allowLeadingWildcard;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set lowercase expanded terms mode.
|
||||
*/
|
||||
public TextQueryString lowercaseExpandedTerms(boolean lowercaseExpandedTerms) {
|
||||
this.lowercaseExpandedTerms = lowercaseExpandedTerms;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set enable position increments mode.
|
||||
*/
|
||||
public TextQueryString enablePositionIncrements(boolean enablePositionIncrements) {
|
||||
this.enablePositionIncrements = enablePositionIncrements;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set fuzzy max expansions.
|
||||
*/
|
||||
public TextQueryString fuzzyMaxExpansions(int fuzzyMaxExpansions) {
|
||||
this.fuzzyMaxExpansions = fuzzyMaxExpansions;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set fuzziness.
|
||||
*/
|
||||
public TextQueryString fuzziness(String fuzziness) {
|
||||
this.fuzziness = fuzziness;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the fuzzy prefix length.
|
||||
*/
|
||||
public TextQueryString fuzzyPrefixLength(int fuzzyPrefixLength) {
|
||||
this.fuzzyPrefixLength = fuzzyPrefixLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the phrase slop.
|
||||
*/
|
||||
public TextQueryString phraseSlop(double phraseSlop) {
|
||||
this.phraseSlop = phraseSlop;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the boost.
|
||||
*/
|
||||
public TextQueryString boost(double boost) {
|
||||
this.boost = boost;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the analyze wildcard mode.
|
||||
*/
|
||||
public TextQueryString analyzeWildcard(boolean analyzeWildcard) {
|
||||
this.analyzeWildcard = analyzeWildcard;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Set the auto generate phrase queries mode.
|
||||
*/
|
||||
public TextQueryString autoGeneratePhraseQueries(boolean autoGeneratePhraseQueries) {
|
||||
this.autoGeneratePhraseQueries = autoGeneratePhraseQueries;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the max determinized states.
|
||||
*/
|
||||
public TextQueryString maxDeterminizedStates(int maxDeterminizedStates) {
|
||||
this.maxDeterminizedStates = maxDeterminizedStates;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time zone.
|
||||
*/
|
||||
public TextQueryString timeZone(String timeZone) {
|
||||
this.timeZone = timeZone;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rewrite option.
|
||||
*/
|
||||
public TextQueryString rewrite(String rewrite) {
|
||||
this.rewrite = rewrite;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rewrite option.
|
||||
*/
|
||||
public String getRewrite() {
|
||||
return rewrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fields.
|
||||
*/
|
||||
public String[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if AND is the default operator.
|
||||
*/
|
||||
public boolean isOperatorAnd() {
|
||||
return operatorAnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the analyzer.
|
||||
*/
|
||||
public String getAnalyzer() {
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the locale.
|
||||
*/
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return lenient mode.
|
||||
*/
|
||||
public boolean isLenient() {
|
||||
return lenient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum should match.
|
||||
*/
|
||||
public String getMinShouldMatch() {
|
||||
return minShouldMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the useDixMax mode.
|
||||
*/
|
||||
public boolean isUseDisMax() {
|
||||
return useDisMax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tie breaker.
|
||||
*/
|
||||
public double getTieBreaker() {
|
||||
return tieBreaker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default field.
|
||||
*/
|
||||
public String getDefaultField() {
|
||||
return defaultField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the allow leading wildcard mode.
|
||||
*/
|
||||
public boolean isAllowLeadingWildcard() {
|
||||
return allowLeadingWildcard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the lowercase expanded terms mode.
|
||||
*/
|
||||
public boolean isLowercaseExpandedTerms() {
|
||||
return lowercaseExpandedTerms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the enable position increments mode.
|
||||
*/
|
||||
public boolean isEnablePositionIncrements() {
|
||||
return enablePositionIncrements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fuzzy max expansions.
|
||||
*/
|
||||
public int getFuzzyMaxExpansions() {
|
||||
return fuzzyMaxExpansions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fuzziness.
|
||||
*/
|
||||
public String getFuzziness() {
|
||||
return fuzziness;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fuzzy prefix length.
|
||||
*/
|
||||
public int getFuzzyPrefixLength() {
|
||||
return fuzzyPrefixLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the phrase slop.
|
||||
*/
|
||||
public double getPhraseSlop() {
|
||||
return phraseSlop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the analyze wildcard mode.
|
||||
*/
|
||||
public boolean isAnalyzeWildcard() {
|
||||
return analyzeWildcard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the boost.
|
||||
*/
|
||||
public double getBoost() {
|
||||
return boost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the auto generate phase queries mode.
|
||||
*/
|
||||
public boolean isAutoGeneratePhraseQueries() {
|
||||
return autoGeneratePhraseQueries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the max determinized states.
|
||||
*/
|
||||
public int getMaxDeterminizedStates() {
|
||||
return maxDeterminizedStates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time zone.
|
||||
*/
|
||||
public String getTimeZone() {
|
||||
return timeZone;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
package com.avaje.ebean.search;
|
||||
|
||||
/**
|
||||
* Simple text query options.
|
||||
* <p>
|
||||
* This maps to an ElasticSearch "simple text query".
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* TextSimple options = new TextSimple()
|
||||
* .analyzeWildcard(true)
|
||||
* .fields("name")
|
||||
* .lenient(true)
|
||||
* .opAnd();
|
||||
*
|
||||
* List<Customer> customers = server.find(Customer.class)
|
||||
* .text()
|
||||
* .textSimple("quick brown", options)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public class TextSimple {
|
||||
|
||||
protected String[] fields;
|
||||
|
||||
protected boolean operatorAnd;
|
||||
|
||||
protected String analyzer;
|
||||
|
||||
protected String flags;
|
||||
|
||||
protected boolean lowercaseExpandedTerms = true;
|
||||
|
||||
protected boolean analyzeWildcard;
|
||||
|
||||
protected String locale;
|
||||
|
||||
protected boolean lenient;
|
||||
|
||||
protected String minShouldMatch;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*/
|
||||
public TextSimple() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the fields.
|
||||
*/
|
||||
public TextSimple fields(String... fields) {
|
||||
this.fields = fields;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use AND as the default operator.
|
||||
*/
|
||||
public TextSimple opAnd() {
|
||||
this.operatorAnd = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use OR as the default operator.
|
||||
*/
|
||||
public TextSimple opOr() {
|
||||
this.operatorAnd = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the analyzer
|
||||
*/
|
||||
public TextSimple analyzer(String analyzer) {
|
||||
this.analyzer = analyzer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flags.
|
||||
*/
|
||||
public TextSimple flags(String flags) {
|
||||
this.flags = flags;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the false to not use lowercase expanded terms.
|
||||
*/
|
||||
public TextSimple lowercaseExpandedTerms(boolean lowercaseExpandedTerms) {
|
||||
this.lowercaseExpandedTerms = lowercaseExpandedTerms;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to use analyze wildcard.
|
||||
*/
|
||||
public TextSimple analyzeWildcard(boolean analyzeWildcard) {
|
||||
this.analyzeWildcard = analyzeWildcard;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the locale.
|
||||
*/
|
||||
public TextSimple locale(String locale) {
|
||||
this.locale = locale;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the lenient mode.
|
||||
*/
|
||||
public TextSimple lenient(boolean lenient) {
|
||||
this.lenient = lenient;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum should match.
|
||||
*/
|
||||
public TextSimple minShouldMatch(String minShouldMatch) {
|
||||
this.minShouldMatch = minShouldMatch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return lenient mode.
|
||||
*/
|
||||
public boolean isLenient() {
|
||||
return lenient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true to analyse wildcard.
|
||||
*/
|
||||
public boolean isAnalyzeWildcard() {
|
||||
return analyzeWildcard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return lowercase expanded terms mode.
|
||||
*/
|
||||
public boolean isLowercaseExpandedTerms() {
|
||||
return lowercaseExpandedTerms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the default operator should be AND.
|
||||
*/
|
||||
public boolean isOperatorAnd() {
|
||||
return operatorAnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the analyzer to use.
|
||||
*/
|
||||
public String getAnalyzer() {
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fields.
|
||||
*/
|
||||
public String[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the locale.
|
||||
*/
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the flags.
|
||||
*/
|
||||
public String getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum should match.
|
||||
*/
|
||||
public String getMinShouldMatch() {
|
||||
return minShouldMatch;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@ public interface JsonBeanReader<T> {
|
||||
/**
|
||||
* Create a new reader taking the context from the existing one but using a new JsonParser.
|
||||
*/
|
||||
JsonBeanReader<T> forJson(JsonParser moreJson);
|
||||
JsonBeanReader<T> forJson(JsonParser moreJson, boolean resetContext);
|
||||
|
||||
/**
|
||||
* Add a bean explicitly to the persistence context.
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import com.avaje.ebean.FetchPath;
|
||||
import com.avaje.ebean.plugin.BeanType;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Type;
|
||||
@@ -66,6 +68,16 @@ public interface JsonContext {
|
||||
*/
|
||||
<T> JsonBeanReader<T> createBeanReader(Class<T> cls, JsonParser parser, JsonReadOptions options) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Create and return a new bean reading for the bean type given the JSON options and source.
|
||||
* <p>
|
||||
* Note that JsonOption provides an option for setting a persistence context and also enabling
|
||||
* further lazy loading. Further lazy loading requires a persistence context so if that is set
|
||||
* on then a persistence context is created if there is not one set.
|
||||
* </p>
|
||||
*/
|
||||
<T> JsonBeanReader<T> createBeanReader(BeanType<T> beanType, JsonParser parser, JsonReadOptions options) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json string input into a list of beans of a specific type.
|
||||
*
|
||||
@@ -213,13 +225,13 @@ public interface JsonContext {
|
||||
JsonParser createParser(Reader reader) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Return a helper that can write scalar types known to Ebean to Jackson.
|
||||
* Write a scalar types known to Ebean to Jackson.
|
||||
* <p>
|
||||
* Ebean has built in support for java8 and Joda types as well as the other
|
||||
* standard JDK types like URI, URL, UUID etc. This is a fast simple way to
|
||||
* write any of those types to Jackson.
|
||||
* </p>
|
||||
*/
|
||||
JsonScalar getScalar(JsonGenerator generator);
|
||||
void writeScalar(JsonGenerator generator, Object scalarValue) throws IOException;
|
||||
|
||||
}
|
||||
@@ -23,6 +23,8 @@ public class JsonReadOptions {
|
||||
|
||||
protected PersistenceContext persistenceContext;
|
||||
|
||||
protected Object loadContext;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
@@ -100,4 +102,19 @@ public class JsonReadOptions {
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return persistenceContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the load context to use.
|
||||
*/
|
||||
public Object getLoadContext() {
|
||||
return loadContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the load context to use.
|
||||
*/
|
||||
public void setLoadContext(Object loadContext) {
|
||||
this.loadContext = loadContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Writes any scalar type known to Ebean to the underlying Jackson generator.
|
||||
*/
|
||||
public interface JsonScalar {
|
||||
|
||||
/**
|
||||
* Write the scalar type to JSON where the value can be any type known to Ebean
|
||||
* including Enums, Java8 time types, Joda types, URL, URI etc.
|
||||
*/
|
||||
void write(String name, Object value) throws IOException;
|
||||
}
|
||||
@@ -135,6 +135,11 @@ public interface JsonWriter {
|
||||
*/
|
||||
void writeNumber(long value);
|
||||
|
||||
/**
|
||||
* Write a double value.
|
||||
*/
|
||||
void writeNumber(double value);
|
||||
|
||||
/**
|
||||
* Write a BigDecimal value (typically inside a list).
|
||||
*/
|
||||
|
||||
@@ -5,9 +5,6 @@ import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Controls the loading of reference objects for a query instance.
|
||||
@@ -19,38 +16,40 @@ public interface LoadContext {
|
||||
*/
|
||||
int getSecondaryQueriesMinBatchSize(int defaultQueryBatch);
|
||||
|
||||
/**
|
||||
* Execute any secondary (+query) queries if there are any defined.
|
||||
* @param parentRequest the originating query request
|
||||
*/
|
||||
void executeSecondaryQueries(OrmQueryRequest<?> parentRequest);
|
||||
/**
|
||||
* Execute any secondary (+query) queries if there are any defined.
|
||||
*
|
||||
* @param parentRequest the originating query request
|
||||
* @param forEach set true when using findEach iteration
|
||||
*/
|
||||
void executeSecondaryQueries(OrmQueryRequest<?> parentRequest, boolean forEach);
|
||||
|
||||
/**
|
||||
* Return the node for a given path which is used by AutoTune profiling.
|
||||
*/
|
||||
ObjectGraphNode getObjectGraphNode(String path);
|
||||
* Return the node for a given path which is used by AutoTune profiling.
|
||||
*/
|
||||
ObjectGraphNode getObjectGraphNode(String path);
|
||||
|
||||
/**
|
||||
* Return the persistence context used by this query and future lazy loading.
|
||||
*/
|
||||
PersistenceContext getPersistenceContext();
|
||||
/**
|
||||
* Return the persistence context used by this query and future lazy loading.
|
||||
*/
|
||||
PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Set the persistence context used by this query and future lazy loading.
|
||||
* <p>
|
||||
* Used by query iterator when processing large result sets.
|
||||
* </p>
|
||||
*/
|
||||
void resetPersistenceContext(PersistenceContext persistenceContext);
|
||||
/**
|
||||
* Set the persistence context used by this query and future lazy loading.
|
||||
* <p>
|
||||
* Used by query iterator when processing large result sets.
|
||||
* </p>
|
||||
*/
|
||||
void resetPersistenceContext(PersistenceContext persistenceContext);
|
||||
|
||||
/**
|
||||
* Register a Bean for lazy loading.
|
||||
*/
|
||||
void register(String path, EntityBeanIntercept ebi);
|
||||
/**
|
||||
* Register a Bean for lazy loading.
|
||||
*/
|
||||
void register(String path, EntityBeanIntercept ebi);
|
||||
|
||||
/**
|
||||
* Register a collection for lazy loading.
|
||||
*/
|
||||
void register(String path, BeanCollection<?> bc);
|
||||
/**
|
||||
* Register a collection for lazy loading.
|
||||
*/
|
||||
void register(String path, BeanCollection<?> bc);
|
||||
|
||||
}
|
||||
|
||||
@@ -14,5 +14,5 @@ public interface LoadSecondaryQuery {
|
||||
/**
|
||||
* Execute the secondary query with a given batch size.
|
||||
*/
|
||||
void loadSecondaryQuery(OrmQueryRequest<?> parentRequest);
|
||||
void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, boolean forEach);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.TransactionCallback;
|
||||
import com.avaje.ebean.annotation.DocStoreEvent;
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
import com.avaje.ebean.event.changelog.BeanChange;
|
||||
@@ -61,23 +61,23 @@ public class ScopedTransaction implements SpiTransaction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocStoreEvent getDocStoreUpdateMode() {
|
||||
return transaction.getDocStoreUpdateMode();
|
||||
public DocStoreMode getDocStoreMode() {
|
||||
return transaction.getDocStoreMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDocStoreUpdateMode(DocStoreEvent indexUpdateMode) {
|
||||
transaction.setDocStoreUpdateMode(indexUpdateMode);
|
||||
public void setDocStoreMode(DocStoreMode mode) {
|
||||
transaction.setDocStoreMode(mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDocStoreBulkBatchSize() {
|
||||
return transaction.getDocStoreBulkBatchSize();
|
||||
public int getDocStoreBatchSize() {
|
||||
return transaction.getDocStoreBatchSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDocStoreUpdateBatchSize(int batchSize) {
|
||||
transaction.setDocStoreUpdateBatchSize(batchSize);
|
||||
public void setDocStoreBatchSize(int batchSize) {
|
||||
transaction.setDocStoreBatchSize(batchSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.avaje.ebeaninternal.api;
|
||||
import com.avaje.ebean.Expression;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.expression.ElasticExpressionContext;
|
||||
import com.avaje.ebeaninternal.server.expression.DocQueryContext;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -16,7 +16,7 @@ public interface SpiExpression extends Expression {
|
||||
/**
|
||||
* Write the expression as an elastic search expression.
|
||||
*/
|
||||
void writeElastic(ElasticExpressionContext context) throws IOException;
|
||||
void writeDocQuery(DocQueryContext context) throws IOException;
|
||||
|
||||
/**
|
||||
* Process "Many" properties populating ManyWhereJoins.
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.ExpressionList;
|
||||
import com.avaje.ebeaninternal.server.expression.DocQueryContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -24,4 +26,8 @@ public interface SpiExpressionList<T> extends ExpressionList<T>, SpiExpression {
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Write the top level where expressions taking into account possible extra idEquals expression.
|
||||
*/
|
||||
void writeDocQuery(DocQueryContext context, SpiExpression idEquals) throws IOException;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.Junction;
|
||||
import com.avaje.ebeaninternal.server.expression.DocQueryContext;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* SPI methods for Junction.
|
||||
*/
|
||||
public interface SpiJunction<T> extends Junction<T> {
|
||||
|
||||
/**
|
||||
* Write the Junction taking into account it is implied.
|
||||
*/
|
||||
void writeDocQueryJunction(DocQueryContext context) throws IOException;
|
||||
}
|
||||
@@ -16,12 +16,10 @@ import com.avaje.ebeaninternal.server.autotune.ProfilingListener;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
import com.avaje.ebeaninternal.server.expression.ElasticExpressionContext;
|
||||
import com.avaje.ebeaninternal.server.query.CancelableQuery;
|
||||
import com.avaje.ebeaninternal.server.querydefn.NaturalKeyBindParam;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -130,11 +128,6 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the query as an elastic search query.
|
||||
*/
|
||||
void writeElastic(ElasticExpressionContext context) throws IOException;
|
||||
|
||||
/**
|
||||
* Return true if AutoTune should be attempted on this query.
|
||||
*/
|
||||
@@ -516,6 +509,11 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
SpiExpressionList<T> getHavingExpressions();
|
||||
|
||||
/**
|
||||
* Return the text expressions.
|
||||
*/
|
||||
SpiExpressionList<T> getTextExpression();
|
||||
|
||||
/**
|
||||
* Return additional having clause. Where raw String expressions are added
|
||||
* to having clause rather than Expression objects.
|
||||
|
||||
@@ -4,7 +4,7 @@ import java.sql.Connection;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.annotation.DocStoreEvent;
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.event.changelog.BeanChange;
|
||||
import com.avaje.ebean.event.changelog.ChangeSet;
|
||||
@@ -109,13 +109,13 @@ public interface SpiTransaction extends Transaction {
|
||||
* Returning 0 implies to use the system wide default batch size.
|
||||
* </p>
|
||||
*/
|
||||
DocStoreEvent getDocStoreUpdateMode();
|
||||
DocStoreMode getDocStoreMode();
|
||||
|
||||
/**
|
||||
* Return the batch size to us for ElasticSearch Bulk API calls
|
||||
* as a result of this transaction.
|
||||
*/
|
||||
int getDocStoreBulkBatchSize();
|
||||
int getDocStoreBatchSize();
|
||||
|
||||
/**
|
||||
* Return the batchSize specifically set for this transaction or 0.
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.avaje.ebean.event.changelog.BeanChange;
|
||||
import com.avaje.ebean.event.changelog.ChangeSet;
|
||||
import com.avaje.ebean.event.changelog.ChangeType;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import com.avaje.ebean.text.json.JsonScalar;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
@@ -97,10 +96,7 @@ public class ChangeJsonBuilder {
|
||||
if (bean.getType() != ChangeType.DELETE) {
|
||||
gen.writeFieldName("values");
|
||||
gen.writeStartObject();
|
||||
// use JsonScalar as it knows how to encode all the scalar
|
||||
// property types that Ebean supports (Java8, Joda etc)
|
||||
JsonScalar scalarWriter = json.getScalar(gen);
|
||||
writeValuePairs(bean, scalarWriter, gen);
|
||||
writeValuePairs(bean, gen);
|
||||
gen.writeEndObject();
|
||||
}
|
||||
}
|
||||
@@ -111,7 +107,7 @@ public class ChangeJsonBuilder {
|
||||
* We are intentionally keeping the same new/old structure for both inserts and updates.
|
||||
* </p>
|
||||
*/
|
||||
protected void writeValuePairs(BeanChange bean, JsonScalar scalarWriter, JsonGenerator gen) throws IOException {
|
||||
protected void writeValuePairs(BeanChange bean, JsonGenerator gen) throws IOException {
|
||||
|
||||
for (Map.Entry<String, ValuePair> entry : bean.getValues().entrySet()) {
|
||||
gen.writeFieldName(entry.getKey());
|
||||
@@ -119,11 +115,13 @@ public class ChangeJsonBuilder {
|
||||
ValuePair value = entry.getValue();
|
||||
Object newValue = value.getNewValue();
|
||||
if (newValue != null) {
|
||||
scalarWriter.write("new", newValue);
|
||||
gen.writeFieldName("new");
|
||||
json.writeScalar(gen, newValue);
|
||||
}
|
||||
Object oldValue = value.getOldValue();
|
||||
if (oldValue != null) {
|
||||
scalarWriter.write("old", oldValue);
|
||||
gen.writeFieldName("old");
|
||||
json.writeScalar(gen, oldValue);
|
||||
}
|
||||
gen.writeEndObject();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeUUIDBinary;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
@@ -8,8 +10,6 @@ import java.sql.Types;
|
||||
import java.util.Calendar;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeUUIDBinary;
|
||||
|
||||
/**
|
||||
* Default implementation of TypeConverter.
|
||||
* <p>
|
||||
@@ -18,451 +18,452 @@ import com.avaje.ebeaninternal.server.type.ScalarTypeUUIDBinary;
|
||||
*/
|
||||
public final class BasicTypeConverter implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 7691463236204070311L;
|
||||
|
||||
/**
|
||||
* Type code for java.util.Calendar.
|
||||
*/
|
||||
public static final int UTIL_CALENDAR = -999998986;
|
||||
private static final long serialVersionUID = 7691463236204070311L;
|
||||
|
||||
/**
|
||||
* Type code for java.util.Date.
|
||||
*/
|
||||
public static final int UTIL_DATE = -999998988;
|
||||
/**
|
||||
* Type code for java.util.Calendar.
|
||||
*/
|
||||
public static final int UTIL_CALENDAR = -999998986;
|
||||
|
||||
private BasicTypeConverter() {
|
||||
}
|
||||
/**
|
||||
* Type code for java.util.Date.
|
||||
*/
|
||||
public static final int UTIL_DATE = -999998988;
|
||||
|
||||
/**
|
||||
* Convert the Object to the required data type.
|
||||
*
|
||||
* @param value
|
||||
* the Object value
|
||||
* @param toDataType
|
||||
* the dataType as per java.sql.Types.
|
||||
*/
|
||||
public static Object convert(Object value, int toDataType) {
|
||||
private BasicTypeConverter() {
|
||||
}
|
||||
|
||||
try {
|
||||
switch (toDataType) {
|
||||
case UTIL_DATE: {
|
||||
return toUtilDate(value);
|
||||
}
|
||||
case UTIL_CALENDAR: {
|
||||
return toCalendar(value);
|
||||
}
|
||||
case Types.BIGINT: {
|
||||
return toLong(value);
|
||||
}
|
||||
case Types.INTEGER: {
|
||||
return toInteger(value);
|
||||
}
|
||||
case Types.BIT: {
|
||||
return toBoolean(value);
|
||||
}
|
||||
case Types.TINYINT: {
|
||||
return toByte(value);
|
||||
}
|
||||
case Types.SMALLINT: {
|
||||
return toShort(value);
|
||||
}
|
||||
case Types.NUMERIC: {
|
||||
return toBigDecimal(value);
|
||||
}
|
||||
case Types.DECIMAL: {
|
||||
return toBigDecimal(value);
|
||||
}
|
||||
case Types.REAL: {
|
||||
return toFloat(value);
|
||||
}
|
||||
case Types.DOUBLE: {
|
||||
return toDouble(value);
|
||||
}
|
||||
case Types.FLOAT: {
|
||||
return toDouble(value);
|
||||
}
|
||||
case Types.BOOLEAN: {
|
||||
return toBoolean(value);
|
||||
}
|
||||
case Types.TIMESTAMP: {
|
||||
return toTimestamp(value);
|
||||
}
|
||||
case Types.DATE: {
|
||||
return toDate(value);
|
||||
}
|
||||
case Types.VARCHAR: {
|
||||
return toString(value);
|
||||
}
|
||||
case Types.CHAR: {
|
||||
return toString(value);
|
||||
}
|
||||
case Types.OTHER: {
|
||||
return value;
|
||||
}
|
||||
case Types.JAVA_OBJECT: {
|
||||
return value;
|
||||
}
|
||||
case Types.BINARY:
|
||||
case Types.LONGVARBINARY:
|
||||
case Types.BLOB: {
|
||||
return value;
|
||||
}
|
||||
case Types.LONGVARCHAR:
|
||||
case Types.CLOB: {
|
||||
return value;
|
||||
}
|
||||
default: {
|
||||
String msg = "Unhandled data type [" + toDataType + "] converting [" + value + "]";
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
}
|
||||
} catch (ClassCastException e) {
|
||||
String m = "ClassCastException converting to data type [" + toDataType + "] value [" + value + "]";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Convert the Object to the required data type.
|
||||
*
|
||||
* @param value the Object value
|
||||
* @param toDataType the dataType as per java.sql.Types.
|
||||
*/
|
||||
public static Object convert(Object value, int toDataType) {
|
||||
|
||||
/**
|
||||
* Convert the value to a String.
|
||||
*/
|
||||
public static String toString(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return (String) value;
|
||||
}
|
||||
if (value instanceof char[]) {
|
||||
return String.valueOf((char[]) value);
|
||||
}
|
||||
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the value to a Boolean with an explicit String true value.
|
||||
*/
|
||||
public static Boolean toBoolean(Object value, String dbTrueValue) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
try {
|
||||
switch (toDataType) {
|
||||
case UTIL_DATE: {
|
||||
return toUtilDate(value);
|
||||
}
|
||||
if (value instanceof Boolean) {
|
||||
return (Boolean) value;
|
||||
case UTIL_CALENDAR: {
|
||||
return toCalendar(value);
|
||||
}
|
||||
String s = value.toString();
|
||||
return s.equalsIgnoreCase(dbTrueValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to a Boolean. Can be a Boolean or the string values
|
||||
* "true" or "false".
|
||||
*/
|
||||
public static Boolean toBoolean(Object value) {
|
||||
case Types.BIGINT: {
|
||||
return toLong(value);
|
||||
}
|
||||
case Types.INTEGER: {
|
||||
return toInteger(value);
|
||||
}
|
||||
case Types.BIT: {
|
||||
return toBoolean(value);
|
||||
}
|
||||
case Types.TINYINT: {
|
||||
return toByte(value);
|
||||
}
|
||||
case Types.SMALLINT: {
|
||||
return toShort(value);
|
||||
}
|
||||
case Types.NUMERIC: {
|
||||
return toBigDecimal(value);
|
||||
}
|
||||
case Types.DECIMAL: {
|
||||
return toBigDecimal(value);
|
||||
}
|
||||
case Types.REAL: {
|
||||
return toFloat(value);
|
||||
}
|
||||
case Types.DOUBLE: {
|
||||
return toDouble(value);
|
||||
}
|
||||
case Types.FLOAT: {
|
||||
return toDouble(value);
|
||||
}
|
||||
case Types.BOOLEAN: {
|
||||
return toBoolean(value);
|
||||
}
|
||||
case Types.TIMESTAMP: {
|
||||
return toTimestamp(value);
|
||||
}
|
||||
case Types.DATE: {
|
||||
return toDate(value);
|
||||
}
|
||||
case Types.VARCHAR: {
|
||||
return toString(value);
|
||||
}
|
||||
case Types.CHAR: {
|
||||
return toString(value);
|
||||
}
|
||||
case Types.OTHER: {
|
||||
return value;
|
||||
}
|
||||
case Types.JAVA_OBJECT: {
|
||||
return value;
|
||||
}
|
||||
case Types.BINARY:
|
||||
case Types.LONGVARBINARY:
|
||||
case Types.BLOB: {
|
||||
return value;
|
||||
}
|
||||
case Types.LONGVARCHAR:
|
||||
case Types.CLOB: {
|
||||
return value;
|
||||
}
|
||||
default: {
|
||||
String msg = "Unhandled data type [" + toDataType + "] converting [" + value + "]";
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
}
|
||||
} catch (ClassCastException e) {
|
||||
String m = "ClassCastException converting to data type [" + toDataType + "] value [" + value + "]";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Boolean) {
|
||||
return (Boolean) value;
|
||||
}
|
||||
/**
|
||||
* Convert the value to a String.
|
||||
*/
|
||||
public static String toString(Object value) {
|
||||
|
||||
return Boolean.valueOf(value.toString());
|
||||
}
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return (String) value;
|
||||
}
|
||||
if (value instanceof char[]) {
|
||||
return String.valueOf((char[]) value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to a UUID.
|
||||
*/
|
||||
public static UUID toUUID(Object value) {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return UUID.fromString((String) value);
|
||||
}
|
||||
if (value instanceof byte[]) {
|
||||
return ScalarTypeUUIDBinary.convertFromBytes((byte[])value);
|
||||
}
|
||||
return (UUID) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert the passed in object to a BigDecimal. It should be another
|
||||
* numeric type.
|
||||
*/
|
||||
public static BigDecimal toBigDecimal(Object value) {
|
||||
/**
|
||||
* Convert the value to a Boolean with an explicit String true value.
|
||||
*/
|
||||
public static Boolean toBoolean(Object value, String dbTrueValue) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof BigDecimal) {
|
||||
return (BigDecimal) value;
|
||||
}
|
||||
return new BigDecimal(value.toString());
|
||||
}
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Boolean) {
|
||||
return (Boolean) value;
|
||||
}
|
||||
String s = value.toString();
|
||||
return s.equalsIgnoreCase(dbTrueValue);
|
||||
}
|
||||
|
||||
public static Float toFloat(Object value) {
|
||||
/**
|
||||
* Convert the value to a Boolean. Can be a Boolean or the string values
|
||||
* "true" or "false".
|
||||
*/
|
||||
public static Boolean toBoolean(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Float) {
|
||||
return (Float) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).floatValue();
|
||||
}
|
||||
return Float.valueOf(value.toString());
|
||||
}
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Boolean) {
|
||||
return (Boolean) value;
|
||||
}
|
||||
|
||||
public static Short toShort(Object value) {
|
||||
return Boolean.valueOf(value.toString());
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Short) {
|
||||
return (Short) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).shortValue();
|
||||
}
|
||||
return Short.valueOf(value.toString());
|
||||
}
|
||||
/**
|
||||
* Convert the value to a UUID.
|
||||
*/
|
||||
public static UUID toUUID(Object value) {
|
||||
|
||||
public static Byte toByte(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof UUID) {
|
||||
return (UUID) value;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return UUID.fromString((String) value);
|
||||
}
|
||||
if (value instanceof byte[]) {
|
||||
return ScalarTypeUUIDBinary.convertFromBytes((byte[]) value);
|
||||
}
|
||||
return UUID.fromString(value.toString());
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Byte) {
|
||||
return (Byte) value;
|
||||
}
|
||||
return Byte.valueOf(value.toString());
|
||||
}
|
||||
/**
|
||||
* convert the passed in object to a BigDecimal. It should be another
|
||||
* numeric type.
|
||||
*/
|
||||
public static BigDecimal toBigDecimal(Object value) {
|
||||
|
||||
/**
|
||||
* convert the passed in object to a Integer. It should be another numeric
|
||||
* type.
|
||||
*/
|
||||
public static Integer toInteger(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof BigDecimal) {
|
||||
return (BigDecimal) value;
|
||||
}
|
||||
return new BigDecimal(value.toString());
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
return (Integer) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).intValue();
|
||||
}
|
||||
return Integer.valueOf(value.toString());
|
||||
}
|
||||
public static Float toFloat(Object value) {
|
||||
|
||||
/**
|
||||
* Convert the object to a Long. It should be another numeric type.
|
||||
*/
|
||||
public static Long toLong(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Float) {
|
||||
return (Float) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).floatValue();
|
||||
}
|
||||
return Float.valueOf(value.toString());
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Long) {
|
||||
return (Long) value;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return Long.valueOf((String) value);
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).longValue();
|
||||
}
|
||||
if (value instanceof java.util.Date) {
|
||||
return ((java.util.Date) value).getTime();
|
||||
}
|
||||
if (value instanceof Calendar) {
|
||||
return ((Calendar) value).getTime().getTime();
|
||||
}
|
||||
return Long.valueOf(value.toString());
|
||||
}
|
||||
public static Short toShort(Object value) {
|
||||
|
||||
public static BigInteger toMathBigInteger(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Short) {
|
||||
return (Short) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).shortValue();
|
||||
}
|
||||
return Short.valueOf(value.toString());
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof BigInteger) {
|
||||
return (BigInteger) value;
|
||||
}
|
||||
return new BigInteger(value.toString());
|
||||
}
|
||||
public static Byte toByte(Object value) {
|
||||
|
||||
/**
|
||||
* Convert the object to a Double. It should be another numberic type.
|
||||
*/
|
||||
public static Double toDouble(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Byte) {
|
||||
return (Byte) value;
|
||||
}
|
||||
return Byte.valueOf(value.toString());
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Double) {
|
||||
return (Double) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).doubleValue();
|
||||
}
|
||||
return Double.valueOf(value.toString());
|
||||
}
|
||||
/**
|
||||
* convert the passed in object to a Integer. It should be another numeric
|
||||
* type.
|
||||
*/
|
||||
public static Integer toInteger(Object value) {
|
||||
|
||||
/**
|
||||
* convert the passed in object to a Timestamp. It is expected to be a
|
||||
* java.sql.Date really.
|
||||
*/
|
||||
public static Timestamp toTimestamp(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
return (Integer) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).intValue();
|
||||
}
|
||||
return Integer.valueOf(value.toString());
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Timestamp) {
|
||||
return (Timestamp) value;
|
||||
/**
|
||||
* Convert the object to a Long. It should be another numeric type.
|
||||
*/
|
||||
public static Long toLong(Object value) {
|
||||
|
||||
} else if (value instanceof java.util.Date) {
|
||||
// no nanos here... so hopefully ok
|
||||
return new Timestamp(((java.util.Date) value).getTime());
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Long) {
|
||||
return (Long) value;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return Long.valueOf((String) value);
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).longValue();
|
||||
}
|
||||
if (value instanceof java.util.Date) {
|
||||
return ((java.util.Date) value).getTime();
|
||||
}
|
||||
if (value instanceof Calendar) {
|
||||
return ((Calendar) value).getTime().getTime();
|
||||
}
|
||||
return Long.valueOf(value.toString());
|
||||
}
|
||||
|
||||
} else if (value instanceof Calendar) {
|
||||
return new Timestamp(((Calendar) value).getTime().getTime());
|
||||
public static BigInteger toMathBigInteger(Object value) {
|
||||
|
||||
} else if (value instanceof String) {
|
||||
return Timestamp.valueOf((String) value);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof BigInteger) {
|
||||
return (BigInteger) value;
|
||||
}
|
||||
return new BigInteger(value.toString());
|
||||
}
|
||||
|
||||
} else if (value instanceof Number) {
|
||||
return new Timestamp(((Number) value).longValue());
|
||||
/**
|
||||
* Convert the object to a Double. It should be another numberic type.
|
||||
*/
|
||||
public static Double toDouble(Object value) {
|
||||
|
||||
} else {
|
||||
String msg = "Unable to convert [" + value.getClass().getName() + "] into a Timestamp.";
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
}
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Double) {
|
||||
return (Double) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).doubleValue();
|
||||
}
|
||||
return Double.valueOf(value.toString());
|
||||
}
|
||||
|
||||
public static java.sql.Time toTime(Object value) {
|
||||
/**
|
||||
* convert the passed in object to a Timestamp. It is expected to be a
|
||||
* java.sql.Date really.
|
||||
*/
|
||||
public static Timestamp toTimestamp(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof java.sql.Time) {
|
||||
return (java.sql.Time) value;
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Timestamp) {
|
||||
return (Timestamp) value;
|
||||
|
||||
} else if (value instanceof String) {
|
||||
return java.sql.Time.valueOf((String) value);
|
||||
} else if (value instanceof java.util.Date) {
|
||||
// no nanos here... so hopefully ok
|
||||
return new Timestamp(((java.util.Date) value).getTime());
|
||||
|
||||
} else {
|
||||
String m = "Unable to convert [" + value.getClass().getName() + "] into a java.sql.Date.";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
} else if (value instanceof Calendar) {
|
||||
return new Timestamp(((Calendar) value).getTime().getTime());
|
||||
|
||||
/**
|
||||
* convert the passed in object to a java sql Date.
|
||||
*/
|
||||
public static java.sql.Date toDate(Object value) {
|
||||
} else if (value instanceof String) {
|
||||
return Timestamp.valueOf((String) value);
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof java.sql.Date) {
|
||||
return (java.sql.Date) value;
|
||||
} else if (value instanceof Number) {
|
||||
return new Timestamp(((Number) value).longValue());
|
||||
|
||||
} else if (value instanceof java.util.Date) {
|
||||
return new java.sql.Date(((java.util.Date) value).getTime());
|
||||
} else {
|
||||
String msg = "Unable to convert [" + value.getClass().getName() + "] into a Timestamp.";
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (value instanceof Calendar) {
|
||||
return new java.sql.Date(((Calendar) value).getTime().getTime());
|
||||
public static java.sql.Time toTime(Object value) {
|
||||
|
||||
} else if (value instanceof String) {
|
||||
return java.sql.Date.valueOf((String) value);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof java.sql.Time) {
|
||||
return (java.sql.Time) value;
|
||||
|
||||
} else if (value instanceof Number) {
|
||||
return new java.sql.Date(((Number) value).longValue());
|
||||
} else if (value instanceof String) {
|
||||
return java.sql.Time.valueOf((String) value);
|
||||
|
||||
} else {
|
||||
String m = "Unable to convert [" + value.getClass().getName() + "] into a java.sql.Date.";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String m = "Unable to convert [" + value.getClass().getName() + "] into a java.sql.Date.";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* convert the passed in object to a java sql Date.
|
||||
*/
|
||||
public static java.util.Date toUtilDate(Object value) {
|
||||
/**
|
||||
* convert the passed in object to a java sql Date.
|
||||
*/
|
||||
public static java.sql.Date toDate(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof java.sql.Timestamp) {
|
||||
// loss of nanos precision
|
||||
return new java.util.Date(((java.sql.Timestamp) value).getTime());
|
||||
}
|
||||
// DEVNOTE: strictly speaking do I need to convert a java.sql.Date to
|
||||
// java.util.Date? equals() is symmetrical so perhaps this is not
|
||||
// really required?
|
||||
if (value instanceof java.sql.Date) {
|
||||
return new java.util.Date(((java.sql.Date) value).getTime());
|
||||
}
|
||||
if (value instanceof java.util.Date) {
|
||||
return (java.util.Date) value;
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof java.sql.Date) {
|
||||
return (java.sql.Date) value;
|
||||
|
||||
} else if (value instanceof Calendar) {
|
||||
return ((Calendar) value).getTime();
|
||||
} else if (value instanceof java.util.Date) {
|
||||
return new java.sql.Date(((java.util.Date) value).getTime());
|
||||
|
||||
} else if (value instanceof String) {
|
||||
return new java.util.Date(Timestamp.valueOf((String) value).getTime());
|
||||
} else if (value instanceof Calendar) {
|
||||
return new java.sql.Date(((Calendar) value).getTime().getTime());
|
||||
|
||||
} else if (value instanceof Number) {
|
||||
return new java.util.Date(((Number) value).longValue());
|
||||
} else if (value instanceof String) {
|
||||
return java.sql.Date.valueOf((String) value);
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Unable to convert [" + value.getClass().getName() + "] into a java.util.Date");
|
||||
}
|
||||
}
|
||||
} else if (value instanceof Number) {
|
||||
return new java.sql.Date(((Number) value).longValue());
|
||||
|
||||
/**
|
||||
* convert the passed in object to a java sql Date.
|
||||
*/
|
||||
public static Calendar toCalendar(Object value) {
|
||||
} else {
|
||||
String m = "Unable to convert [" + value.getClass().getName() + "] into a java.sql.Date.";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Calendar) {
|
||||
return (Calendar) value;
|
||||
/**
|
||||
* convert the passed in object to a java sql Date.
|
||||
*/
|
||||
public static java.util.Date toUtilDate(Object value) {
|
||||
|
||||
} else if (value instanceof java.util.Date) {
|
||||
java.util.Date date = ((java.util.Date) value);
|
||||
return toCalendarFromDate(date);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof java.sql.Timestamp) {
|
||||
// loss of nanos precision
|
||||
return new java.util.Date(((java.sql.Timestamp) value).getTime());
|
||||
}
|
||||
// DEVNOTE: strictly speaking do I need to convert a java.sql.Date to
|
||||
// java.util.Date? equals() is symmetrical so perhaps this is not
|
||||
// really required?
|
||||
if (value instanceof java.sql.Date) {
|
||||
return new java.util.Date(((java.sql.Date) value).getTime());
|
||||
}
|
||||
if (value instanceof java.util.Date) {
|
||||
return (java.util.Date) value;
|
||||
|
||||
} else if (value instanceof String) {
|
||||
java.util.Date date = toUtilDate(value);
|
||||
return toCalendarFromDate(date);
|
||||
} else if (value instanceof Calendar) {
|
||||
return ((Calendar) value).getTime();
|
||||
|
||||
} else if (value instanceof Number) {
|
||||
long timeMillis = ((Number) value).longValue();
|
||||
java.util.Date date = new java.util.Date(timeMillis);
|
||||
return toCalendarFromDate(date);
|
||||
} else if (value instanceof String) {
|
||||
return new java.util.Date(Timestamp.valueOf((String) value).getTime());
|
||||
|
||||
} else {
|
||||
String m = "Unable to convert [" + value.getClass().getName() + "] into a java.util.Date";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
} else if (value instanceof Number) {
|
||||
return new java.util.Date(((Number) value).longValue());
|
||||
|
||||
private static Calendar toCalendarFromDate(java.util.Date date) {
|
||||
} else {
|
||||
throw new RuntimeException("Unable to convert [" + value.getClass().getName() + "] into a java.util.Date");
|
||||
}
|
||||
}
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(date);
|
||||
/**
|
||||
* convert the passed in object to a java sql Date.
|
||||
*/
|
||||
public static Calendar toCalendar(Object value) {
|
||||
|
||||
return cal;
|
||||
}
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Calendar) {
|
||||
return (Calendar) value;
|
||||
|
||||
} else if (value instanceof java.util.Date) {
|
||||
java.util.Date date = ((java.util.Date) value);
|
||||
return toCalendarFromDate(date);
|
||||
|
||||
} else if (value instanceof String) {
|
||||
java.util.Date date = toUtilDate(value);
|
||||
return toCalendarFromDate(date);
|
||||
|
||||
} else if (value instanceof Number) {
|
||||
long timeMillis = ((Number) value).longValue();
|
||||
java.util.Date date = new java.util.Date(timeMillis);
|
||||
return toCalendarFromDate(date);
|
||||
|
||||
} else {
|
||||
String m = "Unable to convert [" + value.getClass().getName() + "] into a java.util.Date";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
|
||||
private static Calendar toCalendarFromDate(java.util.Date date) {
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(date);
|
||||
|
||||
return cal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ public class DefaultBeanLoader {
|
||||
|
||||
if (pc == null) {
|
||||
pc = new DefaultPersistenceContext();
|
||||
pc.put(parentId, parentBean);
|
||||
parentDesc.contextPut(pc, parentId, parentBean);
|
||||
}
|
||||
|
||||
boolean useManyIdCache = beanCollection != null && parentDesc.isManyPropCaching();
|
||||
@@ -263,7 +263,7 @@ public class DefaultBeanLoader {
|
||||
if (pc == null) {
|
||||
// a reference with no existing persistenceContext
|
||||
pc = new DefaultPersistenceContext();
|
||||
pc.put(id, bean);
|
||||
desc.contextPut(pc, id, bean);
|
||||
ebi.setPersistenceContext(pc);
|
||||
}
|
||||
|
||||
|
||||
@@ -580,48 +580,31 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
|
||||
BeanDescriptor desc = getBeanDescriptor(type);
|
||||
// convert the id type if necessary
|
||||
id = desc.convertId(id);
|
||||
|
||||
Object ref = null;
|
||||
PersistenceContext ctx = null;
|
||||
|
||||
PersistenceContext pc = null;
|
||||
SpiTransaction t = transactionScopeManager.get();
|
||||
if (t != null) {
|
||||
// first try the persistence context
|
||||
ctx = t.getPersistenceContext();
|
||||
ref = ctx.get(type, id);
|
||||
}
|
||||
|
||||
if (ref == null) {
|
||||
InheritInfo inheritInfo = desc.getInheritInfo();
|
||||
if (inheritInfo != null) {
|
||||
// we actually need to do a query because
|
||||
// we don't know the type without the
|
||||
// discriminator value
|
||||
BeanProperty idProp = desc.getIdProperty();
|
||||
if (idProp == null) {
|
||||
throw new PersistenceException("No ID properties for this type? " + desc);
|
||||
}
|
||||
|
||||
// just select the id properties and
|
||||
// the discriminator column (auto added)
|
||||
Query<T> query = createQuery(type);
|
||||
query.select(idProp.getName()).setId(id);
|
||||
|
||||
ref = query.findUnique();
|
||||
|
||||
} else {
|
||||
// use the default reference options
|
||||
ref = desc.createReference(null, id);
|
||||
}
|
||||
|
||||
if (ctx != null && (ref instanceof EntityBean)) {
|
||||
// Not putting a vanilla reference in the persistence context
|
||||
ctx.put(id, ref);
|
||||
pc = t.getPersistenceContext();
|
||||
Object existing = desc.contextGet(pc, id);
|
||||
if (existing != null) {
|
||||
return (T)existing;
|
||||
}
|
||||
}
|
||||
return (T) ref;
|
||||
|
||||
InheritInfo inheritInfo = desc.getInheritInfo();
|
||||
if (inheritInfo == null) {
|
||||
return (T)desc.contextRef(pc, null, id);
|
||||
}
|
||||
|
||||
BeanProperty idProp = desc.getIdProperty();
|
||||
if (idProp == null) {
|
||||
throw new PersistenceException("No ID properties for this type? " + desc);
|
||||
}
|
||||
|
||||
// we actually need to do a query because we don't know the type without the discriminator
|
||||
// value, just select the id property and discriminator column (auto added)
|
||||
return find(type).select(idProp.getName()).setId(id).findUnique();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1082,31 +1065,32 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
if (t == null) {
|
||||
t = getCurrentServerTransaction();
|
||||
}
|
||||
PersistenceContext context = null;
|
||||
|
||||
BeanDescriptor<T> desc = query.getBeanDescriptor();
|
||||
|
||||
PersistenceContext pc = null;
|
||||
if (t != null && useTransactionPersistenceContext(query)) {
|
||||
// first look in the transaction scoped persistence context
|
||||
context = t.getPersistenceContext();
|
||||
if (context != null) {
|
||||
WithOption o = context.getWithOption(query.getBeanType(), query.getId());
|
||||
pc = t.getPersistenceContext();
|
||||
if (pc != null) {
|
||||
WithOption o = desc.contextGetWithOption(pc, query.getId());
|
||||
if (o != null) {
|
||||
if (o.isDeleted()) {
|
||||
// Bean was previously deleted in the same transaction / persistence context
|
||||
return null;
|
||||
}
|
||||
// Return the entity bean instance from the persistence context
|
||||
return (T) o.getBean();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BeanDescriptor<T> desc = query.getBeanDescriptor();
|
||||
if (!desc.calculateUseCache(query.isUseBeanCache())) {
|
||||
// not using bean cache
|
||||
return null;
|
||||
}
|
||||
|
||||
// Hit the L2 bean cache
|
||||
return desc.cacheBeanGet(query, context);
|
||||
return desc.cacheBeanGet(query, pc);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1129,7 +1113,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
SpiQuery<T> spiQuery = (SpiQuery<T>) query;
|
||||
spiQuery.setType(Type.BEAN);
|
||||
|
||||
if (SpiQuery.Mode.NORMAL.equals(spiQuery.getMode()) && !spiQuery.isLoadBeanCache()) {
|
||||
// See if we can skip doing the fetch completely by getting the bean from the
|
||||
// persistence context or the bean cache
|
||||
@@ -1140,6 +1123,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(spiQuery, t);
|
||||
if (request.isUseDocStore()) {
|
||||
return docStore().find(request);
|
||||
}
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return (T) request.findId();
|
||||
@@ -1158,9 +1144,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return findId(query, t);
|
||||
}
|
||||
|
||||
BeanDescriptor<T> desc = beanDescriptorManager.getBeanDescriptor(query.getBeanType());
|
||||
SpiQuery<T> spiQuery = (SpiQuery<T>) query;
|
||||
BeanDescriptor<T> desc = spiQuery.getBeanDescriptor();
|
||||
|
||||
T bean = desc.cacheNaturalKeyLookup((SpiQuery<T>) query, (SpiTransaction) t);
|
||||
T bean = desc.cacheNaturalKeyLookup(spiQuery, (SpiTransaction) t);
|
||||
if (bean != null) {
|
||||
return bean;
|
||||
}
|
||||
@@ -1342,7 +1329,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
|
||||
if (spiQuery.isUseDocStore()) {
|
||||
return docStore().findPagedList(query);
|
||||
return docStore().findPagedList(createQueryRequest(Type.LIST, query, transaction));
|
||||
}
|
||||
|
||||
return new LimitOffsetPagedList<T>(this, spiQuery);
|
||||
@@ -1352,6 +1339,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
|
||||
|
||||
if (request.isUseDocStore()) {
|
||||
docStore().findEach(request, consumer);
|
||||
return;
|
||||
}
|
||||
|
||||
request.initTransIfRequired();
|
||||
request.findEach(consumer);
|
||||
// no try finally - findVisit guarantee's cleanup of the transaction if required
|
||||
@@ -1360,6 +1352,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
public <T> void findEachWhile(Query<T> query, QueryEachWhileConsumer<T> consumer, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
|
||||
if (request.isUseDocStore()) {
|
||||
docStore().findEachWhile(request, consumer);
|
||||
return;
|
||||
}
|
||||
|
||||
request.initTransIfRequired();
|
||||
request.findEachWhile(consumer);
|
||||
@@ -1397,13 +1393,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
public <T> List<T> findList(Query<T> query, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
|
||||
|
||||
Object result = request.getFromQueryCache();
|
||||
if (result != null) {
|
||||
return (List<T>) result;
|
||||
}
|
||||
if (request.isUseDocStore()) {
|
||||
return docStore().findList(query);
|
||||
return docStore().findList(request);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.event.BeanFindController;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebean.text.json.JsonReadOptions;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
import com.avaje.ebeaninternal.api.CQueryPlanKey;
|
||||
import com.avaje.ebeaninternal.api.HashQuery;
|
||||
@@ -59,6 +60,8 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
|
||||
private PersistenceContext persistenceContext;
|
||||
|
||||
private JsonReadOptions jsonRead;
|
||||
|
||||
private HashQuery cacheKey;
|
||||
|
||||
private CQueryPlanKey queryPlanKey;
|
||||
@@ -94,8 +97,11 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
return ebeanServer.getDatabasePlatform().getLikeClause();
|
||||
}
|
||||
|
||||
public void executeSecondaryQueries() {
|
||||
loadContext.executeSecondaryQueries(this);
|
||||
public void executeSecondaryQueries(boolean forEach) {
|
||||
// disable lazy loading leaves loadContext null
|
||||
if (loadContext != null) {
|
||||
loadContext.executeSecondaryQueries(this, forEach);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,7 +158,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
public void prepareQuery() {
|
||||
|
||||
adapterPreQuery();
|
||||
|
||||
this.secondaryQueries = query.convertJoins();
|
||||
this.queryPlanKey = query.prepare(this);
|
||||
}
|
||||
@@ -189,7 +194,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
*/
|
||||
public void persistenceContextAdd(EntityBean bean) {
|
||||
Object id = beanDescriptor.getId(bean);
|
||||
persistenceContext.put(id, bean);
|
||||
beanDescriptor.contextPut(persistenceContext, id, bean);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,9 +218,27 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
createdTransaction = true;
|
||||
}
|
||||
}
|
||||
// initialise the persistenceContext and loadContext
|
||||
this.persistenceContext = getPersistenceContext(query, transaction);
|
||||
this.loadContext = new DLoadContext(this, secondaryQueries);
|
||||
persistenceContext = getPersistenceContext(query, transaction);
|
||||
loadContext = new DLoadContext(this, secondaryQueries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JsonReadOptions taking into account lazy loading and persistence context.
|
||||
*/
|
||||
public JsonReadOptions createJsonReadOptions() {
|
||||
|
||||
persistenceContext = getPersistenceContext(query, transaction);
|
||||
if (query.getPersistenceContext() == null) {
|
||||
query.setPersistenceContext(persistenceContext);
|
||||
}
|
||||
jsonRead = new JsonReadOptions();
|
||||
jsonRead.setPersistenceContext(persistenceContext);
|
||||
if (!query.isDisableLazyLoading()) {
|
||||
loadContext = new DLoadContext(this, secondaryQueries);
|
||||
jsonRead.setLoadContext(loadContext);
|
||||
}
|
||||
|
||||
return jsonRead;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,6 +247,10 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
public void flushPersistenceContextOnIterate() {
|
||||
persistenceContext = new DefaultPersistenceContext();
|
||||
loadContext.resetPersistenceContext(persistenceContext);
|
||||
if (jsonRead != null) {
|
||||
jsonRead.setPersistenceContext(persistenceContext);
|
||||
jsonRead.setLoadContext(loadContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,7 +266,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
|
||||
// determine the scope (from the query and then server)
|
||||
PersistenceContextScope scope = ebeanServer.getPersistenceContextScope(query);
|
||||
return (scope == PersistenceContextScope.QUERY) ? new DefaultPersistenceContext() : t.getPersistenceContext();
|
||||
return (scope == PersistenceContextScope.QUERY || t == null) ? new DefaultPersistenceContext() : t.getPersistenceContext();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebean.annotation.ConcurrencyMode;
|
||||
import com.avaje.ebean.annotation.DocStoreEvent;
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
@@ -69,7 +69,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
|
||||
private final boolean publish;
|
||||
|
||||
private DocStoreEvent docStoreEvent;
|
||||
private DocStoreMode docStoreMode;
|
||||
|
||||
private ConcurrencyMode concurrencyMode;
|
||||
|
||||
@@ -147,7 +147,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
this.parentBean = parentBean;
|
||||
this.controller = beanDescriptor.getPersistController();
|
||||
this.type = type;
|
||||
this.docStoreEvent = calcDocStoreEvent(transaction, type);
|
||||
this.docStoreMode = calcDocStoreMode(transaction, type);
|
||||
if (saveRecurse) {
|
||||
this.persistCascade = t.isPersistCascade();
|
||||
}
|
||||
@@ -175,9 +175,9 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
* Used to check if the Transaction has set the mode to IGNORE when doing large batch inserts that we
|
||||
* don't want to send to the doc store.
|
||||
*/
|
||||
private DocStoreEvent calcDocStoreEvent(SpiTransaction txn, Type type) {
|
||||
DocStoreEvent docStoreEvent = (txn == null) ? null : txn.getDocStoreUpdateMode();
|
||||
return beanDescriptor.getDocStoreEvent(type, docStoreEvent);
|
||||
private DocStoreMode calcDocStoreMode(SpiTransaction txn, Type type) {
|
||||
DocStoreMode txnMode = (txn == null) ? null : txn.getDocStoreMode();
|
||||
return beanDescriptor.getDocStoreMode(type, txnMode);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,7 +203,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
public void initTransIfRequiredWithBatchCascade() {
|
||||
|
||||
if (createImplicitTransIfRequired()) {
|
||||
docStoreEvent = calcDocStoreEvent(transaction, type);
|
||||
docStoreMode = calcDocStoreMode(transaction, type);
|
||||
}
|
||||
if (transaction.checkBatchEscalationOnCascade(this)) {
|
||||
// we escalated to use batch mode so flush when done
|
||||
@@ -308,8 +308,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
* by queuing an event or direct updateAdd (via Bulk API).
|
||||
*/
|
||||
private boolean isDocStoreNotify() {
|
||||
// Either queue or directly update the document store
|
||||
return docStoreEvent != DocStoreEvent.IGNORE;
|
||||
return docStoreMode != DocStoreMode.IGNORE;
|
||||
}
|
||||
|
||||
public boolean isNotifyPersistListener() {
|
||||
@@ -563,6 +562,13 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this was a hard/permanent delete request (and should cascade as such).
|
||||
*/
|
||||
public boolean isHardDeleteCascade() {
|
||||
return (type == Type.DELETE && beanDescriptor.isSoftDelete());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for @Draftable entity beans with @Draft property that the bean is a 'draft'.
|
||||
* Save or Update is not allowed to execute using 'live' beans - must use publish().
|
||||
@@ -699,7 +705,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
*/
|
||||
private void postUpdate() {
|
||||
if (statelessUpdate) {
|
||||
transaction.getPersistenceContext().clear(beanDescriptor.getBeanType(), idValue);
|
||||
beanDescriptor.contextClear(transaction.getPersistenceContext(), idValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -707,9 +713,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
* Aggressive L1 and L2 cache cleanup for deletes.
|
||||
*/
|
||||
private void postDelete() {
|
||||
// Delete the bean from the PersistenceContent
|
||||
transaction.getPersistenceContext().clear(beanDescriptor.getBeanType(), idValue);
|
||||
// Delete from cache early even if transaction fails
|
||||
beanDescriptor.contextClear(transaction.getPersistenceContext(), idValue);
|
||||
beanDescriptor.cacheHandleDelete(idValue, this);
|
||||
}
|
||||
|
||||
@@ -731,7 +735,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
controllerPost();
|
||||
}
|
||||
|
||||
if (type == Type.UPDATE && docStoreEvent == DocStoreEvent.UPDATE) {
|
||||
if (type == Type.UPDATE && docStoreMode == DocStoreMode.UPDATE) {
|
||||
// get the dirty properties for update notification to the doc store
|
||||
dirtyProperties = intercept.getDirtyProperties();
|
||||
}
|
||||
@@ -913,7 +917,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
if (type == Type.UPDATE) {
|
||||
beanDescriptor.docStoreUpdateEmbedded(this, docStoreUpdates);
|
||||
}
|
||||
switch (docStoreEvent) {
|
||||
switch (docStoreMode) {
|
||||
case UPDATE: {
|
||||
docStoreUpdates.addPersist(this);
|
||||
return;
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeanservice.docstore.api.DocQueryRequest;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -15,7 +16,7 @@ import java.util.Set;
|
||||
/**
|
||||
* Defines the ORM query request api.
|
||||
*/
|
||||
public interface SpiOrmQueryRequest<T> {
|
||||
public interface SpiOrmQueryRequest<T> extends DocQueryRequest<T> {
|
||||
|
||||
/**
|
||||
* Return the query.
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Local interface to handle Embedded, Reference and Reference Exported
|
||||
* cases.
|
||||
*/
|
||||
abstract class AssocOneHelp {
|
||||
|
||||
protected final BeanPropertyAssocOne property;
|
||||
|
||||
protected final BeanDescriptor target;
|
||||
|
||||
AssocOneHelp(BeanPropertyAssocOne property) {
|
||||
this.property = property;
|
||||
this.target = property.targetDescriptor;
|
||||
}
|
||||
/**
|
||||
* Effectively skip reading (the jdbc resultSet as already in the persistence context etc).
|
||||
*/
|
||||
void loadIgnore(DbReadContext ctx) {
|
||||
property.targetIdBinder.loadIgnore(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and return the bean.
|
||||
*/
|
||||
Object read(DbReadContext ctx) throws SQLException {
|
||||
|
||||
// Support for Inheritance hierarchy on exported OneToOne ?
|
||||
Object id = property.targetIdBinder.read(ctx);
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PersistenceContext pc = ctx.getPersistenceContext();
|
||||
Object existing = target.contextGet(pc, id);
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
Object ref = target.contextRef(pc, ctx.isReadOnly(), id);
|
||||
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
|
||||
ctx.register(property.name, ebi);
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read setting values into the bean.
|
||||
*/
|
||||
Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
|
||||
Object val = read(ctx);
|
||||
if (bean != null) {
|
||||
property.setValue(bean, val);
|
||||
ctx.propagateState(val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append to the select clause.
|
||||
*/
|
||||
abstract void appendSelect(DbSqlContext ctx, boolean subQuery);
|
||||
|
||||
/**
|
||||
* Append to the from clause.
|
||||
*/
|
||||
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
// nothing required here
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Helper for Embedded BeanPropertyAssocOne.
|
||||
*/
|
||||
final class AssocOneHelpEmbedded extends AssocOneHelp {
|
||||
|
||||
public AssocOneHelpEmbedded(BeanPropertyAssocOne property) {
|
||||
super(property);
|
||||
}
|
||||
|
||||
void loadIgnore(DbReadContext ctx) {
|
||||
for (int i = 0; i < property.embeddedProps.length; i++) {
|
||||
property.embeddedProps[i].loadIgnore(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
|
||||
Object dbVal = read(ctx);
|
||||
if (bean != null) {
|
||||
// set back to the parent bean
|
||||
property.setValue(bean, dbVal);
|
||||
ctx.propagateState(dbVal);
|
||||
return dbVal;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object read(DbReadContext ctx) throws SQLException {
|
||||
|
||||
EntityBean embeddedBean = property.targetDescriptor.createEntityBean();
|
||||
|
||||
boolean notNull = false;
|
||||
for (int i = 0; i < property.embeddedProps.length; i++) {
|
||||
Object value = property.embeddedProps[i].readSet(ctx, embeddedBean);
|
||||
if (value != null) {
|
||||
notNull = true;
|
||||
}
|
||||
}
|
||||
if (notNull) {
|
||||
ctx.propagateState(embeddedBean);
|
||||
return embeddedBean;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
for (int i = 0; i < property.embeddedProps.length; i++) {
|
||||
property.embeddedProps[i].appendSelect(ctx, subQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Helper for BeanPropertyAssocOne for OneToOne exported reference - not so common.
|
||||
*/
|
||||
class AssocOneHelpRefExported extends AssocOneHelp {
|
||||
|
||||
public AssocOneHelpRefExported(BeanPropertyAssocOne property) {
|
||||
super(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append columns for foreign key columns.
|
||||
*/
|
||||
@Override
|
||||
void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
|
||||
// set appropriate tableAlias for the exported id columns
|
||||
String relativePrefix = ctx.getRelativePrefix(property.getName());
|
||||
ctx.pushTableAlias(relativePrefix);
|
||||
property.targetIdBinder.appendSelect(ctx, subQuery);
|
||||
ctx.popTableAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
|
||||
String relativePrefix = ctx.getRelativePrefix(property.getName());
|
||||
property.tableJoin.addJoin(joinType, relativePrefix, ctx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Helper for BeanPropertyAssocOne imported reference but with inheritance.
|
||||
*/
|
||||
class AssocOneHelpRefInherit extends AssocOneHelp {
|
||||
|
||||
private final InheritInfo inherit;
|
||||
|
||||
AssocOneHelpRefInherit(BeanPropertyAssocOne property) {
|
||||
super(property);
|
||||
this.inherit = property.targetInheritInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
void loadIgnore(DbReadContext ctx) {
|
||||
property.targetIdBinder.loadIgnore(ctx);
|
||||
ctx.getDataReader().incrementPos(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and set a Reference bean.
|
||||
*/
|
||||
@Override
|
||||
Object read(DbReadContext ctx) throws SQLException {
|
||||
|
||||
// read discriminator to determine the type
|
||||
InheritInfo rowInheritInfo = inherit.readType(ctx);
|
||||
if (rowInheritInfo == null) {
|
||||
// ignore the id property
|
||||
property.targetIdBinder.loadIgnore(ctx);
|
||||
return null;
|
||||
}
|
||||
|
||||
Object id = property.targetIdBinder.read(ctx);
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// check transaction context to see if it already exists
|
||||
PersistenceContext pc = ctx.getPersistenceContext();
|
||||
BeanDescriptor<?> desc = rowInheritInfo.getBeanDescriptor();
|
||||
Object existing = desc.contextGet(pc, id);
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
// for inheritance hierarchy create the correct type for this row...
|
||||
Object ref = desc.contextRef(pc, ctx.isReadOnly(), id);
|
||||
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
|
||||
ctx.register(property.name, ebi);
|
||||
return ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
|
||||
// add join to support the discriminator column
|
||||
String relativePrefix = ctx.getRelativePrefix(property.name);
|
||||
property.tableJoin.addJoin(joinType, relativePrefix, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append columns for foreign key columns.
|
||||
*/
|
||||
@Override
|
||||
void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
|
||||
if (!subQuery) {
|
||||
// add discriminator column
|
||||
String relativePrefix = ctx.getRelativePrefix(property.getName());
|
||||
String tableAlias = ctx.getTableAlias(relativePrefix);
|
||||
ctx.appendColumn(tableAlias, property.targetInheritInfo.getDiscriminatorColumn());
|
||||
}
|
||||
property.importedId.sqlAppend(ctx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
/**
|
||||
* Helper for BeanPropertyAssocOne imported reference - this is the common case.
|
||||
*/
|
||||
class AssocOneHelpRefSimple extends AssocOneHelp {
|
||||
|
||||
AssocOneHelpRefSimple(BeanPropertyAssocOne property) {
|
||||
super(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append columns for foreign key columns.
|
||||
*/
|
||||
@Override
|
||||
void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
property.importedId.sqlAppend(ctx);
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,12 @@ import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebean.annotation.ConcurrencyMode;
|
||||
import com.avaje.ebean.annotation.DocStoreEvent;
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.bean.PersistenceContextUtil;
|
||||
import com.avaje.ebean.config.EncryptKey;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.IdGenerator;
|
||||
@@ -33,7 +34,6 @@ import com.avaje.ebean.plugin.BeanDocType;
|
||||
import com.avaje.ebean.plugin.BeanType;
|
||||
import com.avaje.ebean.plugin.ExpressionPath;
|
||||
import com.avaje.ebean.plugin.Property;
|
||||
import com.avaje.ebean.text.json.JsonReadOptions;
|
||||
import com.avaje.ebeaninternal.api.CQueryPlanKey;
|
||||
import com.avaje.ebeaninternal.api.LoadContext;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
@@ -71,8 +71,9 @@ import com.avaje.ebeanservice.docstore.api.DocStoreBeanAdapter;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdateContext;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdates;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocMappingBuilder;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyMapping;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocumentMapping;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -80,11 +81,11 @@ import javax.persistence.PersistenceException;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -106,6 +107,28 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
|
||||
private final ConcurrentHashMap<String, ElComparator<T>> comparatorCache = new ConcurrentHashMap<String, ElComparator<T>>();
|
||||
|
||||
public void merge(EntityBean bean, EntityBean existing) {
|
||||
|
||||
EntityBeanIntercept fromEbi = bean._ebean_getIntercept();
|
||||
EntityBeanIntercept toEbi = existing._ebean_getIntercept();
|
||||
|
||||
int propertyLength = toEbi.getPropertyLength();
|
||||
String[] names = getProperties();
|
||||
|
||||
for (int i = 0; i < propertyLength; i++) {
|
||||
|
||||
if (fromEbi.isLoadedProperty(i) ) {
|
||||
BeanProperty property = getBeanProperty(names[i]);
|
||||
if (!toEbi.isLoadedProperty(i)) {
|
||||
Object val = property.getValue(bean);
|
||||
property.setValue(existing, val);
|
||||
} else if (property.isMany()) {
|
||||
property.merge(bean, existing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum EntityType {
|
||||
ORM, EMBEDDED, SQL
|
||||
}
|
||||
@@ -193,6 +216,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
* The type of bean this describes.
|
||||
*/
|
||||
private final Class<T> beanType;
|
||||
protected final Class<?> rootBeanType;
|
||||
|
||||
/**
|
||||
* This is not sent to a remote client.
|
||||
@@ -359,15 +383,14 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
|
||||
private final String docStoreQueueId;
|
||||
|
||||
private DocumentMapping docMapping;
|
||||
|
||||
private final BeanDescriptorDraftHelp<T> draftHelp;
|
||||
private final BeanDescriptorCacheHelp<T> cacheHelp;
|
||||
private final BeanDescriptorJsonHelp<T> jsonHelp;
|
||||
private final DocStoreBeanAdapter<T> docStoreAdapter;
|
||||
private DocStoreBeanAdapter<T> docStoreAdapter;
|
||||
private DocumentMapping docMapping;
|
||||
|
||||
|
||||
private final String defaultSelectClause;
|
||||
private final LinkedHashSet<String> defaultSelectClauseSet;
|
||||
|
||||
private SpiEbeanServer ebeanServer;
|
||||
|
||||
@@ -386,6 +409,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
this.fullName = InternString.intern(deploy.getFullName());
|
||||
|
||||
this.beanType = deploy.getBeanType();
|
||||
this.rootBeanType = PersistenceContextUtil.root(beanType);
|
||||
this.prototypeEntityBean = createPrototypeEntityBean(beanType);
|
||||
|
||||
this.namedQueries = deploy.getNamedQueries();
|
||||
@@ -401,8 +425,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
this.changeLogFilter = deploy.getChangeLogFilter();
|
||||
|
||||
this.defaultSelectClause = deploy.getDefaultSelectClause();
|
||||
this.defaultSelectClauseSet = deploy.parseDefaultSelectClause(defaultSelectClause);
|
||||
|
||||
this.idType = deploy.getIdType();
|
||||
this.idTypePlatformDefault = deploy.isIdTypePlatformDefault();
|
||||
this.idGenerator = deploy.getIdGenerator();
|
||||
@@ -684,7 +706,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
namedUpdate.initialise(parser);
|
||||
}
|
||||
}
|
||||
docStoreAdapter.registerPaths();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -694,7 +715,11 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
for (int i = 0; i < propertiesMany.length; i++) {
|
||||
propertiesMany[i].initialisePostTarget();
|
||||
}
|
||||
if (inheritInfo != null && !inheritInfo.isRoot()) {
|
||||
docStoreAdapter = (DocStoreBeanAdapter<T>)inheritInfo.getRoot().getBeanDescriptor().docStoreAdapter();
|
||||
}
|
||||
docMapping = docStoreAdapter.createDocMapping();
|
||||
docStoreAdapter.registerPaths();
|
||||
}
|
||||
|
||||
public void initInheritInfo() {
|
||||
@@ -889,13 +914,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
return defaultSelectClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default select clause already parsed into an ordered Set.
|
||||
*/
|
||||
public LinkedHashSet<String> getDefaultSelectClauseSet() {
|
||||
return defaultSelectClauseSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this object is the root level object in its entity
|
||||
* inheritance.
|
||||
@@ -929,7 +947,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
* Return the doc store helper for this bean type.
|
||||
*/
|
||||
@Override
|
||||
public BeanDocType docStore() {
|
||||
public BeanDocType<T> docStore() {
|
||||
return docStoreAdapter;
|
||||
}
|
||||
|
||||
@@ -943,24 +961,52 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
/**
|
||||
* Build the Document mapping recursively with the given prefix relative to the root of the document.
|
||||
*/
|
||||
public void docStoreMapping(DocMappingBuilder mapping, String prefix) {
|
||||
public void docStoreMapping(final DocMappingBuilder mapping, final String prefix) {
|
||||
|
||||
if (prefix != null && idProperty != null) {
|
||||
// id property not included in the
|
||||
idProperty.docStoreMapping(mapping, prefix);
|
||||
}
|
||||
|
||||
if (inheritInfo != null) {
|
||||
String discCol = inheritInfo.getDiscriminatorColumn();
|
||||
if (Types.VARCHAR == inheritInfo.getDiscriminatorType()) {
|
||||
mapping.add(new DocPropertyMapping(discCol, DocPropertyType.ENUM));
|
||||
} else {
|
||||
mapping.add(new DocPropertyMapping(discCol, DocPropertyType.INTEGER));
|
||||
}
|
||||
}
|
||||
for (BeanProperty prop: propertiesNonTransient) {
|
||||
prop.docStoreMapping(mapping, prefix);
|
||||
}
|
||||
if (inheritInfo != null) {
|
||||
inheritInfo.visitChildren(new InheritInfoVisitor() {
|
||||
@Override
|
||||
public void visit(InheritInfo inheritInfo) {
|
||||
for (BeanProperty localProperty : inheritInfo.localProperties()) {
|
||||
localProperty.docStoreMapping(mapping, prefix);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of DocStoreEvent that should occur for this type of persist request
|
||||
* Return the root bean type if part of inheritance hierarchy.
|
||||
*/
|
||||
public BeanType<?> root() {
|
||||
if (inheritInfo != null && !inheritInfo.isRoot()) {
|
||||
return inheritInfo.getRoot().getBeanDescriptor();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of DocStoreMode that should occur for this type of persist request
|
||||
* given the transactions requested mode.
|
||||
*/
|
||||
public DocStoreEvent getDocStoreEvent(PersistRequest.Type persistType, DocStoreEvent txnMode) {
|
||||
return docStoreAdapter.getEvent(persistType, txnMode);
|
||||
public DocStoreMode getDocStoreMode(PersistRequest.Type persistType, DocStoreMode txnMode) {
|
||||
return docStoreAdapter.getMode(persistType, txnMode);
|
||||
}
|
||||
|
||||
public void docStoreInsert(Object idValue, PersistRequestBean<T> persistRequest, DocStoreUpdateContext bulkUpdate) throws IOException {
|
||||
@@ -1457,6 +1503,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public T createBean() {
|
||||
return (T)createEntityBean();
|
||||
}
|
||||
@@ -1464,6 +1511,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
/**
|
||||
* Creates a new EntityBean.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public EntityBean createEntityBean() {
|
||||
try {
|
||||
EntityBean bean = (EntityBean)prototypeEntityBean._ebean_newInstance();
|
||||
@@ -1502,14 +1550,14 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
}
|
||||
try {
|
||||
EntityBean eb = createEntityBean();
|
||||
|
||||
convertSetId(id, eb);
|
||||
|
||||
EntityBeanIntercept ebi = eb._ebean_getIntercept();
|
||||
ebi.setBeanLoader(ebeanServer);
|
||||
|
||||
// Note: not creating proxies for many's...
|
||||
ebi.setReference(idPropertyIndex);
|
||||
if (Boolean.TRUE == readOnly) {
|
||||
ebi.setReadOnly(true);
|
||||
}
|
||||
|
||||
return (T) eb;
|
||||
|
||||
@@ -1548,7 +1596,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
}
|
||||
String[] splitBegin = SplitName.splitBegin(path);
|
||||
|
||||
BeanProperty beanProperty = propMap.get(splitBegin[0]);
|
||||
BeanProperty beanProperty = findBeanProperty(splitBegin[0]);
|
||||
if (beanProperty instanceof BeanPropertyAssoc<?>) {
|
||||
BeanPropertyAssoc<?> assocProp = (BeanPropertyAssoc<?>) beanProperty;
|
||||
return assocProp.getTargetDescriptor().getBeanDescriptor(splitBegin[1]);
|
||||
@@ -1642,6 +1690,59 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bean from the persistence context.
|
||||
*/
|
||||
public Object contextGet(PersistenceContext pc, Object id) {
|
||||
return pc.get(rootBeanType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bean from the persistence context with delete check option.
|
||||
*/
|
||||
public PersistenceContext.WithOption contextGetWithOption(PersistenceContext pc, Object id) {
|
||||
return pc.getWithOption(rootBeanType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the bean into the persistence context.
|
||||
*/
|
||||
public void contextPut(PersistenceContext pc, Object id, Object bean) {
|
||||
pc.put(rootBeanType, id, bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the bean into the persistence context if it is absent.
|
||||
*/
|
||||
public Object contextPutIfAbsent(PersistenceContext pc, Object id, EntityBean localBean) {
|
||||
return pc.putIfAbsent(rootBeanType, id, localBean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a reference bean and put it in the persistence context (and return it).
|
||||
*/
|
||||
public Object contextRef(PersistenceContext pc, Boolean readOnly, Object id) {
|
||||
Object ref = createReference(readOnly, id);
|
||||
if (pc != null) {
|
||||
contextPut(pc, id, ref);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a bean from the persistence context.
|
||||
*/
|
||||
public void contextClear(PersistenceContext pc, Object idValue) {
|
||||
pc.clear(rootBeanType, idValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bean from the persistence context (such that we don't fetch it in the same transaction).
|
||||
*/
|
||||
public void contextDeleted(PersistenceContext pc, Object idValue) {
|
||||
pc.deleted(rootBeanType, idValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to return the unique property. If only one property makes up
|
||||
* the unique id then it's value is returned. If there is a concatenated
|
||||
@@ -1718,7 +1819,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
|
||||
@Override
|
||||
public Property getProperty(String propName) {
|
||||
return getBeanProperty(propName);
|
||||
return findBeanProperty(propName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1985,6 +2086,30 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
return inheritInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasInheritance() {
|
||||
return inheritInfo != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDiscColumn() {
|
||||
return inheritInfo.getDiscriminatorColumn();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public T createBeanUsingDisc(Object discValue) {
|
||||
InheritInfo type = inheritInfo.getType(discValue.toString());
|
||||
return (T)type.getBeanDescriptor().createBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInheritanceWhere(SpiQuery<?> query) {
|
||||
if (inheritInfo != null && !inheritInfo.isRoot()) {
|
||||
query.where().eq(inheritInfo.getDiscriminatorColumn(), inheritInfo.getDiscriminatorValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is an embedded bean.
|
||||
*/
|
||||
@@ -2660,9 +2785,4 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
return jsonHelp.jsonReadObject(jsonRead, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T jsonRead(JsonParser parser, JsonReadOptions readOptions, Object objectMapper) throws IOException {
|
||||
ReadJson jsonRead = new ReadJson(this, parser, readOptions, objectMapper);
|
||||
return jsonRead(jsonRead, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ public final class BeanDescriptorCacheHelp<T> {
|
||||
EntityBeanIntercept refEbi = ((EntityBean) refBean)._ebean_getIntercept();
|
||||
|
||||
many.add(bc, (EntityBean) refBean);
|
||||
persistenceContext.put(id, refBean);
|
||||
targetDescriptor.contextPut(persistenceContext, id, refBean);
|
||||
refEbi.setPersistenceContext(persistenceContext);
|
||||
}
|
||||
return true;
|
||||
@@ -343,8 +343,7 @@ public final class BeanDescriptorCacheHelp<T> {
|
||||
EntityBeanIntercept ebi = entityBean._ebean_getIntercept();
|
||||
ebi.setPersistenceContext(context);
|
||||
Object id = desc.getId(entityBean);
|
||||
context.put(id, bean);
|
||||
|
||||
desc.contextPut(context, id, bean);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -254,7 +254,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> DocStoreBeanAdapter<T> createDocStoreBeanAdapter(BeanDescriptor descriptor, DeployBeanDescriptor<T> deploy) {
|
||||
public <T> DocStoreBeanAdapter<T> createDocStoreBeanAdapter(BeanDescriptor<T> descriptor, DeployBeanDescriptor<T> deploy) {
|
||||
return docStoreFactory.createAdapter(descriptor, deploy);
|
||||
}
|
||||
|
||||
@@ -311,8 +311,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
try {
|
||||
createListeners();
|
||||
readEmbeddedDeployment();
|
||||
readEntityDeploymentInitial();
|
||||
readEmbeddedDeployment();
|
||||
readEntityBeanTable();
|
||||
readEntityDeploymentAssociations();
|
||||
readInheritedIdGenerators();
|
||||
@@ -338,8 +338,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
return asOfTableMap;
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
String msg = "Error in deployment";
|
||||
logger.error(msg, e);
|
||||
logger.error("Error in deployment", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -532,12 +531,17 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private <T> BeanDescriptor<T> createEmbedded(Class<T> beanClass) {
|
||||
|
||||
DeployBeanInfo<T> info = createDeployBeanInfo(beanClass);
|
||||
readDeployAssociations(info);
|
||||
DeployBeanInfo<T> info = getDeploy(beanClass);
|
||||
return new BeanDescriptor<T>(this, info.getDescriptor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean deploy info for the given class.
|
||||
*/
|
||||
public <T> DeployBeanInfo<T> getDeploy(Class<T> cls) {
|
||||
return (DeployBeanInfo<T>) deplyInfoMap.get(cls);
|
||||
}
|
||||
|
||||
private void registerBeanDescriptor(BeanDescriptor<?> desc) {
|
||||
descMap.put(desc.getBeanType().getName(), desc);
|
||||
if (desc.isDocStoreMapped()) {
|
||||
@@ -552,13 +556,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
List<Class<?>> embeddedClasses = bootupClasses.getEmbeddables();
|
||||
for (int i = 0; i < embeddedClasses.size(); i++) {
|
||||
Class<?> cls = embeddedClasses.get(i);
|
||||
if (logger.isTraceEnabled()) {
|
||||
String msg = "load deployinfo for embeddable:" + cls.getName();
|
||||
logger.trace(msg);
|
||||
}
|
||||
BeanDescriptor<?> embDesc = createEmbedded(cls);
|
||||
registerBeanDescriptor(embDesc);
|
||||
registerBeanDescriptor(createEmbedded(embeddedClasses.get(i)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,12 +569,15 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
*/
|
||||
private void readEntityDeploymentInitial() {
|
||||
|
||||
List<Class<?>> entityClasses = bootupClasses.getEntities();
|
||||
|
||||
for (Class<?> entityClass : entityClasses) {
|
||||
for (Class<?> entityClass : bootupClasses.getEntities()) {
|
||||
DeployBeanInfo<?> info = createDeployBeanInfo(entityClass);
|
||||
deplyInfoMap.put(entityClass, info);
|
||||
}
|
||||
for (Class<?> entityClass : bootupClasses.getEmbeddables()) {
|
||||
DeployBeanInfo<?> info = createDeployBeanInfo(entityClass);
|
||||
readDeployAssociations(info);
|
||||
deplyInfoMap.put(entityClass, info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1075,7 +1076,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
*/
|
||||
private <T> DeployBeanInfo<T> createDeployBeanInfo(Class<T> beanClass) {
|
||||
|
||||
DeployBeanDescriptor<T> desc = new DeployBeanDescriptor<T>(beanClass, serverConfig);
|
||||
DeployBeanDescriptor<T> desc = new DeployBeanDescriptor<T>(this, beanClass, serverConfig);
|
||||
|
||||
desc.setUpdateChangesOnly(updateChangesOnly);
|
||||
|
||||
|
||||
@@ -48,5 +48,5 @@ public interface BeanDescriptorMap {
|
||||
/**
|
||||
* Create a doc store specific adapter for this bean type.
|
||||
*/
|
||||
<T> DocStoreBeanAdapter<T> createDocStoreBeanAdapter(BeanDescriptor descriptor, DeployBeanDescriptor<T> deploy);
|
||||
<T> DocStoreBeanAdapter<T> createDocStoreBeanAdapter(BeanDescriptor<T> descriptor, DeployBeanDescriptor<T> deploy);
|
||||
}
|
||||
|
||||
@@ -98,14 +98,14 @@ public final class BeanFkeyProperty implements ElPropertyValue {
|
||||
/**
|
||||
* Returns null as not an AssocOne.
|
||||
*/
|
||||
public Object[] getAssocOneIdValues(EntityBean value) {
|
||||
public Object[] getAssocIdValues(EntityBean value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null as not an AssocOne.
|
||||
*/
|
||||
public String getAssocOneIdExpr(String prefix, String operator) {
|
||||
public String getAssocIdExpression(String prefix, String operator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -162,24 +162,23 @@ public final class BeanFkeyProperty implements ElPropertyValue {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
public Object elConvertType(Object value) {
|
||||
@Override
|
||||
public Object convert(Object value) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object bean, Object value) {
|
||||
public void pathSet(Object bean, Object value) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
public void elSetValue(EntityBean bean, Object value, boolean populate) {
|
||||
@Override
|
||||
public Object pathGet(Object bean) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
public Object elGetValue(EntityBean bean) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
public Object elGetReference(EntityBean bean) {
|
||||
@Override
|
||||
public Object pathGetNested(Object bean) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.config.EncryptKey;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeEnum;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocMappingBuilder;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyMapping;
|
||||
import com.avaje.ebean.plugin.Property;
|
||||
@@ -220,6 +219,11 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
*/
|
||||
final String dbColumnDefn;
|
||||
|
||||
/**
|
||||
* DB Column default value for DDL definition (FALSE, NOW etc).
|
||||
*/
|
||||
final String dbColumnDefault;
|
||||
|
||||
/**
|
||||
* Database DDL column comment.
|
||||
*/
|
||||
@@ -299,6 +303,7 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
this.dbScale = deploy.getDbScale();
|
||||
this.dbColumnDefn = InternString.intern(deploy.getDbColumnDefn());
|
||||
this.dbConstraintExpression = InternString.intern(deploy.getDbConstraintExpression());
|
||||
this.dbColumnDefault = deploy.getDbColumnDefault();
|
||||
|
||||
this.inherited = false;// deploy.isInherited();
|
||||
this.owningType = deploy.getOwningType();
|
||||
@@ -408,6 +413,7 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
this.dbScale = source.getDbScale();
|
||||
this.dbColumnDefn = InternString.intern(source.getDbColumnDefn());
|
||||
this.dbConstraintExpression = InternString.intern(source.getDbConstraintExpression());
|
||||
this.dbColumnDefault = source.dbColumnDefault;
|
||||
|
||||
this.inherited = source.isInherited();
|
||||
this.owningType = source.owningType;
|
||||
@@ -462,7 +468,7 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
|
||||
public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain,
|
||||
boolean propertyDeploy) {
|
||||
throw new PersistenceException("Not valid on scalar bean property " + getFullBeanName());
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -768,7 +774,7 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
}
|
||||
}
|
||||
|
||||
public Object elConvertType(Object value) {
|
||||
public Object convert(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -776,28 +782,24 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object bean, Object value) {
|
||||
public void pathSet(Object bean, Object value) {
|
||||
|
||||
// convert for Enums etc
|
||||
Object logicalVal = convertToLogicalType(value);
|
||||
elSetValue((EntityBean) bean, logicalVal, true);
|
||||
}
|
||||
|
||||
public void elSetValue(EntityBean bean, Object value, boolean populate) {
|
||||
if (bean != null) {
|
||||
// Not using setValueIntercept at this stage
|
||||
setValue(bean, value);
|
||||
Object logicalVal = convertToLogicalType(value);
|
||||
setValue((EntityBean)bean, logicalVal);
|
||||
}
|
||||
}
|
||||
|
||||
public Object elGetValue(EntityBean bean) {
|
||||
@Override
|
||||
public Object pathGet(Object bean) {
|
||||
if (bean == null) {
|
||||
return null;
|
||||
}
|
||||
return getValueIntercept(bean);
|
||||
return getValueIntercept((EntityBean)bean);
|
||||
}
|
||||
|
||||
public Object elGetReference(EntityBean bean) {
|
||||
@Override
|
||||
public Object pathGetNested(Object bean) {
|
||||
throw new RuntimeException("Not expected to call this");
|
||||
}
|
||||
|
||||
@@ -832,12 +834,12 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object[] getAssocOneIdValues(EntityBean bean) {
|
||||
public Object[] getAssocIdValues(EntityBean bean) {
|
||||
// Returns null as not an AssocOne.
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getAssocOneIdExpr(String prefix, String operator) {
|
||||
public String getAssocIdExpression(String prefix, String operator) {
|
||||
// Returns null as not an AssocOne.
|
||||
return null;
|
||||
}
|
||||
@@ -950,6 +952,13 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
return dbType.renderType(dbLength, dbScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB column default to use for DDL.
|
||||
*/
|
||||
public String getDbColumnDefault() {
|
||||
return dbColumnDefn != null ? null : dbColumnDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean Field associated with this property.
|
||||
*/
|
||||
@@ -1243,7 +1252,8 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
writeJson.writeNullField(name);
|
||||
} else {
|
||||
if (scalarType != null) {
|
||||
scalarType.jsonWrite(writeJson, name, value);
|
||||
writeJson.writeFieldName(name);
|
||||
scalarType.jsonWrite(writeJson.gen(), value);
|
||||
} else {
|
||||
writeJson.writeValueUsingObjectMapper(name, value);
|
||||
}
|
||||
@@ -1261,7 +1271,7 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
// expect to read non-null json value
|
||||
Object objValue;
|
||||
if (scalarType != null) {
|
||||
objValue = scalarType.jsonRead(ctx.getParser(), event);
|
||||
objValue = scalarType.jsonRead(ctx.getParser());
|
||||
} else {
|
||||
try {
|
||||
objValue = ctx.readValueUsingObjectMapper(propertyType);
|
||||
@@ -1318,7 +1328,7 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
|
||||
DocPropertyType type = scalarType.getDocType();
|
||||
DocPropertyOptions options = docOptions.copy();
|
||||
if (DocPropertyType.STRING == type && isDocCode()) {
|
||||
if (DocPropertyType.ENUM == type || isStringId(type)) {
|
||||
options.setCode(true);
|
||||
}
|
||||
|
||||
@@ -1327,9 +1337,13 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this should be treated as a 'code' (effectively not analysed).
|
||||
* Return true if this is a String Id property and should be treated as a code by the document store.
|
||||
*/
|
||||
private boolean isDocCode() {
|
||||
return id || scalarType instanceof ScalarTypeEnum;
|
||||
private boolean isStringId(DocPropertyType type) {
|
||||
return DocPropertyType.STRING == type && (id || discriminator);
|
||||
}
|
||||
|
||||
public void merge(EntityBean bean, EntityBean existing) {
|
||||
// do nothing unless Many property
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,6 +201,27 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
|
||||
// by default not including "Many" properties in document store
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy collection value if existing is empty.
|
||||
*/
|
||||
@Override
|
||||
public void merge(EntityBean bean, EntityBean existing) {
|
||||
|
||||
Object existingCollection = getVal(existing);
|
||||
if (existingCollection instanceof BeanCollection<?>) {
|
||||
BeanCollection<?> toBC = (BeanCollection<?>)existingCollection;
|
||||
if (!toBC.isPopulated()) {
|
||||
Object fromCollection = getVal(bean);
|
||||
if (fromCollection instanceof BeanCollection<?>) {
|
||||
BeanCollection<?> fromBC = (BeanCollection<?>)fromCollection;
|
||||
if (fromBC.isPopulated()) {
|
||||
toBC.loadFrom(fromBC);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the bean to the appropriate collection on the parent bean.
|
||||
*/
|
||||
@@ -464,14 +485,14 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
|
||||
* Return the Id values from the given bean.
|
||||
*/
|
||||
@Override
|
||||
public Object[] getAssocOneIdValues(EntityBean bean) {
|
||||
public Object[] getAssocIdValues(EntityBean bean) {
|
||||
return targetDescriptor.getIdBinder().getIdValues(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Id expression to add to where clause etc.
|
||||
*/
|
||||
public String getAssocOneIdExpr(String prefix, String operator) {
|
||||
public String getAssocIdExpression(String prefix, String operator) {
|
||||
return targetDescriptor.getIdBinder().getAssocOneIdExpr(prefix, operator);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,8 @@ import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.cache.CachedBeanData;
|
||||
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder;
|
||||
@@ -40,22 +37,23 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
|
||||
private final boolean importedPrimaryKey;
|
||||
|
||||
private final LocalHelp localHelp;
|
||||
private AssocOneHelp localHelp;
|
||||
|
||||
private final BeanProperty[] embeddedProps;
|
||||
protected final BeanProperty[] embeddedProps;
|
||||
|
||||
private final HashMap<String, BeanProperty> embeddedPropsMap;
|
||||
|
||||
/**
|
||||
* The information for Imported foreign Keys.
|
||||
*/
|
||||
private ImportedId importedId;
|
||||
protected ImportedId importedId;
|
||||
|
||||
private ExportedProperty[] exportedProperties;
|
||||
|
||||
private String deleteByParentIdSql;
|
||||
private String deleteByParentIdInSql;
|
||||
BeanPropertyAssocMany<?> relationshipProperty;
|
||||
|
||||
private BeanPropertyAssocMany<?> relationshipProperty;
|
||||
|
||||
/**
|
||||
* Create based on deploy information of an EmbeddedId.
|
||||
@@ -72,7 +70,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
|
||||
super(descriptor, deploy);
|
||||
|
||||
importedPrimaryKey = false;//TODO: Review this - deploy.isImportedPrimaryKey();
|
||||
importedPrimaryKey = deploy.isImportedPrimaryKey();
|
||||
oneToOne = deploy.isOneToOne();
|
||||
oneToOneExported = deploy.isOneToOneExported();
|
||||
|
||||
@@ -89,12 +87,13 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
embeddedProps = null;
|
||||
embeddedPropsMap = null;
|
||||
}
|
||||
localHelp = createHelp(embedded, oneToOneExported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialise() {
|
||||
super.initialise();
|
||||
localHelp = createHelp(embedded, oneToOneExported);
|
||||
|
||||
if (!isTransient) {
|
||||
//noinspection StatementWithEmptyBody
|
||||
if (embedded) {
|
||||
@@ -129,21 +128,21 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
return (EntityBean) getValue(owner);
|
||||
}
|
||||
|
||||
public void setRelationshipProperty(BeanPropertyAssocMany<?> relationshipProperty) {
|
||||
void setRelationshipProperty(BeanPropertyAssocMany<?> relationshipProperty) {
|
||||
this.relationshipProperty = relationshipProperty;
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?> getRelationshipProperty() {
|
||||
BeanPropertyAssocMany<?> getRelationshipProperty() {
|
||||
return relationshipProperty;
|
||||
}
|
||||
|
||||
public void cacheClear() {
|
||||
void cacheClear() {
|
||||
if (targetDescriptor.isBeanCaching() && relationshipProperty != null) {
|
||||
targetDescriptor.cacheManyPropClear(relationshipProperty.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public void cacheDelete(boolean clearOnNull, EntityBean bean) {
|
||||
void cacheDelete(boolean clearOnNull, EntityBean bean) {
|
||||
if (targetDescriptor.isBeanCaching() && relationshipProperty != null) {
|
||||
Object assocBean = getValue(bean);
|
||||
if (assocBean != null) {
|
||||
@@ -270,7 +269,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public void addFkey() {
|
||||
void addFkey() {
|
||||
if (importedId != null) {
|
||||
importedId.addFkeys(name);
|
||||
}
|
||||
@@ -416,14 +415,14 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
* Return the Id values from the given bean.
|
||||
*/
|
||||
@Override
|
||||
public Object[] getAssocOneIdValues(EntityBean bean) {
|
||||
public Object[] getAssocIdValues(EntityBean bean) {
|
||||
return targetDescriptor.getIdBinder().getIdValues(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Id expression to add to where clause etc.
|
||||
*/
|
||||
public String getAssocOneIdExpr(String prefix, String operator) {
|
||||
public String getAssocIdExpression(String prefix, String operator) {
|
||||
return targetDescriptor.getIdBinder().getAssocOneIdExpr(prefix, operator);
|
||||
}
|
||||
|
||||
@@ -463,11 +462,11 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object elGetReference(EntityBean bean) {
|
||||
Object value = getValueIntercept(bean);
|
||||
public Object pathGetNested(Object bean) {
|
||||
Object value = getValueIntercept((EntityBean)bean);
|
||||
if (value == null) {
|
||||
value = targetDescriptor.createEntityBean();
|
||||
setValueIntercept(bean, value);
|
||||
setValueIntercept((EntityBean)bean, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -594,7 +593,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
/**
|
||||
* Set the owner on the embedded bean property.
|
||||
*/
|
||||
public void setEmbeddedOwner(EntityBean owner) {
|
||||
void setEmbeddedOwner(EntityBean owner) {
|
||||
|
||||
Object emb = getValue(owner);
|
||||
if (emb != null) {
|
||||
@@ -629,269 +628,17 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
private LocalHelp createHelp(boolean embedded, boolean oneToOneExported) {
|
||||
private AssocOneHelp createHelp(boolean embedded, boolean oneToOneExported) {
|
||||
if (embedded) {
|
||||
return new Embedded();
|
||||
return new AssocOneHelpEmbedded(this);
|
||||
} else if (oneToOneExported) {
|
||||
return new ReferenceExported();
|
||||
return new AssocOneHelpRefExported(this);
|
||||
} else {
|
||||
return new Reference();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Local interface to handle Embedded, Reference and Reference Exported
|
||||
* cases.
|
||||
*/
|
||||
private abstract class LocalHelp {
|
||||
|
||||
abstract void loadIgnore(DbReadContext ctx);
|
||||
|
||||
abstract Object read(DbReadContext ctx) throws SQLException;
|
||||
|
||||
abstract Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException;
|
||||
|
||||
abstract void appendSelect(DbSqlContext ctx, boolean subQuery);
|
||||
|
||||
abstract void appendFrom(DbSqlContext ctx, SqlJoinType joinType);
|
||||
|
||||
}
|
||||
|
||||
private final class Embedded extends LocalHelp {
|
||||
|
||||
void loadIgnore(DbReadContext ctx) {
|
||||
for (int i = 0; i < embeddedProps.length; i++) {
|
||||
embeddedProps[i].loadIgnore(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
|
||||
Object dbVal = read(ctx);
|
||||
if (bean != null) {
|
||||
// set back to the parent bean
|
||||
setValue(bean, dbVal);
|
||||
ctx.propagateState(dbVal);
|
||||
return dbVal;
|
||||
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object read(DbReadContext ctx) throws SQLException {
|
||||
|
||||
EntityBean embeddedBean = targetDescriptor.createEntityBean();
|
||||
|
||||
boolean notNull = false;
|
||||
for (int i = 0; i < embeddedProps.length; i++) {
|
||||
Object value = embeddedProps[i].readSet(ctx, embeddedBean);
|
||||
if (value != null) {
|
||||
notNull = true;
|
||||
}
|
||||
}
|
||||
if (notNull) {
|
||||
ctx.propagateState(embeddedBean);
|
||||
return embeddedBean;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
for (int i = 0; i < embeddedProps.length; i++) {
|
||||
embeddedProps[i].appendSelect(ctx, subQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For imported reference - this is the common case.
|
||||
*/
|
||||
private final class Reference extends LocalHelp {
|
||||
|
||||
Reference() {
|
||||
}
|
||||
|
||||
@Override
|
||||
void loadIgnore(DbReadContext ctx) {
|
||||
targetIdBinder.loadIgnore(ctx);
|
||||
if (targetInheritInfo != null) {
|
||||
ctx.getDataReader().incrementPos(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
|
||||
Object val = read(ctx);
|
||||
if (bean != null) {
|
||||
setValue(bean, val);
|
||||
ctx.propagateState(val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and set a Reference bean.
|
||||
*/
|
||||
@Override
|
||||
Object read(DbReadContext ctx) throws SQLException {
|
||||
|
||||
BeanDescriptor<?> rowDescriptor = null;
|
||||
Class<?> rowType = targetType;
|
||||
if (targetInheritInfo != null) {
|
||||
// read discriminator to determine the type
|
||||
InheritInfo rowInheritInfo = targetInheritInfo.readType(ctx);
|
||||
if (rowInheritInfo != null) {
|
||||
rowType = rowInheritInfo.getType();
|
||||
rowDescriptor = rowInheritInfo.getBeanDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
// read the foreign key column(s)
|
||||
Object id = targetIdBinder.read(ctx);
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// check transaction context to see if it already exists
|
||||
Object existing = ctx.getPersistenceContext().get(rowType, id);
|
||||
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
Boolean readOnly = ctx.isReadOnly();
|
||||
Object ref;
|
||||
if (targetInheritInfo != null) {
|
||||
// for inheritance hierarchy create the correct type for this row...
|
||||
ref = rowDescriptor.createReference(readOnly, id);
|
||||
return new AssocOneHelpRefInherit(this);
|
||||
} else {
|
||||
ref = targetDescriptor.createReference(readOnly, id);
|
||||
return new AssocOneHelpRefSimple(this);
|
||||
}
|
||||
|
||||
Object existingBean = ctx.getPersistenceContext().putIfAbsent(id, ref);
|
||||
if (existingBean != null) {
|
||||
// advanced case when we use multiple concurrent threads to
|
||||
// build a single object graph, and another thread has since
|
||||
// loaded a matching bean so we will use that instead.
|
||||
ref = existingBean;
|
||||
|
||||
} else {
|
||||
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
|
||||
if (Boolean.TRUE.equals(ctx.isReadOnly())) {
|
||||
ebi.setReadOnly(true);
|
||||
}
|
||||
ctx.register(name, ebi);
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
if (targetInheritInfo != null) {
|
||||
// add join to support the discriminator column
|
||||
String relativePrefix = ctx.getRelativePrefix(name);
|
||||
tableJoin.addJoin(joinType, relativePrefix, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append columns for foreign key columns.
|
||||
*/
|
||||
@Override
|
||||
void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
|
||||
if (!subQuery && targetInheritInfo != null) {
|
||||
// add discriminator column
|
||||
String relativePrefix = ctx.getRelativePrefix(getName());
|
||||
String tableAlias = ctx.getTableAlias(relativePrefix);
|
||||
ctx.appendColumn(tableAlias, targetInheritInfo.getDiscriminatorColumn());
|
||||
}
|
||||
importedId.sqlAppend(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For OneToOne exported reference - not so common.
|
||||
*/
|
||||
private final class ReferenceExported extends LocalHelp {
|
||||
|
||||
@Override
|
||||
void loadIgnore(DbReadContext ctx) {
|
||||
targetDescriptor.getIdBinder().loadIgnore(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and set a Reference bean.
|
||||
*/
|
||||
@Override
|
||||
Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
|
||||
|
||||
Object dbVal = read(ctx);
|
||||
if (bean != null) {
|
||||
setValue(bean, dbVal);
|
||||
ctx.propagateState(dbVal);
|
||||
}
|
||||
return dbVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
Object read(DbReadContext ctx) throws SQLException {
|
||||
|
||||
// TODO: Support for Inheritance hierarchy on exported OneToOne ?
|
||||
IdBinder idBinder = targetDescriptor.getIdBinder();
|
||||
Object id = idBinder.read(ctx);
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PersistenceContext persistCtx = ctx.getPersistenceContext();
|
||||
Object existing = persistCtx.get(targetType, id);
|
||||
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
Object ref = targetDescriptor.createReference(ctx.isReadOnly(), id);
|
||||
|
||||
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
|
||||
if (Boolean.TRUE.equals(ctx.isReadOnly())) {
|
||||
ebi.setReadOnly(true);
|
||||
}
|
||||
persistCtx.put(id, ref);
|
||||
ctx.register(name, ebi);
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append columns for foreign key columns.
|
||||
*/
|
||||
@Override
|
||||
void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
|
||||
// set appropriate tableAlias for the exported id columns
|
||||
|
||||
String relativePrefix = ctx.getRelativePrefix(getName());
|
||||
ctx.pushTableAlias(relativePrefix);
|
||||
|
||||
IdBinder idBinder = targetDescriptor.getIdBinder();
|
||||
idBinder.appendSelect(ctx, subQuery);
|
||||
|
||||
ctx.popTableAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
|
||||
String relativePrefix = ctx.getRelativePrefix(getName());
|
||||
tableJoin.addJoin(joinType, relativePrefix, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ public class BeanPropertyCompound extends BeanProperty {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object elGetReference(EntityBean bean) {
|
||||
public Object pathGetNested(Object bean) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@@ -155,6 +155,7 @@ public class BeanPropertyCompound extends BeanProperty {
|
||||
if (value == null) {
|
||||
ctx.writeNullField(name);
|
||||
} else {
|
||||
ctx.writeFieldName(name);
|
||||
compoundType.jsonWrite(ctx, value, name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,13 +72,13 @@ public class BeanPropertyCompoundScalar extends BeanProperty {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object elGetReference(EntityBean bean) {
|
||||
return getValue(bean);
|
||||
public Object pathGetNested(Object bean) {
|
||||
return pathGet(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object elGetValue(EntityBean bean) {
|
||||
return getValue(bean);
|
||||
public Object pathGet(Object bean) {
|
||||
return ctProperty.getValue(bean);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,64 +10,71 @@ import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyOptions;
|
||||
*/
|
||||
public class DeployDocPropertyOptions {
|
||||
|
||||
private Boolean code;
|
||||
private static DocPropertyOptions EMPTY = new DocPropertyOptions();
|
||||
|
||||
private Boolean sortable;
|
||||
|
||||
private Boolean store;
|
||||
|
||||
private Float boost;
|
||||
|
||||
private String nullValue;
|
||||
private DocPropertyOptions mapping;
|
||||
|
||||
private void createOptions() {
|
||||
if (mapping == null) {
|
||||
mapping = new DocPropertyOptions();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Read the DocProperty deployment options.
|
||||
*/
|
||||
public void setDocProperty(DocProperty doc) {
|
||||
code = checkDefault(doc.code());
|
||||
sortable = checkDefault(doc.sortable());
|
||||
store = checkDefault(doc.store());
|
||||
boost = checkDefault(doc.boost());
|
||||
nullValue = checkDefault(doc.nullValue());
|
||||
|
||||
createOptions();
|
||||
mapping.apply(doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the DocSortable deployment options.
|
||||
*/
|
||||
public void setDocSortable(DocSortable doc) {
|
||||
sortable = Boolean.TRUE;
|
||||
store = checkDefault(doc.store());
|
||||
boost = checkDefault(doc.boost());
|
||||
nullValue = checkDefault(doc.nullValue());
|
||||
|
||||
createOptions();
|
||||
mapping.setSortable(true);
|
||||
setStore(doc.store());
|
||||
setBoost(doc.boost());
|
||||
setNullValue(doc.nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the DocCode deployment options.
|
||||
*/
|
||||
public void setDocCode(DocCode doc) {
|
||||
code = Boolean.TRUE;
|
||||
store = checkDefault(doc.store());
|
||||
boost = checkDefault(doc.boost());
|
||||
nullValue = checkDefault(doc.nullValue());
|
||||
|
||||
createOptions();
|
||||
mapping.setCode(true);
|
||||
setStore(doc.store());
|
||||
setBoost(doc.boost());
|
||||
setNullValue(doc.nullValue());
|
||||
}
|
||||
|
||||
private String checkDefault(String s) {
|
||||
return "".equals(s) ? null : s;
|
||||
private void setNullValue(String value) {
|
||||
if (!value.equals("")) {
|
||||
mapping.setNullValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
private Float checkDefault(float boost) {
|
||||
return (boost == 1) ? null : boost;
|
||||
private void setBoost(float boost) {
|
||||
if (boost != 1) {
|
||||
mapping.setBoost(boost);
|
||||
}
|
||||
}
|
||||
|
||||
private Boolean checkDefault(boolean store) {
|
||||
return (store) ? Boolean.TRUE : null;
|
||||
private void setStore(boolean store) {
|
||||
if (store) {
|
||||
mapping.setStore(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DocPropertyOptions with the collected options.
|
||||
*/
|
||||
public DocPropertyOptions create() {
|
||||
return new DocPropertyOptions(code, sortable, store, boost, nullValue);
|
||||
return (mapping == null) ? EMPTY : mapping;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -145,6 +145,13 @@ public class InheritInfo {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the local properties for this node in the hierarchy.
|
||||
*/
|
||||
public BeanProperty[] localProperties() {
|
||||
return descriptor.propertiesLocal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bean property additionally looking in the sub types.
|
||||
*/
|
||||
|
||||
+67
-48
@@ -2,7 +2,7 @@ package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import com.avaje.ebean.annotation.ConcurrencyMode;
|
||||
import com.avaje.ebean.annotation.DocStore;
|
||||
import com.avaje.ebean.annotation.DocStoreEvent;
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.TableName;
|
||||
import com.avaje.ebean.config.dbplatform.IdGenerator;
|
||||
@@ -14,8 +14,10 @@ import com.avaje.ebean.event.BeanPostLoad;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogFilter;
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
import com.avaje.ebean.util.CamelCaseHelper;
|
||||
import com.avaje.ebeaninternal.server.core.CacheOptions;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.ChainedBeanPersistController;
|
||||
import com.avaje.ebeaninternal.server.deploy.ChainedBeanPersistListener;
|
||||
import com.avaje.ebeaninternal.server.deploy.ChainedBeanPostLoad;
|
||||
@@ -25,6 +27,7 @@ import com.avaje.ebeaninternal.server.deploy.DRawSqlMeta;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployNamedQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployNamedUpdate;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployBeanInfo;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
@@ -34,7 +37,6 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -43,7 +45,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class DeployBeanDescriptor<T> {
|
||||
|
||||
static class PropOrder implements Comparator<DeployBeanProperty> {
|
||||
private static class PropOrder implements Comparator<DeployBeanProperty> {
|
||||
|
||||
public int compare(DeployBeanProperty o1, DeployBeanProperty o2) {
|
||||
|
||||
@@ -59,6 +61,8 @@ public class DeployBeanDescriptor<T> {
|
||||
|
||||
private final ServerConfig serverConfig;
|
||||
|
||||
private final BeanDescriptorManager manager;
|
||||
|
||||
/**
|
||||
* Map of BeanProperty Linked so as to preserve order.
|
||||
*/
|
||||
@@ -187,19 +191,29 @@ public class DeployBeanDescriptor<T> {
|
||||
|
||||
private String docStoreIndexType;
|
||||
|
||||
private DocStoreEvent docStorePersist;
|
||||
private DocStoreEvent docStoreInsert;
|
||||
private DocStoreEvent docStoreUpdate;
|
||||
private DocStoreEvent docStoreDelete;
|
||||
private DocStoreMode docStorePersist;
|
||||
private DocStoreMode docStoreInsert;
|
||||
private DocStoreMode docStoreUpdate;
|
||||
private DocStoreMode docStoreDelete;
|
||||
|
||||
private List<DeployBeanProperty> idProperties;
|
||||
|
||||
/**
|
||||
* Construct the BeanDescriptor.
|
||||
*/
|
||||
public DeployBeanDescriptor(Class<T> beanType, ServerConfig serverConfig) {
|
||||
public DeployBeanDescriptor(BeanDescriptorManager manager, Class<T> beanType, ServerConfig serverConfig) {
|
||||
this.manager = manager;
|
||||
this.serverConfig = serverConfig;
|
||||
this.beanType = beanType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DeployBeanInfo for the given bean class.
|
||||
*/
|
||||
DeployBeanInfo<?> getDeploy(Class<?> cls) {
|
||||
return manager.getDeploy(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this beanType is an abstract class.
|
||||
*/
|
||||
@@ -275,7 +289,7 @@ public class DeployBeanDescriptor<T> {
|
||||
docStoreUpdate = docStore.update();
|
||||
docStoreDelete = docStore.delete();
|
||||
String doc = docStore.doc();
|
||||
if (doc != null && doc.length() > 0) {
|
||||
if (doc.length() > 0) {
|
||||
docStorePathProperties = PathProperties.parse(doc);
|
||||
}
|
||||
}
|
||||
@@ -628,6 +642,34 @@ public class DeployBeanDescriptor<T> {
|
||||
return propMap.put(prop.getName(), prop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the matching property for a given property name or dbColumn.
|
||||
* <p>
|
||||
* This is primarily to find imported primary key columns (ManyToOne that also match the PK).
|
||||
* </p>
|
||||
*/
|
||||
DeployBeanProperty findMatch(String propertyName, String dbColumn) {
|
||||
|
||||
DeployBeanProperty prop = propMap.get(propertyName);
|
||||
if (prop != null) {
|
||||
return prop;
|
||||
}
|
||||
if (dbColumn != null) {
|
||||
String asCamel = CamelCaseHelper.toCamelFromUnderscore(dbColumn);
|
||||
prop = propMap.get(asCamel);
|
||||
if (prop != null) {
|
||||
return prop;
|
||||
}
|
||||
// scan looking for dbColumn match
|
||||
for (DeployBeanProperty property : propMap.values()) {
|
||||
if (dbColumn.equals(property.getDbColumn())) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a BeanProperty by its name.
|
||||
*/
|
||||
@@ -698,7 +740,7 @@ public class DeployBeanDescriptor<T> {
|
||||
/**
|
||||
* Set the DB sequence name.
|
||||
*/
|
||||
public void setSequenceName(String sequenceName) {
|
||||
private void setSequenceName(String sequenceName) {
|
||||
this.sequenceName = sequenceName;
|
||||
}
|
||||
|
||||
@@ -765,7 +807,7 @@ public class DeployBeanDescriptor<T> {
|
||||
tableJoinList.add(join);
|
||||
}
|
||||
|
||||
public List<DeployTableJoin> getTableJoins() {
|
||||
List<DeployTableJoin> getTableJoins() {
|
||||
return tableJoinList;
|
||||
}
|
||||
|
||||
@@ -805,29 +847,6 @@ public class DeployBeanDescriptor<T> {
|
||||
return selectClause.substring(0, selectClause.length() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the include separating by comma or semicolon.
|
||||
*/
|
||||
public LinkedHashSet<String> parseDefaultSelectClause(String rawList) {
|
||||
|
||||
if (rawList == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] res = rawList.split(",");
|
||||
|
||||
LinkedHashSet<String> set = new LinkedHashSet<String>(res.length + 3);
|
||||
|
||||
String temp;
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
temp = res[i].trim();
|
||||
if (temp.length() > 0) {
|
||||
set.add(temp);
|
||||
}
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the primary key is a compound key or if it's database type
|
||||
* is non-numeric (and hence not suitable for db identity or sequence.
|
||||
@@ -874,15 +893,15 @@ public class DeployBeanDescriptor<T> {
|
||||
*/
|
||||
public List<DeployBeanProperty> propertiesId() {
|
||||
|
||||
ArrayList<DeployBeanProperty> list = new ArrayList<DeployBeanProperty>(2);
|
||||
|
||||
for (DeployBeanProperty prop : propMap.values()) {
|
||||
if (prop.isId()) {
|
||||
list.add(prop);
|
||||
if (idProperties == null) {
|
||||
idProperties = new ArrayList<DeployBeanProperty>(2);
|
||||
for (DeployBeanProperty prop : propMap.values()) {
|
||||
if (prop.isId()) {
|
||||
idProperties.add(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
return idProperties;
|
||||
}
|
||||
|
||||
public DeployBeanPropertyAssocOne<?> findJoinToTable(String tableName) {
|
||||
@@ -1008,30 +1027,30 @@ public class DeployBeanDescriptor<T> {
|
||||
/**
|
||||
* Return the DocStore index behavior for bean inserts.
|
||||
*/
|
||||
public DocStoreEvent getDocStoreInsertEvent() {
|
||||
public DocStoreMode getDocStoreInsertEvent() {
|
||||
return getDocStoreIndexEvent(docStoreInsert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DocStore index behavior for bean updates.
|
||||
*/
|
||||
public DocStoreEvent getDocStoreUpdateEvent() {
|
||||
public DocStoreMode getDocStoreUpdateEvent() {
|
||||
return getDocStoreIndexEvent(docStoreUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DocStore index behavior for bean deletes.
|
||||
*/
|
||||
public DocStoreEvent getDocStoreDeleteEvent() {
|
||||
public DocStoreMode getDocStoreDeleteEvent() {
|
||||
return getDocStoreIndexEvent(docStoreDelete);
|
||||
}
|
||||
|
||||
private DocStoreEvent getDocStoreIndexEvent(DocStoreEvent mostSpecific) {
|
||||
private DocStoreMode getDocStoreIndexEvent(DocStoreMode mostSpecific) {
|
||||
if (!docStoreMapped) {
|
||||
return DocStoreEvent.IGNORE;
|
||||
return DocStoreMode.IGNORE;
|
||||
}
|
||||
if (mostSpecific != DocStoreEvent.DEFAULT) return mostSpecific;
|
||||
if (docStorePersist != DocStoreEvent.DEFAULT) return docStorePersist;
|
||||
if (mostSpecific != DocStoreMode.DEFAULT) return mostSpecific;
|
||||
if (docStorePersist != DocStoreMode.DEFAULT) return docStorePersist;
|
||||
return serverConfig.getDocStoreConfig().getPersist();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.avaje.ebean.annotation.WhenModified;
|
||||
import com.avaje.ebean.annotation.WhoCreated;
|
||||
import com.avaje.ebean.annotation.WhoModified;
|
||||
import com.avaje.ebean.config.ScalarTypeConverter;
|
||||
import com.avaje.ebean.config.dbplatform.DbDefaultValue;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncrypt;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
@@ -182,7 +183,7 @@ public class DeployBeanProperty {
|
||||
*/
|
||||
private GeneratedProperty generatedProperty;
|
||||
|
||||
private final DeployBeanDescriptor<?> desc;
|
||||
protected final DeployBeanDescriptor<?> desc;
|
||||
|
||||
private boolean undirectionalShadow;
|
||||
|
||||
@@ -202,6 +203,8 @@ public class DeployBeanProperty {
|
||||
|
||||
private String dbComment;
|
||||
|
||||
private String dbColumnDefault;
|
||||
|
||||
public DeployBeanProperty(DeployBeanDescriptor<?> desc, Class<?> propertyType, ScalarType<?> scalarType, ScalarTypeConverter<?, ?> typeConverter) {
|
||||
this.desc = desc;
|
||||
this.propertyType = propertyType;
|
||||
@@ -902,6 +905,7 @@ public class DeployBeanProperty {
|
||||
public void setSoftDelete() {
|
||||
this.softDelete = true;
|
||||
this.nullable = false;
|
||||
this.dbColumnDefault = DbDefaultValue.FALSE;
|
||||
}
|
||||
|
||||
public boolean isSoftDelete() {
|
||||
@@ -932,4 +936,7 @@ public class DeployBeanProperty {
|
||||
return docMapping.create();
|
||||
}
|
||||
|
||||
public String getDbColumnDefault() {
|
||||
return dbColumnDefault;
|
||||
}
|
||||
}
|
||||
|
||||
+15
-8
@@ -12,43 +12,50 @@ public abstract class DeployBeanPropertyAssoc<T> extends DeployBeanProperty {
|
||||
/**
|
||||
* The type of the joined bean.
|
||||
*/
|
||||
Class<T> targetType;
|
||||
protected Class<T> targetType;
|
||||
|
||||
/**
|
||||
* Persist settings.
|
||||
*/
|
||||
final BeanCascadeInfo cascadeInfo = new BeanCascadeInfo();
|
||||
private final BeanCascadeInfo cascadeInfo = new BeanCascadeInfo();
|
||||
|
||||
/**
|
||||
* The join table information.
|
||||
*/
|
||||
BeanTable beanTable;
|
||||
private BeanTable beanTable;
|
||||
|
||||
/**
|
||||
* Join between the beans.
|
||||
*/
|
||||
final DeployTableJoin tableJoin = new DeployTableJoin();
|
||||
protected final DeployTableJoin tableJoin = new DeployTableJoin();
|
||||
|
||||
/**
|
||||
* Literal added to where clause of lazy loading query.
|
||||
*/
|
||||
String extraWhere;
|
||||
private String extraWhere;
|
||||
|
||||
/**
|
||||
* From the deployment mappedBy attribute.
|
||||
*/
|
||||
String mappedBy;
|
||||
private String mappedBy;
|
||||
|
||||
String docStoreDoc;
|
||||
private String docStoreDoc;
|
||||
|
||||
/**
|
||||
* Construct the property.
|
||||
*/
|
||||
public DeployBeanPropertyAssoc(DeployBeanDescriptor<?> desc, Class<T> targetType) {
|
||||
DeployBeanPropertyAssoc(DeployBeanDescriptor<?> desc, Class<T> targetType) {
|
||||
super(desc, targetType, null, null);
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the target DeployBeanDescriptor for this associated bean property.
|
||||
*/
|
||||
public DeployBeanDescriptor<?> getTargetDeploy() {
|
||||
return desc.getDeploy(targetType).getDescriptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of the target.
|
||||
* <p>
|
||||
|
||||
+74
-54
@@ -5,30 +5,32 @@ package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
*/
|
||||
public class DeployBeanPropertyAssocOne<T> extends DeployBeanPropertyAssoc<T> {
|
||||
|
||||
boolean oneToOne;
|
||||
|
||||
boolean oneToOneExported;
|
||||
private boolean oneToOne;
|
||||
|
||||
DeployBeanEmbedded deployEmbedded;
|
||||
|
||||
/**
|
||||
* Create the property.
|
||||
*/
|
||||
public DeployBeanPropertyAssocOne(DeployBeanDescriptor<?> desc, Class<T> targetType) {
|
||||
super(desc, targetType);
|
||||
}
|
||||
private boolean oneToOneExported;
|
||||
|
||||
/**
|
||||
* Return the deploy information specifically for the deployment
|
||||
* of Embedded beans.
|
||||
*/
|
||||
public DeployBeanEmbedded getDeployEmbedded() {
|
||||
// deployment should be single threaded
|
||||
if (deployEmbedded == null){
|
||||
deployEmbedded = new DeployBeanEmbedded();
|
||||
}
|
||||
return deployEmbedded;
|
||||
}
|
||||
private boolean importedPrimaryKey;
|
||||
|
||||
private DeployBeanEmbedded deployEmbedded;
|
||||
|
||||
/**
|
||||
* Create the property.
|
||||
*/
|
||||
public DeployBeanPropertyAssocOne(DeployBeanDescriptor<?> desc, Class<T> targetType) {
|
||||
super(desc, targetType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the deploy information specifically for the deployment
|
||||
* of Embedded beans.
|
||||
*/
|
||||
public DeployBeanEmbedded getDeployEmbedded() {
|
||||
// deployment should be single threaded
|
||||
if (deployEmbedded == null) {
|
||||
deployEmbedded = new DeployBeanEmbedded();
|
||||
}
|
||||
return deployEmbedded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this has multiple properties (expected for embedded id).
|
||||
@@ -38,42 +40,60 @@ public class DeployBeanPropertyAssocOne<T> extends DeployBeanPropertyAssoc<T> {
|
||||
return getDeployEmbedded().getPropertyColumnMap().size() > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDbColumn() {
|
||||
DeployTableJoinColumn[] columns = tableJoin.columns();
|
||||
if (columns.length == 1){
|
||||
return columns[0].getLocalDbColumn();
|
||||
}
|
||||
return super.getDbColumn();
|
||||
@Override
|
||||
public String getDbColumn() {
|
||||
DeployTableJoinColumn[] columns = tableJoin.columns();
|
||||
if (columns.length == 1) {
|
||||
return columns[0].getLocalDbColumn();
|
||||
}
|
||||
return super.getDbColumn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this a OneToOne property. Otherwise assumed ManyToOne.
|
||||
*/
|
||||
public boolean isOneToOne() {
|
||||
return oneToOne;
|
||||
}
|
||||
/**
|
||||
* Return true if this a OneToOne property. Otherwise assumed ManyToOne.
|
||||
*/
|
||||
public boolean isOneToOne() {
|
||||
return oneToOne;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is a OneToOne.
|
||||
*/
|
||||
public void setOneToOne() {
|
||||
this.oneToOne = true;
|
||||
}
|
||||
/**
|
||||
* Set to true if this is a OneToOne.
|
||||
*/
|
||||
public void setOneToOne() {
|
||||
this.oneToOne = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is the exported side of a OneToOne.
|
||||
*/
|
||||
public boolean isOneToOneExported() {
|
||||
return oneToOneExported;
|
||||
}
|
||||
/**
|
||||
* Return true if this is the exported side of a OneToOne.
|
||||
*/
|
||||
public boolean isOneToOneExported() {
|
||||
return oneToOneExported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is the exported side of a OneToOne. This means
|
||||
* it doesn't 'own' the foreign key column. A OneToMany without the many.
|
||||
*/
|
||||
public void setOneToOneExported() {
|
||||
this.oneToOneExported = true;
|
||||
}
|
||||
/**
|
||||
* Set to true if this is the exported side of a OneToOne. This means
|
||||
* it doesn't 'own' the foreign key column. A OneToMany without the many.
|
||||
*/
|
||||
public void setOneToOneExported() {
|
||||
this.oneToOneExported = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is part of the primary key.
|
||||
*/
|
||||
public boolean isImportedPrimaryKey() {
|
||||
return importedPrimaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is part of the primary key.
|
||||
*/
|
||||
void setImportedPrimaryKey(DeployBeanProperty primaryKey) {
|
||||
this.importedPrimaryKey = true;
|
||||
String dbColumn = primaryKey.getDbColumn();
|
||||
if (dbColumn != null) {
|
||||
// change join db column if matched by property name
|
||||
tableJoin.setLocalColumn(dbColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+33
-7
@@ -1,12 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection.ModifyListenMode;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorMap;
|
||||
@@ -18,6 +11,12 @@ import com.avaje.ebeaninternal.server.deploy.BeanPropertySimpleCollection;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeString;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Helper object to classify BeanProperties into appropriate lists.
|
||||
@@ -68,6 +67,8 @@ public class DeployBeanPropertyLists {
|
||||
public DeployBeanPropertyLists(BeanDescriptorMap owner, BeanDescriptor<?> desc, DeployBeanDescriptor<?> deploy) {
|
||||
this.desc = desc;
|
||||
|
||||
setImportedPrimaryKeys(deploy);
|
||||
|
||||
DeployBeanPropertyAssocOne<?> deployUnidirectional = deploy.getUnidirectional();
|
||||
if (deployUnidirectional == null) {
|
||||
unidirectional = null;
|
||||
@@ -125,6 +126,31 @@ public class DeployBeanPropertyLists {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and set imported primary keys.
|
||||
* <p>
|
||||
* This is where @ManyToOne properties maps to a PFK (Primary and foreign key).
|
||||
* Perform the match by naming convention on property name and db column.
|
||||
* </p>
|
||||
*/
|
||||
private void setImportedPrimaryKeys(DeployBeanDescriptor<?> deploy) {
|
||||
|
||||
List<DeployBeanProperty> ids = deploy.propertiesId();
|
||||
if (ids.size() == 1) {
|
||||
DeployBeanProperty id = ids.get(0);
|
||||
if (id instanceof DeployBeanPropertyAssocOne<?>) {
|
||||
// only interested if the primary key is a compound key
|
||||
DeployBeanDescriptor<?> targetDeploy = ((DeployBeanPropertyAssocOne<?>) id).getTargetDeploy();
|
||||
for (DeployBeanPropertyAssocOne<?> assoc : deploy.propertiesAssocOne()) {
|
||||
DeployBeanProperty pkMatch = targetDeploy.findMatch(assoc.getName(), assoc.getDbColumn());
|
||||
if (pkMatch != null) {
|
||||
assoc.setImportedPrimaryKey(pkMatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unidirectional.
|
||||
*/
|
||||
|
||||
@@ -155,4 +155,13 @@ public class DeployTableJoin {
|
||||
public void setInheritInfo(InheritInfo inheritInfo) {
|
||||
this.inheritInfo = inheritInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the join column (based on imported primary key match on property name etc).
|
||||
*/
|
||||
void setLocalColumn(String dbColumn) {
|
||||
if (columns.size() == 1) {
|
||||
columns.get(0).setLocalDbColumn(dbColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,4 +126,10 @@ public class DeployTableJoinColumn {
|
||||
return localDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the local database column name.
|
||||
*/
|
||||
public void setLocalDbColumn(String localDbColumn) {
|
||||
this.localDbColumn = localDbColumn;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,17 +184,17 @@ public class AnnotationFields extends AnnotationParser {
|
||||
}
|
||||
}
|
||||
|
||||
DocProperty docProperty = get(prop, DocProperty.class);
|
||||
if (docProperty != null) {
|
||||
prop.setDocProperty(docProperty);
|
||||
DocCode docCode = get(prop, DocCode.class);
|
||||
if (docCode != null) {
|
||||
prop.setDocCode(docCode);
|
||||
}
|
||||
DocSortable docSortable = get(prop, DocSortable.class);
|
||||
if (docSortable != null) {
|
||||
prop.setDocSortable(docSortable);
|
||||
}
|
||||
DocCode docCode = get(prop, DocCode.class);
|
||||
if (docCode != null) {
|
||||
prop.setDocCode(docCode);
|
||||
DocProperty docProperty = get(prop, DocProperty.class);
|
||||
if (docProperty != null) {
|
||||
prop.setDocProperty(docProperty);
|
||||
}
|
||||
|
||||
if (get(prop, DbHstore.class) != null) {
|
||||
|
||||
@@ -2,8 +2,6 @@ package com.avaje.ebeaninternal.server.el;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
/**
|
||||
* Comparator based on a ElGetValue.
|
||||
*/
|
||||
@@ -23,16 +21,14 @@ public final class ElComparatorProperty<T> implements Comparator<T>, ElComparato
|
||||
|
||||
public int compare(T o1, T o2) {
|
||||
|
||||
Object val1 = elGetValue.elGetValue((EntityBean) o1);
|
||||
Object val2 = elGetValue.elGetValue((EntityBean) o2);
|
||||
|
||||
Object val1 = elGetValue.pathGet(o1);
|
||||
Object val2 = elGetValue.pathGet(o2);
|
||||
return compareValues(val1, val2);
|
||||
}
|
||||
|
||||
public int compareValue(Object value, T o2) {
|
||||
|
||||
Object val2 = elGetValue.elGetValue((EntityBean) o2);
|
||||
|
||||
Object val2 = elGetValue.pathGet(o2);
|
||||
return compareValues(value, val2);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ public final class ElFilter<T> implements Filter<T> {
|
||||
private Object convertValue(String propertyName, Object value) {
|
||||
// convert type of value to match expected type
|
||||
ElPropertyValue elGetValue = beanDescriptor.getElGetValue(propertyName);
|
||||
return elGetValue.elConvertType(value);
|
||||
return elGetValue.convert(value);
|
||||
}
|
||||
|
||||
private ElComparator<T> getElComparator(String propertyName) {
|
||||
@@ -87,8 +87,8 @@ public final class ElFilter<T> implements Filter<T> {
|
||||
public Filter<T> between(String propertyName, Object min, Object max) {
|
||||
|
||||
ElPropertyValue elGetValue = getElGetValue(propertyName);
|
||||
min = elGetValue.elConvertType(min);
|
||||
max = elGetValue.elConvertType(max);
|
||||
min = elGetValue.convert(min);
|
||||
max = elGetValue.convert(max);
|
||||
|
||||
ElComparator<T> elComparator = getElComparator(propertyName);
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class ElMatchBuilder {
|
||||
}
|
||||
|
||||
public boolean isMatch(T bean) {
|
||||
String v = (String) elGetValue.elGetValue((EntityBean) bean);
|
||||
String v = (String) elGetValue.pathGet(bean);
|
||||
return pattern.matcher(v).matches();
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ class ElMatchBuilder {
|
||||
}
|
||||
|
||||
public boolean isMatch(T bean) {
|
||||
String v = (String) elGetValue.elGetValue((EntityBean) bean);
|
||||
String v = (String) elGetValue.pathGet(bean);
|
||||
return value.equalsIgnoreCase(v);
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ class ElMatchBuilder {
|
||||
|
||||
public boolean isMatch(T bean) {
|
||||
|
||||
String v = (String) elGetValue.elGetValue((EntityBean) bean);
|
||||
String v = (String) elGetValue.pathGet(bean);
|
||||
return charMatch.startsWith(v);
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@ class ElMatchBuilder {
|
||||
|
||||
public boolean isMatch(T bean) {
|
||||
|
||||
String v = (String) elGetValue.elGetValue((EntityBean) bean);
|
||||
String v = (String) elGetValue.pathGet(bean);
|
||||
return charMatch.endsWith(v);
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ class ElMatchBuilder {
|
||||
}
|
||||
|
||||
public boolean isMatch(T bean) {
|
||||
String v = (String) elGetValue.elGetValue((EntityBean) bean);
|
||||
String v = (String) elGetValue.pathGet(bean);
|
||||
return value.startsWith(v);
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,7 @@ class ElMatchBuilder {
|
||||
}
|
||||
|
||||
public boolean isMatch(T bean) {
|
||||
String v = (String) elGetValue.elGetValue((EntityBean) bean);
|
||||
String v = (String) elGetValue.pathGet(bean);
|
||||
return value.endsWith(v);
|
||||
}
|
||||
}
|
||||
@@ -131,7 +131,7 @@ class ElMatchBuilder {
|
||||
}
|
||||
|
||||
public boolean isMatch(T bean) {
|
||||
return (null == elGetValue.elGetValue((EntityBean) bean));
|
||||
return (null == elGetValue.pathGet(bean));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ class ElMatchBuilder {
|
||||
}
|
||||
|
||||
public boolean isMatch(T bean) {
|
||||
return (null != elGetValue.elGetValue((EntityBean) bean));
|
||||
return (null != elGetValue.pathGet(bean));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ class ElMatchBuilder {
|
||||
|
||||
public boolean isMatch(T bean) {
|
||||
|
||||
Object value = elGetValue.elGetValue((EntityBean) bean);
|
||||
Object value = elGetValue.pathGet(bean);
|
||||
return value != null && set.contains(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.el;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.text.StringFormatter;
|
||||
import com.avaje.ebean.text.StringParser;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
@@ -155,14 +154,14 @@ public class ElPropertyChain implements ElPropertyValue {
|
||||
return lastElPropertyValue.isLocalEncrypted();
|
||||
}
|
||||
|
||||
public Object[] getAssocOneIdValues(EntityBean bean) {
|
||||
public Object[] getAssocIdValues(EntityBean bean) {
|
||||
// Don't navigate the object graph as bean
|
||||
// is assumed to be the appropriate type
|
||||
return lastElPropertyValue.getAssocOneIdValues(bean);
|
||||
return lastElPropertyValue.getAssocIdValues(bean);
|
||||
}
|
||||
|
||||
public String getAssocOneIdExpr(String prefix, String operator) {
|
||||
return lastElPropertyValue.getAssocOneIdExpr(expression, operator);
|
||||
public String getAssocIdExpression(String prefix, String operator) {
|
||||
return lastElPropertyValue.getAssocIdExpression(expression, operator);
|
||||
}
|
||||
|
||||
public String getAssocIdInExpr(String prefix) {
|
||||
@@ -173,16 +172,6 @@ public class ElPropertyChain implements ElPropertyValue {
|
||||
return lastElPropertyValue.getAssocIdInValueExpr(size);
|
||||
}
|
||||
|
||||
public int getDeployOrder() {
|
||||
int i = lastBeanProperty.getDeployOrder();
|
||||
int max = chain.length - 1;
|
||||
for (int j = 0; j < max; j++) {
|
||||
int xtra = ((max - j) * 1000) * chain[j].getDeployOrder();
|
||||
i += xtra;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public boolean isAssocId() {
|
||||
return assocId;
|
||||
}
|
||||
@@ -221,64 +210,49 @@ public class ElPropertyChain implements ElPropertyValue {
|
||||
return scalarType;
|
||||
}
|
||||
|
||||
public Object elConvertType(Object value) {
|
||||
public Object convert(Object value) {
|
||||
// just convert using the last one in the chain
|
||||
return lastElPropertyValue.elConvertType(value);
|
||||
return lastElPropertyValue.convert(value);
|
||||
}
|
||||
|
||||
public Object elGetValue(EntityBean bean) {
|
||||
|
||||
@Override
|
||||
public Object pathGet(Object bean) {
|
||||
for (int i = 0; i < chain.length; i++) {
|
||||
bean = (EntityBean) chain[i].elGetValue(bean);
|
||||
bean = chain[i].pathGet(bean);
|
||||
if (bean == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object elGetReference(EntityBean bean) {
|
||||
@Override
|
||||
public Object pathGetNested(Object bean) {
|
||||
|
||||
EntityBean prevBean = bean;
|
||||
Object prevBean = bean;
|
||||
for (int i = 0; i < last; i++) {
|
||||
// always return non null prevBean
|
||||
prevBean = (EntityBean) chain[i].elGetReference(prevBean);
|
||||
prevBean = chain[i].pathGetNested(prevBean);
|
||||
}
|
||||
// try the last step in the chain
|
||||
return chain[last].elGetValue(prevBean);
|
||||
return chain[last].pathGet(prevBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object bean, Object value) {
|
||||
elSetValue((EntityBean)bean, value, true);
|
||||
}
|
||||
public void pathSet(Object bean, Object value) {
|
||||
|
||||
public void elSetValue(EntityBean bean, Object value, boolean populate) {
|
||||
|
||||
EntityBean prevBean = bean;
|
||||
if (populate) {
|
||||
for (int i = 0; i < last; i++) {
|
||||
// always return non null prevBean
|
||||
prevBean = (EntityBean) chain[i].elGetReference(prevBean);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < last; i++) {
|
||||
// always return non null prevBean
|
||||
prevBean = (EntityBean) chain[i].elGetValue(prevBean);
|
||||
if (prevBean == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Object prevBean = bean;
|
||||
for (int i = 0; i < last; i++) {
|
||||
prevBean = chain[i].pathGetNested(prevBean);
|
||||
}
|
||||
if (prevBean != null) {
|
||||
if (lastBeanProperty != null) {
|
||||
// last chain element maps to a real scalar property
|
||||
lastBeanProperty.setValueIntercept(prevBean, value);
|
||||
lastBeanProperty.pathSet(prevBean, value);
|
||||
|
||||
} else {
|
||||
// a non-scalar property of a Compound value object
|
||||
lastElPropertyValue.elSetValue(prevBean, value, populate);
|
||||
lastElPropertyValue.pathSet(prevBean, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user