mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
162
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9237cb8a8 | ||
|
|
99e548db03 | ||
|
|
71499d15e1 | ||
|
|
c9b0fd708a | ||
|
|
8e43ece490 | ||
|
|
fb2b8b4cf6 | ||
|
|
33f3920a60 | ||
|
|
9a912390d4 | ||
|
|
30a5769973 | ||
|
|
084c9ad433 | ||
|
|
737022bc57 | ||
|
|
de6ba31996 | ||
|
|
df95f4759b | ||
|
|
32f4a56ab4 | ||
|
|
04965892f0 | ||
|
|
fdb2965d6e | ||
|
|
ab2789dd08 | ||
|
|
8f80280105 | ||
|
|
1179f84611 | ||
|
|
8593d3e496 | ||
|
|
c658b8c80c | ||
|
|
44e3c6b9a8 | ||
|
|
c296127bab | ||
|
|
83d0d6320c | ||
|
|
6ce4ca4a5b | ||
|
|
21c97e786d | ||
|
|
2a1c394093 | ||
|
|
f55b348a55 | ||
|
|
84b2ffa971 | ||
|
|
406b7304ad | ||
|
|
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 | ||
|
|
ec38137e5c | ||
|
|
bfcbd335c8 | ||
|
|
2cafdf709d | ||
|
|
ed2ea13deb | ||
|
|
8d3b4a0407 | ||
|
|
cb1fe297d6 | ||
|
|
6561c118ec | ||
|
|
eda7fe24c1 | ||
|
|
2353049c6f | ||
|
|
6c49ac0857 | ||
|
|
76033385dc | ||
|
|
b61cd30e29 | ||
|
|
18edaf877b | ||
|
|
f055a0d0cb | ||
|
|
a22574b0c9 | ||
|
|
3130f751f5 | ||
|
|
c83606c1da | ||
|
|
439858b259 | ||
|
|
3d3948aa8b | ||
|
|
27045baf44 | ||
|
|
5c6d6608ef | ||
|
|
2fcaab44c6 | ||
|
|
69bf1758bc | ||
|
|
af554410fd | ||
|
|
ae7827c483 | ||
|
|
4df2d4020e | ||
|
|
1aeffd31e0 | ||
|
|
5c59066ff8 | ||
|
|
a2bf8a0e46 | ||
|
|
3ef77ea410 | ||
|
|
fe2c2e5331 | ||
|
|
3d91a4f927 | ||
|
|
165d4aca92 | ||
|
|
076f8a03b9 | ||
|
|
ca944eb756 | ||
|
|
769e4bb488 | ||
|
|
0d456b2ad6 | ||
|
|
39e913cbe2 | ||
|
|
ae38672e02 | ||
|
|
8a8b36ec1e | ||
|
|
62aca1e77b | ||
|
|
f0b80068b6 | ||
|
|
5721fe3807 | ||
|
|
afffb88a29 | ||
|
|
4c3a125192 | ||
|
|
f8804f8d18 | ||
|
|
4848c24a0a | ||
|
|
4c3d1d9edd | ||
|
|
42b112c3d7 | ||
|
|
59996da07a |
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>6.17.1</version>
|
||||
<version>7.5.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
@@ -55,10 +55,29 @@
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-datasource-api</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-datasource</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- bring in cluster support by default -->
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-cluster</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.7</version>
|
||||
<version>[1.7.1,1.7.99)</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope for Spring boot loader classpath scanning support -->
|
||||
@@ -73,7 +92,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.5.3</version>
|
||||
<version>2.6.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -81,7 +100,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.5.3</version>
|
||||
<version>2.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -135,13 +154,6 @@
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>2.1.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-agentloader</artifactId>
|
||||
@@ -152,7 +164,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 +180,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 +231,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>
|
||||
@@ -273,7 +285,7 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<doctitle>Ebean 6</doctitle>
|
||||
<doctitle>Ebean 7</doctitle>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
@@ -292,7 +304,6 @@
|
||||
</additionalparam>
|
||||
<linksource>true</linksource>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
|
||||
</configuration>
|
||||
|
||||
<executions>
|
||||
|
||||
@@ -71,7 +71,7 @@ class DRawSqlParser {
|
||||
|
||||
preFrom = trimSelectKeyword(preFrom);
|
||||
|
||||
return new Sql(sql.hashCode(), preFrom, preWhere, whereExprAnd, preHaving, havingExprAnd, orderByPrefix, orderBySql, (distinctPos > -1));
|
||||
return new Sql(sql, preFrom, preWhere, whereExprAnd, preHaving, havingExprAnd, orderByPrefix, orderBySql, (distinctPos > -1));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Bean holding the details to update the document store.
|
||||
*/
|
||||
public final class DocStoreQueueEntry {
|
||||
|
||||
/**
|
||||
* Action to either update or delete a document from the index.
|
||||
*/
|
||||
public enum Action {
|
||||
|
||||
/**
|
||||
* Action is to update a document in the doc store.
|
||||
*/
|
||||
INDEX(1),
|
||||
|
||||
/**
|
||||
* Action is to delete a document from the doc store..
|
||||
*/
|
||||
DELETE(2),
|
||||
|
||||
/**
|
||||
* An update is required based on a change to a nested/embedded object at a given path.
|
||||
*/
|
||||
NESTED(3);
|
||||
|
||||
int value;
|
||||
|
||||
Action(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value associated with this action type.
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
final Action type;
|
||||
|
||||
final String queueId;
|
||||
|
||||
final String path;
|
||||
|
||||
final Object beanId;
|
||||
|
||||
/**
|
||||
* Construct for an INDEX or DELETE action.
|
||||
*/
|
||||
public DocStoreQueueEntry(Action type, String queueId, Object beanId) {
|
||||
this(type, queueId, null, beanId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for an NESTED/embedded path invalidation action.
|
||||
*/
|
||||
public DocStoreQueueEntry(Action type, String queueId, String path, Object beanId) {
|
||||
this.type = type;
|
||||
this.queueId = queueId;
|
||||
this.path = path;
|
||||
this.beanId = beanId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the event type.
|
||||
*/
|
||||
public Action getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associate queueId.
|
||||
*/
|
||||
public String getQueueId() {
|
||||
return queueId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path if this is a nested update.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean id (which matches the document id).
|
||||
*/
|
||||
public Object getBeanId() {
|
||||
return beanId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebeanservice.docstore.api.DocQueryRequest;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Document storage operations.
|
||||
*/
|
||||
public interface DocumentStore {
|
||||
|
||||
/**
|
||||
* Update the associated document store using the result of the query.
|
||||
* <p>
|
||||
* This will execute the query against the database creating a document for each
|
||||
* bean graph and sending this to the document store.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that the select and fetch paths of the query is set for you to match the
|
||||
* document structure needed based on <code>@DocStore</code> and <code>@DocStoreEmbedded</code>
|
||||
* so what this query requires is the predicates only.
|
||||
* </p>
|
||||
* <p>
|
||||
* This query will be executed using findEach so it is safe to use a query
|
||||
* that will fetch a lot of beans. The default bulkBatchSize is used.
|
||||
* </p>
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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 find(DocQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* 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(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(DocQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* 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>
|
||||
* 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(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.
|
||||
*/
|
||||
long process(List<DocStoreQueueEntry> queueEntries) throws IOException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
void createIndex(String indexName, String alias);
|
||||
|
||||
/**
|
||||
* Copy the index to a new index.
|
||||
* <p>
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Copy entries from an index to a new index but limiting to documents that have been
|
||||
* modified since the sinceEpochMillis time.
|
||||
* <p>
|
||||
* 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);
|
||||
}
|
||||
@@ -1886,11 +1886,16 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see com.avaje.ebean.text.PathProperties
|
||||
* @see Query#apply(com.avaje.ebean.text.PathProperties)
|
||||
* @see FetchPath
|
||||
* @see Query#apply(FetchPath)
|
||||
*/
|
||||
JsonContext json();
|
||||
|
||||
/**
|
||||
* Return the Document store.
|
||||
*/
|
||||
DocumentStore docStore();
|
||||
|
||||
/**
|
||||
* Publish a single bean given its type and id returning the resulting live bean.
|
||||
* <p>
|
||||
|
||||
@@ -133,7 +133,7 @@ public class EbeanServerFactory {
|
||||
/**
|
||||
* Create the container instance using the configuration.
|
||||
*/
|
||||
private static SpiContainer createContainer(ContainerConfig containerConfig) {
|
||||
protected static SpiContainer createContainer(ContainerConfig containerConfig) {
|
||||
|
||||
String implClassName = System.getProperty("ebean.container", DEFAULT_CONTAINER);
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -245,6 +251,11 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression idEq(Object value);
|
||||
|
||||
/**
|
||||
* Id IN a list of Id values.
|
||||
*/
|
||||
Expression idIn(Object... idValues);
|
||||
|
||||
/**
|
||||
* Id IN a list of Id values.
|
||||
*/
|
||||
@@ -285,6 +296,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 +355,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,10 +1,13 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
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;
|
||||
@@ -31,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.
|
||||
@@ -95,7 +98,7 @@ public interface ExpressionList<T> extends Serializable {
|
||||
/**
|
||||
* Apply the path properties to the query replacing the select and fetch clauses.
|
||||
*/
|
||||
Query<T> apply(PathProperties pathProperties);
|
||||
Query<T> apply(FetchPath fetchPath);
|
||||
|
||||
/**
|
||||
* Perform an 'As of' query using history tables to return the object graph
|
||||
@@ -113,10 +116,16 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
Query<T> asDraft();
|
||||
|
||||
/**
|
||||
* Deprecated in favour of setIncludeSoftDeletes().
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> includeSoftDeletes();
|
||||
|
||||
/**
|
||||
* Execute the query including soft deleted rows.
|
||||
*/
|
||||
Query<T> includeSoftDeletes();
|
||||
Query<T> setIncludeSoftDeletes();
|
||||
|
||||
/**
|
||||
* Execute as a delete query deleting the 'root level' beans that match the predicates
|
||||
@@ -381,6 +390,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>
|
||||
@@ -729,6 +764,11 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
ExpressionList<T> notExists(Query<?> subQuery);
|
||||
|
||||
/**
|
||||
* Id IN a list of id values.
|
||||
*/
|
||||
ExpressionList<T> idIn(Object... idValues);
|
||||
|
||||
/**
|
||||
* Id IN a list of id values.
|
||||
*/
|
||||
@@ -803,6 +843,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.
|
||||
*/
|
||||
@@ -819,20 +900,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();
|
||||
|
||||
@@ -249,4 +249,22 @@ public class FetchConfig implements Serializable {
|
||||
return queryAll;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
FetchConfig that = (FetchConfig) o;
|
||||
if (lazyBatchSize != that.lazyBatchSize) return false;
|
||||
if (queryBatchSize != that.queryBatchSize) return false;
|
||||
return queryAll == that.queryAll;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = lazyBatchSize;
|
||||
result = 92821 * result + queryBatchSize;
|
||||
result = 92821 * result + (queryAll ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides paths and properties for an object graph that can be used to control what parts of the object graph
|
||||
* is fetching (select and fetch clauses) and also can be used to control JSON marshalling (what parts of the object
|
||||
* graph are included in the JSON).
|
||||
*/
|
||||
public interface FetchPath {
|
||||
|
||||
/**
|
||||
* Return true if the path is included in this FetchPath.
|
||||
*/
|
||||
boolean hasPath(String path);
|
||||
|
||||
/**
|
||||
* Return the properties at the given path.
|
||||
*/
|
||||
Set<String> getProperties(String path);
|
||||
|
||||
/**
|
||||
* Apply the fetch path to the query.
|
||||
*/
|
||||
<T> void apply(Query<T> query);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
import com.avaje.ebean.util.ClassUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -271,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.
|
||||
*/
|
||||
@@ -588,10 +600,10 @@ public abstract class Model {
|
||||
/**
|
||||
* Creates a query applying the path properties to set the select and fetch clauses.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#apply(com.avaje.ebean.text.PathProperties)}
|
||||
* Equivalent to {@link Query#apply(FetchPath)}
|
||||
*/
|
||||
public Query<T> apply(PathProperties pathProperties) {
|
||||
return db().find(type).apply(pathProperties);
|
||||
public Query<T> apply(FetchPath fetchPath) {
|
||||
return db().find(type).apply(fetchPath);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
/**
|
||||
* Captures and wraps IOException's occurring during ElasticSearch processing etc.
|
||||
*/
|
||||
public class PersistenceIOException extends PersistenceException {
|
||||
|
||||
public PersistenceIOException(String msg, Exception cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
public PersistenceIOException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
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;
|
||||
@@ -275,7 +273,7 @@ import java.util.Set;
|
||||
* @param <T>
|
||||
* the type of Entity bean this query will fetch.
|
||||
*/
|
||||
public interface Query<T> extends Serializable {
|
||||
public interface Query<T> {
|
||||
|
||||
/**
|
||||
* Return the RawSql that was set to use for this query.
|
||||
@@ -304,8 +302,9 @@ public interface Query<T> extends Serializable {
|
||||
Query<T> asDraft();
|
||||
|
||||
/**
|
||||
* Execute the query including soft deleted rows.
|
||||
* Deprecated in favour of setIncludeSoftDeletes().
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> includeSoftDeletes();
|
||||
|
||||
/**
|
||||
@@ -377,6 +376,11 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
Query<T> setLazyLoadBatchSize(int lazyLoadBatchSize);
|
||||
|
||||
/**
|
||||
* Execute the query including soft deleted rows.
|
||||
*/
|
||||
Query<T> setIncludeSoftDeletes();
|
||||
|
||||
/**
|
||||
* Disable read auditing for this query.
|
||||
* <p>
|
||||
@@ -522,10 +526,10 @@ public interface Query<T> extends Serializable {
|
||||
/**
|
||||
* Apply the path properties replacing the select and fetch clauses.
|
||||
* <p>
|
||||
* This is typically used when the PathProperties is applied to both the query and the JSON output.
|
||||
* This is typically used when the FetchPath is applied to both the query and the JSON output.
|
||||
* </p>
|
||||
*/
|
||||
Query<T> apply(PathProperties pathProperties);
|
||||
Query<T> apply(FetchPath fetchPath);
|
||||
|
||||
/**
|
||||
* Execute the query returning the list of Id's.
|
||||
@@ -1043,6 +1047,27 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
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.
|
||||
@@ -1286,6 +1311,14 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
Query<T> setUseQueryCache(boolean useQueryCache);
|
||||
|
||||
/**
|
||||
* 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 useDocStore);
|
||||
|
||||
/**
|
||||
* When set to true when you want the returned beans to be read only.
|
||||
*/
|
||||
@@ -1365,4 +1398,5 @@ public interface Query<T> extends Serializable {
|
||||
* </p>
|
||||
*/
|
||||
Set<String> validate();
|
||||
|
||||
}
|
||||
|
||||
@@ -206,6 +206,14 @@ public final class RawSql implements Serializable {
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the key;
|
||||
*/
|
||||
public Key getKey() {
|
||||
boolean parsed = sql != null && sql.parsed;
|
||||
String unParsedSql = (sql == null) ? "" : sql.unparsedSql;
|
||||
return new Key(parsed, unParsedSql, columnMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resultSet if this is a ResultSet based RawSql.
|
||||
@@ -221,16 +229,6 @@ public final class RawSql implements Serializable {
|
||||
return columnMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash for this query.
|
||||
*/
|
||||
public int queryHash() {
|
||||
if (resultSet != null) {
|
||||
return 31 * columnMapping.queryHash();
|
||||
}
|
||||
return 31 * sql.queryHash() + columnMapping.queryHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the sql part of the query. For parsed RawSql the sql is broken
|
||||
* up so that Ebean can insert extra WHERE and HAVING expressions into the
|
||||
@@ -260,13 +258,10 @@ public final class RawSql implements Serializable {
|
||||
|
||||
private final boolean distinct;
|
||||
|
||||
private final int queryHashCode;
|
||||
|
||||
/**
|
||||
* Construct for unparsed SQL.
|
||||
*/
|
||||
protected Sql(String unparsedSql) {
|
||||
this.queryHashCode = unparsedSql.hashCode();
|
||||
this.parsed = false;
|
||||
this.unparsedSql = unparsedSql;
|
||||
this.preFrom = null;
|
||||
@@ -282,12 +277,11 @@ public final class RawSql implements Serializable {
|
||||
/**
|
||||
* Construct for parsed SQL.
|
||||
*/
|
||||
protected Sql(int queryHashCode, String preFrom, String preWhere, boolean andWhereExpr,
|
||||
protected Sql(String unparsedSql, String preFrom, String preWhere, boolean andWhereExpr,
|
||||
String preHaving, boolean andHavingExpr, String orderByPrefix, String orderBy, boolean distinct) {
|
||||
|
||||
this.queryHashCode = queryHashCode;
|
||||
this.unparsedSql = unparsedSql;
|
||||
this.parsed = true;
|
||||
this.unparsedSql = null;
|
||||
this.preFrom = preFrom;
|
||||
this.preHaving = preHaving;
|
||||
this.preWhere = preWhere;
|
||||
@@ -298,13 +292,6 @@ public final class RawSql implements Serializable {
|
||||
this.distinct = distinct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash for this query.
|
||||
*/
|
||||
public int queryHash() {
|
||||
return queryHashCode;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (!parsed) {
|
||||
return "unparsed[" + unparsedSql + "]";
|
||||
@@ -406,13 +393,10 @@ public final class RawSql implements Serializable {
|
||||
|
||||
private final boolean immutable;
|
||||
|
||||
private final int queryHashCode;
|
||||
|
||||
/**
|
||||
* Construct from parsed sql where the columns have been identified.
|
||||
*/
|
||||
protected ColumnMapping(List<Column> columns) {
|
||||
this.queryHashCode = 0;
|
||||
this.immutable = false;
|
||||
this.parsed = true;
|
||||
this.propertyMap = null;
|
||||
@@ -428,7 +412,6 @@ public final class RawSql implements Serializable {
|
||||
* Construct for unparsed sql.
|
||||
*/
|
||||
protected ColumnMapping() {
|
||||
this.queryHashCode = 0;
|
||||
this.immutable = false;
|
||||
this.parsed = false;
|
||||
this.propertyMap = null;
|
||||
@@ -443,17 +426,13 @@ public final class RawSql implements Serializable {
|
||||
this.immutable = false;
|
||||
this.parsed = false;
|
||||
this.propertyMap = null;
|
||||
//this.propertyColumnMap = null;
|
||||
this.dbColumnMap = new LinkedHashMap<String, Column>();
|
||||
|
||||
int hc = 31;
|
||||
|
||||
int pos = 0;
|
||||
for (String prop : propertyNames) {
|
||||
hc = 31 * hc + prop.hashCode();
|
||||
dbColumnMap.put(prop, new Column(pos++, prop, null, prop));
|
||||
}
|
||||
propertyColumnMap = dbColumnMap;
|
||||
this.queryHashCode = hc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -464,20 +443,28 @@ public final class RawSql implements Serializable {
|
||||
this.parsed = parsed;
|
||||
this.dbColumnMap = dbColumnMap;
|
||||
|
||||
int hc = ColumnMapping.class.getName().hashCode();
|
||||
|
||||
HashMap<String, Column> pcMap = new HashMap<String, Column>();
|
||||
HashMap<String, String> pMap = new HashMap<String, String>();
|
||||
|
||||
for (Column c : dbColumnMap.values()) {
|
||||
pMap.put(c.getPropertyName(), c.getDbColumn());
|
||||
pcMap.put(c.getPropertyName(), c);
|
||||
hc = 31 * hc + ((c.getPropertyName() == null) ? 0 : c.getPropertyName().hashCode());
|
||||
hc = 31 * hc + ((c.getDbColumn() == null) ? 0 : c.getDbColumn().hashCode());
|
||||
}
|
||||
this.propertyMap = Collections.unmodifiableMap(pMap);
|
||||
this.propertyColumnMap = Collections.unmodifiableMap(pcMap);
|
||||
this.queryHashCode = hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ColumnMapping that = (ColumnMapping) o;
|
||||
return dbColumnMap.equals(that.dbColumnMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return dbColumnMap.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -521,16 +508,6 @@ public final class RawSql implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query hash for this column mapping.
|
||||
*/
|
||||
public int queryHash() {
|
||||
if (queryHashCode == 0) {
|
||||
throw new RuntimeException("Bug: queryHashCode == 0");
|
||||
}
|
||||
return queryHashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the Columns where supplied by parsing the sql select
|
||||
* clause.
|
||||
@@ -648,6 +625,27 @@ public final class RawSql implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Column that = (Column) o;
|
||||
if (indexPos != that.indexPos) return false;
|
||||
if (!dbColumn.equals(that.dbColumn)) return false;
|
||||
if (dbAlias != null ? !dbAlias.equals(that.dbAlias) : that.dbAlias != null) return false;
|
||||
return propertyName != null ? propertyName.equals(that.propertyName) : that.propertyName == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = indexPos;
|
||||
result = 31 * result + dbColumn.hashCode();
|
||||
result = 31 * result + (dbAlias != null ? dbAlias.hashCode() : 0);
|
||||
result = 31 * result + (propertyName != null ? propertyName.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return dbColumn + "->" + propertyName;
|
||||
}
|
||||
@@ -699,4 +697,39 @@ public final class RawSql implements Serializable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A key for the RawSql object using for the query plan.
|
||||
*/
|
||||
public static final class Key {
|
||||
|
||||
private final boolean parsed;
|
||||
private final ColumnMapping columnMapping;
|
||||
private final String unParsedSql;
|
||||
|
||||
Key(boolean parsed, String unParsedSql, ColumnMapping columnMapping) {
|
||||
this.parsed = parsed;
|
||||
this.unParsedSql = unParsedSql;
|
||||
this.columnMapping = columnMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Key that = (Key) o;
|
||||
return parsed == that.parsed
|
||||
&& columnMapping.equals(that.columnMapping)
|
||||
&& unParsedSql.equals(that.unParsedSql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (parsed ? 1 : 0);
|
||||
result = 31 * result + columnMapping.hashCode();
|
||||
result = 31 * result + unParsedSql.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
import com.avaje.ebean.config.DocStoreConfig;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
@@ -81,6 +83,29 @@ public interface Transaction extends Closeable {
|
||||
*/
|
||||
boolean isActive();
|
||||
|
||||
/**
|
||||
* Set the behavior for document store updates on this transaction.
|
||||
* <p>
|
||||
* For example, set the mode to DocStoreEvent.IGNORE for this transaction and
|
||||
* then any changes via this transaction are not sent to the doc store. This
|
||||
* would be used when doing large bulk inserts into the database and we want
|
||||
* to control how that is sent to the document store.
|
||||
* </p>
|
||||
*/
|
||||
void setDocStoreMode(DocStoreMode mode);
|
||||
|
||||
/**
|
||||
* Set the batch size to use for sending messages to the document store.
|
||||
* <p>
|
||||
* You might set this if you know the changes in this transaction result in especially large or
|
||||
* especially small payloads and want to adjust the batch size to match.
|
||||
* </p>
|
||||
* <p>
|
||||
* Setting this overrides the default of {@link DocStoreConfig#getBulkBatchSize()}
|
||||
* </p>
|
||||
*/
|
||||
void setDocStoreBatchSize(int batchSize);
|
||||
|
||||
/**
|
||||
* Explicitly turn off or on the cascading nature of save() and delete(). This
|
||||
* gives the developer exact control over what beans are saved and deleted
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used to indicate that a particular string property should be treated as a 'code' and not analysed for text searching.
|
||||
* <p>
|
||||
* By default all Id properties and all Enum properties are treated as 'code' and not analysed.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocCode {
|
||||
|
||||
/**
|
||||
* 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 "";
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the property is included in the parent document store index.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
*
|
||||
* @DocStore
|
||||
* @Entity @Table(name = "o_order")
|
||||
* public class Order {
|
||||
*
|
||||
* ...
|
||||
* // include some customer details including
|
||||
* // nested billingAddress
|
||||
* @DocEmbedded(doc = "id,status,name,billingAddress(*,country(*)")
|
||||
* @ManyToOne
|
||||
* Customer customer;
|
||||
*
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocEmbedded {
|
||||
|
||||
/**
|
||||
* The properties on the embedded bean to include in the index.
|
||||
*/
|
||||
String doc() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the entity type maps to a document store (like ElasticSearch).
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocMapping {
|
||||
|
||||
/**
|
||||
* The property name the mapping applies to.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Mapping options.
|
||||
*/
|
||||
DocProperty options();
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the entity type maps to a document store (like ElasticSearch).
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocProperty {
|
||||
|
||||
/**
|
||||
* Set this to true to indicate that this property should be un-analysed.
|
||||
*/
|
||||
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 "";
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used to indicate that a particular string property should support sorting. What this typically means is that
|
||||
* for ElasticSearch an additional 'raw' field is added that stores the un-analysed value. This un-analysed value
|
||||
* can be used for sorting etc and the original field used for text searching.
|
||||
* <p>
|
||||
* For example, customer name and product name are good candidates for marking with @DocSortable.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocSortable {
|
||||
|
||||
/**
|
||||
* 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 "";
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the entity type maps to a document store (like ElasticSearch).
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocStore {
|
||||
|
||||
/**
|
||||
* A unique Id used when queuing reindex events.
|
||||
*/
|
||||
String queueId() default "";
|
||||
|
||||
/**
|
||||
* The ElasticSearch index name. If left unspecified the short name of the bean type is used.
|
||||
*/
|
||||
String indexName() default "";
|
||||
|
||||
/**
|
||||
* The ElasticSearch index type. If left unspecified the short name of the bean type is used.
|
||||
*/
|
||||
String indexType() default "";
|
||||
|
||||
/**
|
||||
* The number of shards this index should use.
|
||||
*/
|
||||
int shards() default 0;
|
||||
|
||||
/**
|
||||
* The number of replicas this index should use.
|
||||
*/
|
||||
int replicas() default 0;
|
||||
|
||||
/**
|
||||
* Additional mapping that can be defined on the properties.
|
||||
*/
|
||||
DocMapping[] mapping() default {};
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Insert, Update, Delete events occur.
|
||||
*/
|
||||
DocStoreMode persist() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Insert occurs.
|
||||
*/
|
||||
DocStoreMode insert() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Update occurs.
|
||||
*/
|
||||
DocStoreMode update() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Delete occurs.
|
||||
*/
|
||||
DocStoreMode delete() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify to include only some properties in the doc store document.
|
||||
* <p>
|
||||
* If this is left as default then all scalar properties are included,
|
||||
* all @ManyToOne properties are included with just the nested id property
|
||||
* and no @OneToMany properties are included.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that typically DocStoreEmbedded is used on @ManyToOne and @OneToMany
|
||||
* properties to indicate what part of the nested document should be included.
|
||||
* </p>
|
||||
*
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // only include the customer id and name
|
||||
* @DocStore(doc = "id,name")
|
||||
* @Entity @Table(name = "o_order")
|
||||
* public class Customer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
String doc() default "";
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Deprecated in favor of @DocEmbedded (i.e. renamed to @DocEmbedded)
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Deprecated
|
||||
public @interface DocStoreEmbedded {
|
||||
|
||||
/**
|
||||
* The properties on the embedded bean to include in the index.
|
||||
*/
|
||||
String doc() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
/**
|
||||
* Defines the behavior options when a Insert, Update or Delete event occurs
|
||||
* on a bean with an associated ElasticSearch index.
|
||||
* <p>
|
||||
* For some indexes or some transactions it can be beneficial to queue the event
|
||||
* for later processing rather than look to update ElasticSearch at that time.
|
||||
* </p>
|
||||
*/
|
||||
public enum DocStoreMode {
|
||||
|
||||
/**
|
||||
* Add the event to the queue for processing later (delaying the update to the document store).
|
||||
*/
|
||||
QUEUE,
|
||||
|
||||
/**
|
||||
* Update the document store when transaction succeeds.
|
||||
*/
|
||||
UPDATE,
|
||||
|
||||
/**
|
||||
* Ignore the event and not update the document store.
|
||||
* <p>
|
||||
* This can be used on a index or for a transaction where you want to have more
|
||||
* manual programmatic control over the updating of the document store. Say you want to
|
||||
* IGNORE on a particular transaction and instead manually queue a bulk update.
|
||||
* </p>
|
||||
*/
|
||||
IGNORE,
|
||||
|
||||
/**
|
||||
* The actual mode of QUEUE, UPDATE or IGNORE is set from the default configuration.
|
||||
*/
|
||||
DEFAULT
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -125,6 +130,11 @@ public interface BeanCollection<E> extends Serializable {
|
||||
*/
|
||||
void internalAdd(Object bean);
|
||||
|
||||
/**
|
||||
* Add the bean with a check to see if it is already contained.
|
||||
*/
|
||||
void internalAddWithCheck(Object bean);
|
||||
|
||||
/**
|
||||
* Return the number of elements in the List Set or Map.
|
||||
*/
|
||||
|
||||
@@ -219,6 +219,18 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
this.fullyLoadedBean = fullyLoadedBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check each property to see if the bean is partially loaded.
|
||||
*/
|
||||
public boolean isPartial() {
|
||||
for (int i = 0; i < loadedProps.length; i++) {
|
||||
if (!loadedProps[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this bean has been directly modified (it has oldValues) or
|
||||
* if any embedded beans are either new or dirty (and hence need saving).
|
||||
@@ -469,7 +481,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public void setLoadedProperty(int propertyIndex) {
|
||||
loadedProps[propertyIndex] = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the property is loaded.
|
||||
*/
|
||||
@@ -560,6 +572,23 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the array of flags indicating the dirty properties.
|
||||
*/
|
||||
public boolean[] getDirtyProperties() {
|
||||
int len = getPropertyLength();
|
||||
boolean[] dirties = new boolean[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (changedProps != null && changedProps[i]) {
|
||||
dirties[i] = true;
|
||||
} else if (embeddedDirty != null && embeddedDirty[i]) {
|
||||
// an embedded property has been changed - recurse
|
||||
dirties[i] = true;
|
||||
}
|
||||
}
|
||||
return dirties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of dirty properties.
|
||||
*/
|
||||
|
||||
@@ -10,31 +10,31 @@ package com.avaje.ebean.bean;
|
||||
public interface PersistenceContext {
|
||||
|
||||
/**
|
||||
* Put the entity bean into the PersistanceContext.
|
||||
* 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 PersistanceContext if one is not already
|
||||
* Put the entity bean into the PersistenceContext if one is not already
|
||||
* present (for this id).
|
||||
* <p>
|
||||
* Returns an existing entity bean (if one is already there) and otherwise
|
||||
* 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,10 @@
|
||||
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;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -8,17 +13,13 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
/**
|
||||
* List capable of lazy loading.
|
||||
*/
|
||||
public final class BeanList<E> extends AbstractBeanCollection<E> implements List<E>, BeanCollectionAdd {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
/**
|
||||
* The underlying List implementation.
|
||||
*/
|
||||
@@ -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) {
|
||||
@@ -74,6 +84,13 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void internalAddWithCheck(Object bean) {
|
||||
if (list == null || !list.contains(bean)) {
|
||||
internalAdd(bean);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkEmptyLazyLoad() {
|
||||
if (list == null) {
|
||||
list = new ArrayList<E>();
|
||||
@@ -99,11 +116,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (list == null) {
|
||||
@@ -134,7 +151,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
public Collection<E> getActualDetails() {
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<?> getActualEntries() {
|
||||
return list;
|
||||
|
||||
@@ -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>();
|
||||
@@ -66,7 +75,18 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
map.put((K) key, (E) bean);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void internalPutWithCheck(Object key, Object bean) {
|
||||
if (map == null || !map.containsKey(key)) {
|
||||
internalPut(key, bean);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void internalAddWithCheck(Object bean) {
|
||||
throw new RuntimeException("Not allowed for map");
|
||||
}
|
||||
|
||||
public void internalAdd(Object bean) {
|
||||
throw new RuntimeException("Not allowed for map");
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
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;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
/**
|
||||
* Set capable of lazy loading.
|
||||
*/
|
||||
@@ -57,6 +58,22 @@ 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)) {
|
||||
internalAdd(bean);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalAdd(Object bean) {
|
||||
if (set == null) {
|
||||
@@ -107,11 +124,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (set == null) {
|
||||
|
||||
@@ -90,6 +90,13 @@ public class ClassLoadConfig {
|
||||
return context.forName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the classLoader to use for service loading etc.
|
||||
*/
|
||||
public ClassLoader getClassLoader() {
|
||||
return context.getClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the preferred, caller and context class loaders.
|
||||
*/
|
||||
@@ -138,6 +145,9 @@ public class ClassLoadConfig {
|
||||
return Class.forName(name, true, classLoader);
|
||||
}
|
||||
|
||||
ClassLoader getClassLoader() {
|
||||
return preferredLoader != null ? preferredLoader : contextLoader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
@@ -12,453 +10,51 @@ import java.util.Properties;
|
||||
*/
|
||||
public class ContainerConfig {
|
||||
|
||||
protected boolean clusterActive;
|
||||
|
||||
protected Properties properties;
|
||||
|
||||
/**
|
||||
* Communication mode used for clustering.
|
||||
* Return true if clustering is active.
|
||||
*/
|
||||
public enum ClusterMode {
|
||||
|
||||
/**
|
||||
* No clustering.
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* Use Multicast networking for cluster wide communication.
|
||||
*/
|
||||
MULTICAST,
|
||||
|
||||
/**
|
||||
* Use TCP Sockets for cluster wide communication.
|
||||
*/
|
||||
SOCKET
|
||||
public boolean isClusterActive() {
|
||||
return clusterActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cluster mode to use.
|
||||
* Set to true for clustering to be active.
|
||||
*/
|
||||
ClusterMode mode = ClusterMode.NONE;
|
||||
|
||||
/**
|
||||
* Configuration if using TCP sockets for clustering communication.
|
||||
*/
|
||||
SocketConfig socketConfig = new SocketConfig();
|
||||
|
||||
/**
|
||||
* Configuration if using Multicast for clustering communication.
|
||||
*/
|
||||
MulticastConfig multicastConfig = new MulticastConfig();
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// MulticastConfig
|
||||
|
||||
/**
|
||||
* The configuration for clustering using Multicast networking.
|
||||
*/
|
||||
public static class MulticastConfig {
|
||||
|
||||
int managerSleepMillis = 80;
|
||||
int lastSendTimeFreqSecs = 300;//5mins
|
||||
int lastStatusTimeFreqSecs = 600;//10mins
|
||||
int maxResendOutgoingAttempts = 200;
|
||||
int maxResendIncomingRequests = 50;
|
||||
|
||||
int listenPort;
|
||||
String listenAddress;
|
||||
int sendPort;
|
||||
String sendAddress;
|
||||
|
||||
// Note 1500 is Ethernet MTU and this must be less than UDP max packet size of 65507
|
||||
int maxSendPacketSize = 1500;
|
||||
|
||||
// Whether to send packets even when there are no other members online
|
||||
boolean sendWithNoMembers = true;
|
||||
|
||||
// When multiple instances are on same box you need to broadcast back locally
|
||||
boolean disableLoopback;
|
||||
int listenTimeToLive = -1;
|
||||
int listenTimeout = 1000;
|
||||
int listenBufferSize = 65500;
|
||||
// For multihomed environment the address the listener should bind to
|
||||
String listenBindAddress;
|
||||
|
||||
/**
|
||||
* Return the manager sleep millis.
|
||||
*/
|
||||
public int getManagerSleepMillis() {
|
||||
return managerSleepMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the manager sleep millis.
|
||||
*/
|
||||
public void setManagerSleepMillis(int managerSleepMillis) {
|
||||
this.managerSleepMillis = managerSleepMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last send time frequency.
|
||||
*/
|
||||
public int getLastSendTimeFreqSecs() {
|
||||
return lastSendTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last send time frequency.
|
||||
*/
|
||||
public void setLastSendTimeFreqSecs(int lastSendTimeFreqSecs) {
|
||||
this.lastSendTimeFreqSecs = lastSendTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last status time frequency.
|
||||
*/
|
||||
public int getLastStatusTimeFreqSecs() {
|
||||
return lastStatusTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last status time frequency.
|
||||
*/
|
||||
public void setLastStatusTimeFreqSecs(int lastStatusTimeFreqSecs) {
|
||||
this.lastStatusTimeFreqSecs = lastStatusTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of times we will try to re-send a given packet before giving up sending
|
||||
*/
|
||||
public int getMaxResendOutgoingAttempts() {
|
||||
return maxResendOutgoingAttempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum retry attempts for outgoing messages.
|
||||
*/
|
||||
public void setMaxResendOutgoingAttempts(int maxResendOutgoingAttempts) {
|
||||
this.maxResendOutgoingAttempts = maxResendOutgoingAttempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of times we will ask for a packet to be resent to us before giving up asking.
|
||||
*/
|
||||
public int getMaxResendIncomingRequests() {
|
||||
return maxResendIncomingRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum retry attempts for incoming messages.
|
||||
*/
|
||||
public void setMaxResendIncomingRequests(int maxResendIncomingRequests) {
|
||||
this.maxResendIncomingRequests = maxResendIncomingRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen port.
|
||||
*/
|
||||
public int getListenPort() {
|
||||
return listenPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen port.
|
||||
*/
|
||||
public void setListenPort(int port) {
|
||||
this.listenPort = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen address.
|
||||
*/
|
||||
public String getListenAddress() {
|
||||
return listenAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen address.
|
||||
*/
|
||||
public void setListenAddress(String listenAddress) {
|
||||
this.listenAddress = listenAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the send port.
|
||||
*/
|
||||
public int getSendPort() {
|
||||
return sendPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the send port.
|
||||
*/
|
||||
public void setSendPort(int sendPort) {
|
||||
this.sendPort = sendPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the send address.
|
||||
*/
|
||||
public String getSendAddress() {
|
||||
return sendAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the send address.
|
||||
*/
|
||||
public void setSendAddress(String sendAddress) {
|
||||
this.sendAddress = sendAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum send packet size.
|
||||
*/
|
||||
public int getMaxSendPacketSize() {
|
||||
return maxSendPacketSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum send packet size. Note 1500 is Ethernet MTU and this must be less than UDP max packet size of 65507.
|
||||
*/
|
||||
public void setMaxSendPacketSize(int maxSendPacketSize) {
|
||||
this.maxSendPacketSize = maxSendPacketSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if send messages when no other members in the cluster are up.
|
||||
*/
|
||||
public boolean isSendWithNoMembers() {
|
||||
return sendWithNoMembers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set true if send messages when no other members in the cluster are up.
|
||||
*/
|
||||
public void setSendWithNoMembers(boolean sendWithNoMembers) {
|
||||
this.sendWithNoMembers = sendWithNoMembers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if loopback is disabled. When multiple instances are on same box you need to broadcast back locally.
|
||||
*/
|
||||
public boolean isDisableLoopback() {
|
||||
return disableLoopback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if loopback is disabled. When multiple instances are on same box you need to broadcast back locally.
|
||||
*/
|
||||
public void setDisableLoopback(boolean disableLoopback) {
|
||||
this.disableLoopback = disableLoopback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen time to live.
|
||||
*/
|
||||
public int getListenTimeToLive() {
|
||||
return listenTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen time to live.
|
||||
*/
|
||||
public void setListenTimeToLive(int listenTimeToLive) {
|
||||
this.listenTimeToLive = listenTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen timeout.
|
||||
*/
|
||||
public int getListenTimeout() {
|
||||
return listenTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the listen timeout.
|
||||
*/
|
||||
public void setListenTimeout(int listenTimeout) {
|
||||
this.listenTimeout = listenTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen buffer size.
|
||||
*/
|
||||
public int getListenBufferSize() {
|
||||
return listenBufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen buffer size.
|
||||
*/
|
||||
public void setListenBufferSize(int listenBufferSize) {
|
||||
this.listenBufferSize = listenBufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listener bind address (optional). For multihomed environment the address the listener should bind to.
|
||||
*/
|
||||
public String getListenBindAddress() {
|
||||
return listenBindAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listener bind address (optional). For multihomed environment the address the listener should bind to.
|
||||
*/
|
||||
public void setListenBindAddress(String listenBindAddress) {
|
||||
this.listenBindAddress = listenBindAddress;
|
||||
}
|
||||
public void setClusterActive(boolean clusterActive) {
|
||||
this.clusterActive = clusterActive;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// SocketConfig
|
||||
|
||||
/**
|
||||
* Configuration for clustering using TCP sockets.
|
||||
* <p>
|
||||
* This is good for when there are relatively small number of cluster members.
|
||||
* Return the deployment properties.
|
||||
*/
|
||||
public static class SocketConfig {
|
||||
|
||||
/**
|
||||
* This local server in host:port format.
|
||||
*/
|
||||
String localHostPort;
|
||||
|
||||
/**
|
||||
* All the cluster members in host:port format.
|
||||
*/
|
||||
List<String> members = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* core threads for the associated thread pool.
|
||||
*/
|
||||
int coreThreads = 2;
|
||||
|
||||
/**
|
||||
* Max threads for the associated thread pool.
|
||||
*/
|
||||
int maxThreads = 16;
|
||||
|
||||
String threadPoolName = "EbeanCluster";
|
||||
|
||||
/**
|
||||
* Return the host and port for this server instance.
|
||||
*/
|
||||
public String getLocalHostPort() {
|
||||
return localHostPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the host and port for this server instance.
|
||||
*/
|
||||
public void setLocalHostPort(String localHostPort) {
|
||||
this.localHostPort = localHostPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the host and port for all the members of the cluster.
|
||||
*/
|
||||
public List<String> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all the host and port for all the members of the cluster.
|
||||
*/
|
||||
public void setMembers(List<String> members) {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of core threads to use.
|
||||
*/
|
||||
public int getCoreThreads() {
|
||||
return coreThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of core threads to use.
|
||||
*/
|
||||
public void setCoreThreads(int coreThreads) {
|
||||
this.coreThreads = coreThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of max threads to use.
|
||||
*/
|
||||
public int getMaxThreads() {
|
||||
return maxThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of max threads to use.
|
||||
*/
|
||||
public void setMaxThreads(int maxThreads) {
|
||||
this.maxThreads = maxThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the thread pool name.
|
||||
*/
|
||||
public String getThreadPoolName() {
|
||||
return threadPoolName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the thread pool name.
|
||||
*/
|
||||
public void setThreadPoolName(String threadPoolName) {
|
||||
this.threadPoolName = threadPoolName;
|
||||
}
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// Members
|
||||
/**
|
||||
* Set the deployment properties.
|
||||
*/
|
||||
public void setProperties(Properties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from properties.
|
||||
*/
|
||||
public void loadFromProperties(Properties properties) {
|
||||
//TODO
|
||||
this.properties = properties;
|
||||
this.clusterActive = getProperty(properties, "ebean.cluster.active", clusterActive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cluster mode.
|
||||
* Return the boolean property setting.
|
||||
*/
|
||||
public ClusterMode getMode() {
|
||||
return mode;
|
||||
protected boolean getProperty(Properties properties, String key, boolean defaultValue) {
|
||||
return "true".equalsIgnoreCase(properties.getProperty(key, Boolean.toString(defaultValue)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cluster mode.
|
||||
*/
|
||||
public void setMode(ClusterMode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the socket communication configuration.
|
||||
*/
|
||||
public SocketConfig getSocketConfig() {
|
||||
return socketConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the socket communication configuration.
|
||||
*/
|
||||
public void setSocketConfig(SocketConfig socketConfig) {
|
||||
this.socketConfig = socketConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the multicast communication configuration.
|
||||
*/
|
||||
public MulticastConfig getMulticastConfig() {
|
||||
return multicastConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the multicast communication configuration.
|
||||
*/
|
||||
public void setMulticastConfig(MulticastConfig multicastConfig) {
|
||||
this.multicastConfig = multicastConfig;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,556 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.util.StringHelper;
|
||||
|
||||
/**
|
||||
* Used to config a DataSource when using the internal Ebean DataSource
|
||||
* implementation.
|
||||
* <p>
|
||||
* If a DataSource instance is already defined via
|
||||
* {@link ServerConfig#setDataSource(javax.sql.DataSource)} or defined as JNDI
|
||||
* dataSource via {@link ServerConfig#setDataSourceJndiName(String)} then those
|
||||
* will used and not this DataSourceConfig.
|
||||
* </p>
|
||||
*/
|
||||
public class DataSourceConfig {
|
||||
|
||||
private String url;
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
private String driver;
|
||||
|
||||
private int minConnections = 2;
|
||||
|
||||
private int maxConnections = 20;
|
||||
|
||||
private int isolationLevel = Transaction.READ_COMMITTED;
|
||||
|
||||
private boolean autoCommit;
|
||||
|
||||
private String heartbeatSql;
|
||||
|
||||
private int heartbeatFreqSecs = 30;
|
||||
|
||||
private int heartbeatTimeoutSeconds = 3;
|
||||
|
||||
private boolean captureStackTrace;
|
||||
|
||||
private int maxStackTraceSize = 5;
|
||||
|
||||
private int leakTimeMinutes = 30;
|
||||
|
||||
private int maxInactiveTimeSecs = 720;
|
||||
|
||||
private int maxAgeMinutes = 0;
|
||||
|
||||
private int trimPoolFreqSecs = 59;
|
||||
|
||||
private int pstmtCacheSize = 20;
|
||||
|
||||
private int cstmtCacheSize = 20;
|
||||
|
||||
private int waitTimeoutMillis = 1000;
|
||||
|
||||
private String poolListener;
|
||||
|
||||
private boolean offline;
|
||||
|
||||
protected Map<String, String> customProperties;
|
||||
|
||||
/**
|
||||
* Return the connection URL.
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connection URL.
|
||||
*/
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the database username.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the database username.
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the database password.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the database password.
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the database driver.
|
||||
*/
|
||||
public String getDriver() {
|
||||
return driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the database driver.
|
||||
*/
|
||||
public void setDriver(String driver) {
|
||||
this.driver = driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction isolation level.
|
||||
*/
|
||||
public int getIsolationLevel() {
|
||||
return isolationLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transaction isolation level.
|
||||
*/
|
||||
public void setIsolationLevel(int isolationLevel) {
|
||||
this.isolationLevel = isolationLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return autoCommit setting.
|
||||
*/
|
||||
public boolean isAutoCommit() {
|
||||
return autoCommit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to turn on autoCommit.
|
||||
*/
|
||||
public void setAutoCommit(boolean autoCommit) {
|
||||
this.autoCommit = autoCommit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum number of connections the pool should maintain.
|
||||
*/
|
||||
public int getMinConnections() {
|
||||
return minConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum number of connections the pool should maintain.
|
||||
*/
|
||||
public void setMinConnections(int minConnections) {
|
||||
this.minConnections = minConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of connections the pool can reach.
|
||||
*/
|
||||
public int getMaxConnections() {
|
||||
return maxConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum number of connections the pool can reach.
|
||||
*/
|
||||
public void setMaxConnections(int maxConnections) {
|
||||
this.maxConnections = maxConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a SQL statement used to test the database is accessible.
|
||||
* <p>
|
||||
* Note that if this is not set then it can get defaulted from the
|
||||
* DatabasePlatform.
|
||||
* </p>
|
||||
*/
|
||||
public String getHeartbeatSql() {
|
||||
return heartbeatSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a SQL statement used to test the database is accessible.
|
||||
* <p>
|
||||
* Note that if this is not set then it can get defaulted from the
|
||||
* DatabasePlatform.
|
||||
* </p>
|
||||
*/
|
||||
public void setHeartbeatSql(String heartbeatSql) {
|
||||
this.heartbeatSql = heartbeatSql;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the heartbeat frequency in seconds.
|
||||
* <p>
|
||||
* This is the expected frequency in which the DataSource should be checked to
|
||||
* make sure it is healthy and trim idle connections.
|
||||
* </p>
|
||||
*/
|
||||
public int getHeartbeatFreqSecs() {
|
||||
return heartbeatFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expected heartbeat frequency in seconds.
|
||||
*/
|
||||
public void setHeartbeatFreqSecs(int heartbeatFreqSecs) {
|
||||
this.heartbeatFreqSecs = heartbeatFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the heart beat timeout in seconds.
|
||||
*/
|
||||
public int getHeartbeatTimeoutSeconds() {
|
||||
return heartbeatTimeoutSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the heart beat timeout in seconds.
|
||||
*/
|
||||
public void setHeartbeatTimeoutSeconds(int heartbeatTimeoutSeconds) {
|
||||
this.heartbeatTimeoutSeconds = heartbeatTimeoutSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a stack trace should be captured when obtaining a connection
|
||||
* from the pool.
|
||||
* <p>
|
||||
* This can be used to diagnose a suspected connection pool leak.
|
||||
* </p>
|
||||
* <p>
|
||||
* Obviously this has a performance overhead.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isCaptureStackTrace() {
|
||||
return captureStackTrace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if a stack trace should be captured when obtaining a connection
|
||||
* from the pool.
|
||||
* <p>
|
||||
* This can be used to diagnose a suspected connection pool leak.
|
||||
* </p>
|
||||
* <p>
|
||||
* Obviously this has a performance overhead.
|
||||
* </p>
|
||||
*/
|
||||
public void setCaptureStackTrace(boolean captureStackTrace) {
|
||||
this.captureStackTrace = captureStackTrace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the max size for reporting stack traces on busy connections.
|
||||
*/
|
||||
public int getMaxStackTraceSize() {
|
||||
return maxStackTraceSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the max size for reporting stack traces on busy connections.
|
||||
*/
|
||||
public void setMaxStackTraceSize(int maxStackTraceSize) {
|
||||
this.maxStackTraceSize = maxStackTraceSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time in minutes after which a connection could be considered to
|
||||
* have leaked.
|
||||
*/
|
||||
public int getLeakTimeMinutes() {
|
||||
return leakTimeMinutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time in minutes after which a connection could be considered to
|
||||
* have leaked.
|
||||
*/
|
||||
public void setLeakTimeMinutes(int leakTimeMinutes) {
|
||||
this.leakTimeMinutes = leakTimeMinutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the PreparedStatement cache (per connection).
|
||||
*/
|
||||
public int getPstmtCacheSize() {
|
||||
return pstmtCacheSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of the PreparedStatement cache (per connection).
|
||||
*/
|
||||
public void setPstmtCacheSize(int pstmtCacheSize) {
|
||||
this.pstmtCacheSize = pstmtCacheSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the CallableStatement cache (per connection).
|
||||
*/
|
||||
public int getCstmtCacheSize() {
|
||||
return cstmtCacheSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of the CallableStatement cache (per connection).
|
||||
*/
|
||||
public void setCstmtCacheSize(int cstmtCacheSize) {
|
||||
this.cstmtCacheSize = cstmtCacheSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time in millis to wait for a connection before timing out once
|
||||
* the pool has reached its maximum size.
|
||||
*/
|
||||
public int getWaitTimeoutMillis() {
|
||||
return waitTimeoutMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time in millis to wait for a connection before timing out once the
|
||||
* pool has reached its maximum size.
|
||||
*/
|
||||
public void setWaitTimeoutMillis(int waitTimeoutMillis) {
|
||||
this.waitTimeoutMillis = waitTimeoutMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time in seconds a connection can be idle after which it can be
|
||||
* trimmed from the pool.
|
||||
* <p>
|
||||
* This is so that the pool after a busy period can trend over time back
|
||||
* towards the minimum connections.
|
||||
* </p>
|
||||
*/
|
||||
public int getMaxInactiveTimeSecs() {
|
||||
return maxInactiveTimeSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum age a connection is allowed to be before it is closed.
|
||||
* <p>
|
||||
* This can be used to close really old connections.
|
||||
* </p>
|
||||
*/
|
||||
public int getMaxAgeMinutes() {
|
||||
return maxAgeMinutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum age a connection can be in minutes.
|
||||
*/
|
||||
public void setMaxAgeMinutes(int maxAgeMinutes) {
|
||||
this.maxAgeMinutes = maxAgeMinutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time in seconds a connection can be idle after which it can be
|
||||
* trimmed from the pool.
|
||||
* <p>
|
||||
* This is so that the pool after a busy period can trend over time back
|
||||
* towards the minimum connections.
|
||||
* </p>
|
||||
*/
|
||||
public void setMaxInactiveTimeSecs(int maxInactiveTimeSecs) {
|
||||
this.maxInactiveTimeSecs = maxInactiveTimeSecs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the minimum time gap between pool trim checks.
|
||||
* <p>
|
||||
* This defaults to 59 seconds meaning that the pool trim check will run every
|
||||
* minute assuming the heart beat check runs every 30 seconds.
|
||||
* </p>
|
||||
*/
|
||||
public int getTrimPoolFreqSecs() {
|
||||
return trimPoolFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum trim gap between pool trim checks.
|
||||
*/
|
||||
public void setTrimPoolFreqSecs(int trimPoolFreqSecs) {
|
||||
this.trimPoolFreqSecs = trimPoolFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the pool listener.
|
||||
*/
|
||||
public String getPoolListener() {
|
||||
return poolListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a pool listener.
|
||||
*/
|
||||
public void setPoolListener(String poolListener) {
|
||||
this.poolListener = poolListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the DataSource should be left offline.
|
||||
* <p>
|
||||
* This is to support DDL generation etc without having a real database.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isOffline() {
|
||||
return offline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the DataSource should be left offline.
|
||||
* <p>
|
||||
* This is to support DDL generation etc without having a real database.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that you MUST specify the database platform name (oracle, postgres,
|
||||
* h2, mysql etc) using {@link ServerConfig#setDatabasePlatformName(String)}
|
||||
* when you do this.
|
||||
* </p>
|
||||
*/
|
||||
public void setOffline(boolean offline) {
|
||||
this.offline = offline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of custom properties for the jdbc driver connection.
|
||||
*/
|
||||
public Map<String, String> getCustomProperties() {
|
||||
return customProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom properties for the jdbc driver connection.
|
||||
*
|
||||
* @param customProperties
|
||||
*/
|
||||
public void setCustomProperties(Map<String, String> customProperties) {
|
||||
this.customProperties = customProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings by reading the ebean.properties file.
|
||||
*
|
||||
* @param serverName name of the server
|
||||
*/
|
||||
public void loadSettings(String serverName) {
|
||||
loadSettings(new PropertiesWrapper("datasource", serverName, PropertyMap.defaultProperties()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from the properties supplied.
|
||||
* <p>
|
||||
* You can use this when you have your own properties to use for configuration.
|
||||
* </p>
|
||||
*
|
||||
* @param properties the properties to configure the datasource
|
||||
* @param serverName the name of the specific datasource (optional)
|
||||
*/
|
||||
public void loadSettings(Properties properties, String serverName) {
|
||||
PropertiesWrapper dbProps = new PropertiesWrapper("datasource", serverName, properties);
|
||||
loadSettings(dbProps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from the PropertiesWrapper.
|
||||
*/
|
||||
public void loadSettings(PropertiesWrapper properties) {
|
||||
|
||||
username = properties.get("username", username);
|
||||
password = properties.get("password", password);
|
||||
driver = properties.get("driver", properties.get("databaseDriver", driver));
|
||||
url = properties.get("url", properties.get("databaseUrl", url));
|
||||
|
||||
autoCommit = properties.getBoolean("autoCommit", autoCommit);
|
||||
captureStackTrace = properties.getBoolean("captureStackTrace", captureStackTrace);
|
||||
maxStackTraceSize = properties.getInt("maxStackTraceSize", maxStackTraceSize);
|
||||
leakTimeMinutes = properties.getInt("leakTimeMinutes", leakTimeMinutes);
|
||||
maxInactiveTimeSecs = properties.getInt("maxInactiveTimeSecs", maxInactiveTimeSecs);
|
||||
trimPoolFreqSecs = properties.getInt("trimPoolFreqSecs", trimPoolFreqSecs);
|
||||
maxAgeMinutes = properties.getInt("maxAgeMinutes", maxAgeMinutes);
|
||||
|
||||
minConnections = properties.getInt("minConnections", minConnections);
|
||||
maxConnections = properties.getInt("maxConnections", maxConnections);
|
||||
pstmtCacheSize = properties.getInt("pstmtCacheSize", pstmtCacheSize);
|
||||
cstmtCacheSize = properties.getInt("cstmtCacheSize", cstmtCacheSize);
|
||||
|
||||
waitTimeoutMillis = properties.getInt("waitTimeout", waitTimeoutMillis);
|
||||
|
||||
heartbeatSql = properties.get("heartbeatSql", heartbeatSql);
|
||||
heartbeatTimeoutSeconds = properties.getInt("heartbeatTimeoutSeconds", heartbeatTimeoutSeconds);
|
||||
poolListener = properties.get("poolListener", poolListener);
|
||||
offline = properties.getBoolean("offline", offline);
|
||||
|
||||
String isoLevel = properties.get("isolationlevel", getTransactionIsolationLevel(isolationLevel));
|
||||
this.isolationLevel = getTransactionIsolationLevel(isoLevel);
|
||||
|
||||
String customProperties = properties.get("customProperties", null);
|
||||
if (customProperties != null && customProperties.length() > 0) {
|
||||
this.customProperties = StringHelper.delimitedToMap(customProperties, ";", "=");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the isolation level description from the associated Connection int value.
|
||||
*/
|
||||
public String getTransactionIsolationLevel(int level) {
|
||||
switch (level) {
|
||||
case Connection.TRANSACTION_NONE : return "NONE";
|
||||
case Connection.TRANSACTION_READ_COMMITTED : return "READ_COMMITTED";
|
||||
case Connection.TRANSACTION_READ_UNCOMMITTED : return "READ_UNCOMMITTED";
|
||||
case Connection.TRANSACTION_REPEATABLE_READ : return "REPEATABLE_READ";
|
||||
case Connection.TRANSACTION_SERIALIZABLE : return "SERIALIZABLE";
|
||||
default: throw new RuntimeException("Transaction Isolation level [" + level + "] is not known.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the isolation level for a given string description.
|
||||
*/
|
||||
public int getTransactionIsolationLevel(String level) {
|
||||
level = level.toUpperCase();
|
||||
if (level.startsWith("TRANSACTION")) {
|
||||
level = level.substring("TRANSACTION".length());
|
||||
}
|
||||
level = level.replace("_", "");
|
||||
if ("NONE".equalsIgnoreCase(level)) {
|
||||
return Connection.TRANSACTION_NONE;
|
||||
}
|
||||
if ("READCOMMITTED".equalsIgnoreCase(level)) {
|
||||
return Connection.TRANSACTION_READ_COMMITTED;
|
||||
}
|
||||
if ("READUNCOMMITTED".equalsIgnoreCase(level)) {
|
||||
return Connection.TRANSACTION_READ_UNCOMMITTED;
|
||||
}
|
||||
if ("REPEATABLEREAD".equalsIgnoreCase(level)) {
|
||||
return Connection.TRANSACTION_REPEATABLE_READ;
|
||||
}
|
||||
if ("SERIALIZABLE".equalsIgnoreCase(level)) {
|
||||
return Connection.TRANSACTION_SERIALIZABLE;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Transaction Isolation level [" + level + "] is not known.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
|
||||
/**
|
||||
* Configuration for the Document store integration (e.g. ElasticSearch).
|
||||
*/
|
||||
public class DocStoreConfig {
|
||||
|
||||
/**
|
||||
* True when the Document store integration is active/on.
|
||||
*/
|
||||
protected boolean active;
|
||||
|
||||
/**
|
||||
* Set to true means Ebean will generate mapping files on startup.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
protected String url;
|
||||
|
||||
/**
|
||||
* The default mode used by indexes.
|
||||
*/
|
||||
protected DocStoreMode persist = DocStoreMode.UPDATE;
|
||||
|
||||
/**
|
||||
* The default batch size to use for the Bulk API calls.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to make the Document store (ElasticSearch) integration active.
|
||||
*/
|
||||
public void setActive(boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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 DocStoreMode getPersist() {
|
||||
return persist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default behavior for when Insert, Update and Delete events occur on beans that have an associated
|
||||
* Document store.
|
||||
* <ul>
|
||||
* <li>DocStoreEvent.UPDATE - build and send message to Bulk API</li>
|
||||
* <li>DocStoreEvent.QUEUE - add an entry with the index type and id only into a queue for later processing</li>
|
||||
* <li>DocStoreEvent.IGNORE - ignore. Most likely used when some scheduled batch job handles updating the index</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* You might choose to use QUEUE if that particular index data is updating very frequently or the cost of indexing
|
||||
* is expensive. Setting it to QUEUE can mean many changes can be batched together potentially coalescing multiple
|
||||
* updates for an index entry into a single update.
|
||||
* </p>
|
||||
* <p>
|
||||
* You might choose to use IGNORE when you have your own external process for updating the indexes. In this case
|
||||
* you don't want Ebean to do anything when the data changes.
|
||||
* </p>
|
||||
*/
|
||||
public void setPersist(DocStoreMode persist) {
|
||||
this.persist = persist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load settings specified in properties files.
|
||||
*/
|
||||
public void loadSettings(PropertiesWrapper properties) {
|
||||
|
||||
active = properties.getBoolean("docstore.active", active);
|
||||
url = properties.get("docstore.url", url);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,11 @@ public final class PropertyMap implements Serializable {
|
||||
return (propertyMap == null) ? new Properties() : propertyMap.asProperties();
|
||||
}
|
||||
|
||||
public static boolean loadTestProperties() {
|
||||
String disable = System.getProperty("disableTestProperties");
|
||||
return (disable == null || !disable.equalsIgnoreCase("true"));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return map.toString();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ final class PropertyMapLoader {
|
||||
* Load the <code>test-ebean.properties</code>.
|
||||
*/
|
||||
public static PropertyMap loadTestProperties() {
|
||||
if (!PropertyMap.loadTestProperties()) {
|
||||
return new PropertyMap();
|
||||
}
|
||||
return load(null, "test-ebean.properties");
|
||||
}
|
||||
|
||||
@@ -31,7 +34,7 @@ final class PropertyMapLoader {
|
||||
if (fileName == null) {
|
||||
fileName = System.getProperty("ebean.props.file");
|
||||
if (fileName == null) {
|
||||
loadTestProperties = true;
|
||||
loadTestProperties = PropertyMap.loadTestProperties();
|
||||
fileName = "ebean.properties";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,14 @@ import com.avaje.ebean.event.readaudit.ReadAuditLogger;
|
||||
import com.avaje.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import com.avaje.ebean.meta.MetaInfoManager;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import org.avaje.datasource.DataSourceConfig;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* The configuration used for creating a EbeanServer.
|
||||
@@ -129,6 +132,11 @@ public class ServerConfig {
|
||||
*/
|
||||
private String classPathReaderClassName;
|
||||
|
||||
/**
|
||||
* Configuration for the ElasticSearch integration.
|
||||
*/
|
||||
private DocStoreConfig docStoreConfig = new DocStoreConfig();
|
||||
|
||||
/**
|
||||
* This is used to populate @WhoCreated, @WhoModified and
|
||||
* support other audit features (who executed a query etc).
|
||||
@@ -283,7 +291,7 @@ public class ServerConfig {
|
||||
private DbConstraintNaming constraintNaming = new DbConstraintNaming();
|
||||
|
||||
/**
|
||||
* Behaviour of update to include on the change properties.
|
||||
* Behaviour of update to include on the change properties.
|
||||
*/
|
||||
private boolean updateChangesOnly = true;
|
||||
|
||||
@@ -387,6 +395,8 @@ public class ServerConfig {
|
||||
*/
|
||||
private boolean expressionEqualsWithNullAsNoop;
|
||||
|
||||
private String jodaLocalTimeMode;
|
||||
|
||||
/**
|
||||
* Construct a Server Configuration for programmatically creating an EbeanServer.
|
||||
*/
|
||||
@@ -1151,6 +1161,20 @@ public class ServerConfig {
|
||||
this.namingConvention = namingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configuration for the ElasticSearch integration.
|
||||
*/
|
||||
public DocStoreConfig getDocStoreConfig() {
|
||||
return docStoreConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the configuration for the ElasticSearch integration.
|
||||
*/
|
||||
public void setDocStoreConfig(DocStoreConfig docStoreConfig) {
|
||||
this.docStoreConfig = docStoreConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the constraint naming convention used in DDL generation.
|
||||
*/
|
||||
@@ -1368,8 +1392,6 @@ public class ServerConfig {
|
||||
* <p>
|
||||
* Values are oracle, h2, postgres, mysql, mssqlserver2005.
|
||||
* </p>
|
||||
*
|
||||
* @see DataSourceConfig#setOffline(boolean)
|
||||
*/
|
||||
public void setDatabasePlatformName(String databasePlatformName) {
|
||||
this.databasePlatformName = databasePlatformName;
|
||||
@@ -1640,6 +1662,20 @@ public class ServerConfig {
|
||||
this.disableClasspathSearch = disableClasspathSearch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mode to use for Joda LocalTime support 'normal' or 'utc'.
|
||||
*/
|
||||
public String getJodaLocalTimeMode() {
|
||||
return jodaLocalTimeMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mode to use for Joda LocalTime support 'normal' or 'utc'.
|
||||
*/
|
||||
public void setJodaLocalTimeMode(String jodaLocalTimeMode) {
|
||||
this.jodaLocalTimeMode = jodaLocalTimeMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Programmatically add classes (typically entities) that this server should
|
||||
* use.
|
||||
@@ -2118,6 +2154,23 @@ public class ServerConfig {
|
||||
this.classLoadConfig = classLoadConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the service loader using the classLoader defined in ClassLoadConfig.
|
||||
*/
|
||||
public <T> ServiceLoader<T> serviceLoad(Class<T> spiService) {
|
||||
|
||||
return ServiceLoader.load(spiService, classLoadConfig.getClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first service using the service loader (or null).
|
||||
*/
|
||||
public <T> T service(Class<T> spiService) {
|
||||
ServiceLoader<T> load = serviceLoad(spiService);
|
||||
Iterator<T> serviceInstances = load.iterator();
|
||||
return serviceInstances.hasNext() ? serviceInstances.next() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load settings from ebean.properties.
|
||||
*/
|
||||
@@ -2192,11 +2245,18 @@ public class ServerConfig {
|
||||
* @param p - The defined property source passed to load settings
|
||||
*/
|
||||
protected void loadDataSourceSettings(PropertiesWrapper p) {
|
||||
dataSourceConfig.loadSettings(p.withPrefix("datasource"));
|
||||
dataSourceConfig.loadSettings(p.properties, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 to allow overridden behaviour.
|
||||
*/
|
||||
protected void loadAutoTuneSettings(PropertiesWrapper p) {
|
||||
autoTuneConfig.loadSettings(p);
|
||||
@@ -2223,6 +2283,11 @@ public class ServerConfig {
|
||||
}
|
||||
loadDataSourceSettings(p);
|
||||
|
||||
if (docStoreConfig == null) {
|
||||
docStoreConfig = new DocStoreConfig();
|
||||
}
|
||||
loadDocStoreSettings(p);
|
||||
|
||||
explicitTransactionBeginMode = p.getBoolean("explicitTransactionBeginMode", explicitTransactionBeginMode);
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
|
||||
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager);
|
||||
@@ -2286,6 +2351,7 @@ public class ServerConfig {
|
||||
dbUuid = DbUuid.BINARY;
|
||||
}
|
||||
localTimeWithNanos = p.getBoolean("localTimeWithNanos", localTimeWithNanos);
|
||||
jodaLocalTimeMode = p.get("jodaLocalTimeMode", jodaLocalTimeMode);
|
||||
|
||||
lazyLoadBatchSize = p.getInt("lazyLoadBatchSize", lazyLoadBatchSize);
|
||||
queryBatchSize = p.getInt("queryBatchSize", queryBatchSize);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -16,11 +16,9 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
this.name = "oracle";
|
||||
this.maxTableNameLength = 30;
|
||||
this.maxConstraintNameLength = 30;
|
||||
// OnQueryOnly.CLOSE as a performance optimisation on Oracle
|
||||
this.onQueryOnly = OnQueryOnly.CLOSE;
|
||||
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
|
||||
|
||||
@@ -19,9 +19,6 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
public PostgresPlatform() {
|
||||
super();
|
||||
this.name = "postgres";
|
||||
|
||||
// OnQueryOnly.CLOSE as a performance optimisation on Postgres
|
||||
this.onQueryOnly = OnQueryOnly.CLOSE;
|
||||
this.likeClause = "like ? escape''";
|
||||
this.selectCountWithAlias = true;
|
||||
this.blobDbType = Types.LONGVARBINARY;
|
||||
@@ -30,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);
|
||||
|
||||
@@ -220,28 +220,37 @@ public class DbMigration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the diff migration.
|
||||
*/
|
||||
private void generateDiff(Request request) throws IOException {
|
||||
|
||||
if (request.hasPendingDrops()) {
|
||||
logger.info("Pending un-applied drops in versions {}", request.getPendingDrops());
|
||||
List<String> pendingDrops = request.getPendingDrops();
|
||||
if (!pendingDrops.isEmpty()) {
|
||||
logger.info("Pending un-applied drops in versions {}", pendingDrops);
|
||||
}
|
||||
|
||||
ModelDiff diff = request.createDiff();
|
||||
if (diff.isEmpty()) {
|
||||
Migration migration = request.createDiffMigration();
|
||||
if (migration == null) {
|
||||
logger.info("no changes detected - no migration written");
|
||||
} else {
|
||||
// there were actually changes to write
|
||||
generateMigration(request, diff.getMigration(), null);
|
||||
generateMigration(request, migration, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the migration based on the pendingDrops from a prior version.
|
||||
*/
|
||||
private void generatePendingDrop(Request request, String pendingVersion) throws IOException {
|
||||
|
||||
Migration migration = request.migrationForPendingDrop(pendingVersion);
|
||||
|
||||
generateMigration(request, migration, pendingVersion);
|
||||
if (request.hasPendingDrops()) {
|
||||
logger.info("... remaining pending un-applied drops in versions {}", request.getPendingDrops());
|
||||
|
||||
List<String> pendingDrops = request.getPendingDrops();
|
||||
if (!pendingDrops.isEmpty()) {
|
||||
logger.info("... remaining pending un-applied drops in versions {}", pendingDrops);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,13 +276,6 @@ public class DbMigration {
|
||||
this.current = currentModel.read();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are pending un-applied drops.
|
||||
*/
|
||||
public boolean hasPendingDrops() {
|
||||
return migrated.hasPendingDrops();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the migration for the pending drops for a given version.
|
||||
*/
|
||||
@@ -294,12 +296,12 @@ public class DbMigration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an return the diff of the current model to the migration model.
|
||||
* Create and return the diff of the current model to the migration model.
|
||||
*/
|
||||
public ModelDiff createDiff() {
|
||||
public Migration createDiffMigration() {
|
||||
ModelDiff diff = new ModelDiff(migrated);
|
||||
diff.compareTo(current);
|
||||
return diff;
|
||||
return diff.isEmpty() ? null : diff.getMigration();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,7 +330,7 @@ public class DbMigration {
|
||||
*/
|
||||
private String generatePendingDrop() {
|
||||
|
||||
String nextDrop = System.getProperty("ddl.migration.pendingDrop");
|
||||
String nextDrop = System.getProperty("ddl.migration.pendingDropsFor");
|
||||
if (nextDrop != null) {
|
||||
return nextDrop;
|
||||
}
|
||||
|
||||
@@ -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
-1
@@ -14,7 +14,7 @@ public class PostgresHistoryDdl extends DbTriggerBasedHistoryDdl {
|
||||
|
||||
|
||||
public PostgresHistoryDdl() {
|
||||
this.currentTimestamp = "statement_timestamp()";
|
||||
this.currentTimestamp = "current_timestamp";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-9
@@ -5,7 +5,7 @@ import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
|
||||
/**
|
||||
* Converts a logical column definition into platform specific one.
|
||||
*
|
||||
* <p>
|
||||
* This translates standard sql types into platform specific ones.
|
||||
*/
|
||||
public class PlatformTypeConverter {
|
||||
@@ -44,20 +44,21 @@ public class PlatformTypeConverter {
|
||||
return columnDefinition;
|
||||
}
|
||||
|
||||
String type = columnDefinition.substring(0,open);
|
||||
String suffix = close + 1 < columnDefinition.length() ? columnDefinition.substring(close + 1) : "";
|
||||
String type = columnDefinition.substring(0, open);
|
||||
try {
|
||||
DbType dbType = platformTypes.lookup(type);
|
||||
int comma = columnDefinition.indexOf(',',open);
|
||||
int comma = columnDefinition.indexOf(',', open);
|
||||
if (comma > -1) {
|
||||
// scale and precision - decimal(10,4)
|
||||
int scale = Integer.parseInt(columnDefinition.substring(open+1, comma));
|
||||
int precision = Integer.parseInt(columnDefinition.substring(comma+1, close));
|
||||
return dbType.renderType(scale,precision);
|
||||
int scale = Integer.parseInt(columnDefinition.substring(open + 1, comma));
|
||||
int precision = Integer.parseInt(columnDefinition.substring(comma + 1, close));
|
||||
return dbType.renderType(scale, precision) + suffix;
|
||||
|
||||
} else {
|
||||
// scale - varchar(10)
|
||||
int scale = Integer.parseInt(columnDefinition.substring(open+1, close));
|
||||
return dbType.renderType(scale,0);
|
||||
int scale = Integer.parseInt(columnDefinition.substring(open + 1, close));
|
||||
return dbType.renderType(scale, 0) + suffix;
|
||||
}
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
@@ -73,7 +74,7 @@ public class PlatformTypeConverter {
|
||||
|
||||
try {
|
||||
DbType dbType = platformTypes.lookup(columnDefinition);
|
||||
return dbType.renderType(0,0);
|
||||
return dbType.renderType(0, 0);
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
// assume already platform specific, leave as is
|
||||
|
||||
@@ -28,6 +28,7 @@ import javax.xml.bind.annotation.XmlType;
|
||||
* </sequence>
|
||||
* <attribute name="type" use="required" type="{http://ebean-orm.github.io/xml/ns/dbmigration}changeSetType" />
|
||||
* <attribute name="dropsFor" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="suppressDropsForever" type="{http://www.w3.org/2001/XMLSchema}boolean" />
|
||||
* <attribute name="generated" type="{http://www.w3.org/2001/XMLSchema}boolean" />
|
||||
* <attribute name="author" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="comment" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
@@ -65,6 +66,8 @@ public class ChangeSet {
|
||||
protected ChangeSetType type;
|
||||
@XmlAttribute(name = "dropsFor")
|
||||
protected String dropsFor;
|
||||
@XmlAttribute(name = "suppressDropsForever")
|
||||
protected Boolean suppressDropsForever;
|
||||
@XmlAttribute(name = "generated")
|
||||
protected Boolean generated;
|
||||
@XmlAttribute(name = "author")
|
||||
@@ -161,6 +164,30 @@ public class ChangeSet {
|
||||
this.dropsFor = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the suppressDropsForever property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link Boolean }
|
||||
*
|
||||
*/
|
||||
public Boolean isSuppressDropsForever() {
|
||||
return suppressDropsForever;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the suppressDropsForever property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link Boolean }
|
||||
*
|
||||
*/
|
||||
public void setSuppressDropsForever(Boolean value) {
|
||||
this.suppressDropsForever = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the generated property.
|
||||
*
|
||||
|
||||
@@ -159,12 +159,7 @@ public class CurrentModel {
|
||||
ModelDiff diff = new ModelDiff();
|
||||
diff.compareTo(model);
|
||||
|
||||
List<Object> applyChanges = diff.getApplyChanges();
|
||||
|
||||
// put the changes into a ChangeSet
|
||||
ChangeSet applyChangeSet = new ChangeSet();
|
||||
applyChangeSet.getChangeSetChildren().addAll(applyChanges);
|
||||
return applyChangeSet;
|
||||
return diff.getApplyChangeSet();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -356,8 +356,9 @@ public class MTable {
|
||||
return withHistory;
|
||||
}
|
||||
|
||||
public void setWithHistory(boolean withHistory) {
|
||||
public MTable setWithHistory(boolean withHistory) {
|
||||
this.withHistory = withHistory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<String> allHistoryColumns(boolean includeDropped) {
|
||||
|
||||
@@ -13,7 +13,6 @@ import com.avaje.ebean.dbmigration.migration.DropIndex;
|
||||
import com.avaje.ebean.dbmigration.migration.DropTable;
|
||||
import com.avaje.ebean.dbmigration.migration.Migration;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -45,8 +44,7 @@ public class ModelContainer {
|
||||
* Adjust the FK references on all the draft tables.
|
||||
*/
|
||||
public void adjustDraftReferences() {
|
||||
Collection<MTable> tables = this.tables.values();
|
||||
for (MTable table : tables) {
|
||||
for (MTable table : this.tables.values()) {
|
||||
if (table.isDraft()) {
|
||||
table.adjustReferences(this);
|
||||
}
|
||||
@@ -92,9 +90,9 @@ public class ModelContainer {
|
||||
if (pending) {
|
||||
// un-applied drop columns etc
|
||||
pendingDrops.add(version, changeSet);
|
||||
|
||||
} else if (isDropsFor(changeSet)) {
|
||||
// applied drops (so no longer pending)
|
||||
pendingDrops.remove(MigrationVersion.parse(changeSet.getDropsFor()));
|
||||
pendingDrops.appliedDropsFor(changeSet);
|
||||
}
|
||||
if (!isDropsFor(changeSet)) {
|
||||
applyChangeSet(changeSet);
|
||||
@@ -265,13 +263,6 @@ public class ModelContainer {
|
||||
indexes.put(indexName, new MIndex(indexName, tableName, columnNames));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are pending drops.
|
||||
*/
|
||||
public boolean hasPendingDrops() {
|
||||
return !pendingDrops.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of versions containing un-applied pending drops.
|
||||
*/
|
||||
@@ -293,10 +284,26 @@ public class ModelContainer {
|
||||
pendingDrops.registerPendingHistoryDropColumns(newModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register any pending drop columns on history tables. These columns are now not in the current
|
||||
* logical model but we still need to include them in the history views and triggers until they
|
||||
* are actually dropped.
|
||||
*/
|
||||
public void registerPendingHistoryDropColumns(ChangeSet changeSet) {
|
||||
for (Object change : changeSet.getChangeSetChildren()) {
|
||||
if (change instanceof DropColumn) {
|
||||
DropColumn dropColumn = (DropColumn) change;
|
||||
if (Boolean.TRUE.equals(dropColumn.isWithHistory())) {
|
||||
registerPendingDropColumn(dropColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a drop column on a history tables that has not been applied yet.
|
||||
*/
|
||||
public void registerPendingDropColumn(DropColumn dropColumn) {
|
||||
private void registerPendingDropColumn(DropColumn dropColumn) {
|
||||
|
||||
MTable table = getTable(dropColumn.getTableName());
|
||||
if (table == null) {
|
||||
|
||||
@@ -66,16 +66,14 @@ public class ModelDiff {
|
||||
public Migration getMigration() {
|
||||
|
||||
Migration migration = new Migration();
|
||||
ChangeSet applyChangeSet = getApplyChangeSet();
|
||||
if (!applyChangeSet.getChangeSetChildren().isEmpty()) {
|
||||
if (!applyChanges.isEmpty()) {
|
||||
// add a non empty apply changeSet
|
||||
migration.getChangeSet().add(applyChangeSet);
|
||||
migration.getChangeSet().add(getApplyChangeSet());
|
||||
}
|
||||
|
||||
ChangeSet dropChangeSet = getDropChangeSet();
|
||||
if (!dropChangeSet.getChangeSetChildren().isEmpty()) {
|
||||
if (!dropChanges.isEmpty()) {
|
||||
// add a non empty drop changeSet
|
||||
migration.getChangeSet().add(dropChangeSet);
|
||||
migration.getChangeSet().add(getDropChangeSet());
|
||||
}
|
||||
return migration;
|
||||
}
|
||||
@@ -83,14 +81,14 @@ public class ModelDiff {
|
||||
/**
|
||||
* Return the list of 'apply' changes.
|
||||
*/
|
||||
public List<Object> getApplyChanges() {
|
||||
List<Object> getApplyChanges() {
|
||||
return applyChanges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of 'drop' changes.
|
||||
*/
|
||||
public List<Object> getDropChanges() {
|
||||
List<Object> getDropChanges() {
|
||||
return dropChanges;
|
||||
}
|
||||
|
||||
@@ -108,7 +106,7 @@ public class ModelDiff {
|
||||
/**
|
||||
* Return the 'drop' changeSet.
|
||||
*/
|
||||
public ChangeSet getDropChangeSet() {
|
||||
ChangeSet getDropChangeSet() {
|
||||
// put the changes into a ChangeSet
|
||||
ChangeSet createChangeSet = new ChangeSet();
|
||||
createChangeSet.setType(ChangeSetType.PENDING_DROPS);
|
||||
@@ -156,7 +154,12 @@ public class ModelDiff {
|
||||
}
|
||||
}
|
||||
|
||||
// register un-applied ones from the previous migrations
|
||||
baseModel.registerPendingHistoryDropColumns(newModel);
|
||||
if (!dropChanges.isEmpty()) {
|
||||
// register new ones created just now as part of this diff
|
||||
newModel.registerPendingHistoryDropColumns(getDropChangeSet());
|
||||
}
|
||||
}
|
||||
|
||||
protected void addDropTable(MTable existingTable) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.ebean.dbmigration.model;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSet;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSetType;
|
||||
import com.avaje.ebean.dbmigration.migration.DropColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.DropTable;
|
||||
import com.avaje.ebean.dbmigration.migration.Migration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -37,23 +38,29 @@ public class PendingDrops {
|
||||
|
||||
List<String> versions = new ArrayList<String>();
|
||||
for (Entry value : map.values()) {
|
||||
versions.add(value.version.asString());
|
||||
if (value.hasPendingDrops()) {
|
||||
versions.add(value.version.asString());
|
||||
}
|
||||
}
|
||||
return versions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the pending drops for a version (as they have been applied).
|
||||
* All the pending drops for this migration version have been applied so we need
|
||||
* to remove the (unsuppressed) pending drops for this version.
|
||||
*/
|
||||
public void remove(MigrationVersion version) {
|
||||
map.remove(version.normalised());
|
||||
}
|
||||
public boolean appliedDropsFor(ChangeSet changeSet) {
|
||||
|
||||
/**
|
||||
* Return true if there are no pending drops.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
MigrationVersion version = MigrationVersion.parse(changeSet.getDropsFor());
|
||||
|
||||
Entry entry = map.get(version.normalised());
|
||||
if (entry.removeDrops(changeSet)) {
|
||||
// it had no suppressForever changeSets so remove completely
|
||||
map.remove(version.normalised());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,34 +71,46 @@ public class PendingDrops {
|
||||
*/
|
||||
public Migration migrationForVersion(String pendingVersion) {
|
||||
|
||||
Entry entry = getChangeSets(pendingVersion);
|
||||
Entry entry = getEntry(pendingVersion);
|
||||
|
||||
Migration migration = new Migration();
|
||||
for (ChangeSet changeSet : entry.list) {
|
||||
changeSet.setType(ChangeSetType.APPLY);
|
||||
changeSet.setDropsFor(entry.version.asString());
|
||||
migration.getChangeSet().add(changeSet);
|
||||
Iterator<ChangeSet> it = entry.list.iterator();
|
||||
while (it.hasNext()) {
|
||||
ChangeSet changeSet = it.next();
|
||||
if (!isSuppressForever(changeSet)) {
|
||||
it.remove();
|
||||
changeSet.setType(ChangeSetType.APPLY);
|
||||
changeSet.setDropsFor(entry.version.asString());
|
||||
migration.getChangeSet().add(changeSet);
|
||||
}
|
||||
}
|
||||
|
||||
if (migration.getChangeSet().isEmpty()) {
|
||||
throw new IllegalArgumentException("The remaining pendingDrops changeSets in migration ["+pendingVersion+"] are suppressDropsForever=true and can't be applied");
|
||||
}
|
||||
|
||||
if (!entry.containsSuppressForever()) {
|
||||
// we can remove it completely as it has no suppressForever changes
|
||||
map.remove(entry.version.normalised());
|
||||
}
|
||||
|
||||
return migration;
|
||||
}
|
||||
|
||||
private Entry getChangeSets(String pendingVersion) {
|
||||
private Entry getEntry(String pendingVersion) {
|
||||
|
||||
if ("next".equalsIgnoreCase(pendingVersion)) {
|
||||
Iterator<Entry> it = map.values().iterator();
|
||||
if (it.hasNext()) {
|
||||
Entry first = it.next();
|
||||
it.remove();
|
||||
return first;
|
||||
return it.next();
|
||||
}
|
||||
} else {
|
||||
Entry remove = map.remove(MigrationVersion.parse(pendingVersion).normalised());
|
||||
Entry remove = map.get(MigrationVersion.parse(pendingVersion).normalised());
|
||||
if (remove != null) {
|
||||
return remove;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("No pending changeSets for version [" + pendingVersion + "] found");
|
||||
throw new IllegalArgumentException("No 'pendingDrops' changeSets for migration version [" + pendingVersion + "] found");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,18 +120,25 @@ public class PendingDrops {
|
||||
|
||||
for (Entry entry : map.values()) {
|
||||
for (ChangeSet changeSet : entry.list) {
|
||||
for (Object change : changeSet.getChangeSetChildren()) {
|
||||
if (change instanceof DropColumn) {
|
||||
DropColumn dropColumn = (DropColumn) change;
|
||||
if (Boolean.TRUE.equals(dropColumn.isWithHistory())) {
|
||||
newModel.registerPendingDropColumn(dropColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
newModel.registerPendingHistoryDropColumns(changeSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is an Entry for the given version.
|
||||
*/
|
||||
boolean testContainsEntryFor(MigrationVersion version) {
|
||||
return map.containsKey(version.normalised());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Entry for the given version.
|
||||
*/
|
||||
Entry testGetEntryFor(MigrationVersion version) {
|
||||
return map.get(version.normalised());
|
||||
}
|
||||
|
||||
static class Entry {
|
||||
|
||||
final MigrationVersion version;
|
||||
@@ -126,6 +152,112 @@ public class PendingDrops {
|
||||
void add(ChangeSet changeSet) {
|
||||
list.add(changeSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this contains suppressForever changeSets.
|
||||
*/
|
||||
boolean containsSuppressForever() {
|
||||
for (ChangeSet changeSet : list) {
|
||||
if (isSuppressForever(changeSet)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this contains drops that can be applied / migrated.
|
||||
*/
|
||||
boolean hasPendingDrops() {
|
||||
for (ChangeSet changeSet : list) {
|
||||
if (!isSuppressForever(changeSet)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the drops that are not suppressForever and return true if that
|
||||
* removed all the changeSets (and there are no suppressForever ones).
|
||||
*/
|
||||
boolean removeDrops(ChangeSet appliedDrops) {
|
||||
|
||||
Iterator<ChangeSet> iterator = list.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
ChangeSet next = iterator.next();
|
||||
if (!isSuppressForever(next)) {
|
||||
removeMatchingChanges(next, appliedDrops);
|
||||
if (next.getChangeSetChildren().isEmpty()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the applied drops from the pending ones matching by table name and column name.
|
||||
*/
|
||||
private void removeMatchingChanges(ChangeSet pendingDrops, ChangeSet appliedDrops) {
|
||||
|
||||
List<Object> pending = pendingDrops.getChangeSetChildren();
|
||||
Iterator<Object> iterator = pending.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Object pendingDrop = iterator.next();
|
||||
if (pendingDrop instanceof DropColumn && dropColumnIn((DropColumn)pendingDrop, appliedDrops)) {
|
||||
iterator.remove();
|
||||
|
||||
} else if (pendingDrop instanceof DropTable && dropTableIn((DropTable)pendingDrop, appliedDrops)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the pendingDrop is contained in the appliedDrops.
|
||||
*/
|
||||
private boolean dropTableIn(DropTable pendingDrop, ChangeSet appliedDrops) {
|
||||
for (Object o : appliedDrops.getChangeSetChildren()) {
|
||||
if (o instanceof DropTable && sameTable(pendingDrop, (DropTable)o)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the pendingDrop is contained in the appliedDrops.
|
||||
*/
|
||||
private boolean dropColumnIn(DropColumn pendingDrop, ChangeSet appliedDrops) {
|
||||
for (Object o : appliedDrops.getChangeSetChildren()) {
|
||||
if (o instanceof DropColumn && sameColumn(pendingDrop, (DropColumn) o)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the DropTable match by table name.
|
||||
*/
|
||||
private boolean sameTable(DropTable pendingDrop, DropTable o) {
|
||||
return pendingDrop.getName().equals(o.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the DropColumns match by table and column name.
|
||||
*/
|
||||
private boolean sameColumn(DropColumn pending, DropColumn o) {
|
||||
return pending.getColumnName().equals(o.getColumnName())
|
||||
&& pending.getTableName().equals(o.getTableName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static boolean isSuppressForever(ChangeSet next) {
|
||||
return Boolean.TRUE.equals(next.isSuppressDropsForever());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public class ModelBuildBeanVisitor implements BeanVisitor {
|
||||
table.setComment(descriptor.getDbComment());
|
||||
if (descriptor.isHistorySupport()) {
|
||||
table.setWithHistory(true);
|
||||
BeanProperty whenCreated = descriptor.findWhenCreatedProperty();
|
||||
BeanProperty whenCreated = descriptor.getWhenCreatedProperty();
|
||||
if (whenCreated != null) {
|
||||
table.setWhenCreatedColumn(whenCreated.getDbColumn());
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -3,85 +3,84 @@
|
||||
<TITLE>Ebean core API</TITLE>
|
||||
</HEAD>
|
||||
<Body BGCOLOR="#ffffff">
|
||||
Core API (see <a href="Ebean.html">Ebean</a> and <a href="EbeanServer.html">EbeanServer</a>).
|
||||
Core API (see <a href="EbeanServer.html">EbeanServer</a> and <a href="Ebean.html">Ebean</a>).
|
||||
|
||||
<h3>Ebean</h3>
|
||||
<p>
|
||||
Provides the main API for fetching and persisting beans with eBean.
|
||||
</p>
|
||||
|
||||
<pre class="code">
|
||||
// EXAMPLE 1: Simple fetch
|
||||
//========================
|
||||
<pre>{@code
|
||||
// EXAMPLE 1: Simple fetch
|
||||
//========================
|
||||
|
||||
// fetch order 10
|
||||
Order order = Ebean.find(Order.class, 10);
|
||||
// fetch order 10
|
||||
Order order = Ebean.find(Order.class, 10);
|
||||
|
||||
|
||||
|
||||
// EXAMPLE 2: Fetch an Object with associations
|
||||
//=============================================
|
||||
|
||||
// fetch Customer 7 including their billing and shipping addresses
|
||||
Customer customer =
|
||||
Ebean.find(Customer.class)
|
||||
.setId(7)
|
||||
.fetch("billingAddress")
|
||||
.fetch("shippingAddress")
|
||||
.findUnique();
|
||||
|
||||
Address billAddr = customer.getBillingAddress();
|
||||
Address shipAddr = customer.getShippingAddress();
|
||||
// EXAMPLE 2: Fetch an Object with associations
|
||||
//=============================================
|
||||
|
||||
// fetch Customer 7 including their billing and shipping addresses
|
||||
Customer customer =
|
||||
Ebean.find(Customer.class)
|
||||
.setId(7)
|
||||
.fetch("billingAddress")
|
||||
.fetch("shippingAddress")
|
||||
.findUnique();
|
||||
|
||||
Address billAddr = customer.getBillingAddress();
|
||||
Address shipAddr = customer.getShippingAddress();
|
||||
|
||||
|
||||
|
||||
|
||||
// EXAMPLE 3: Create and save an Order
|
||||
//=====================================
|
||||
|
||||
// get a Customer reference so we don't hit the database
|
||||
Customer custRef = Ebean.getReference(Customer.class, 7);
|
||||
// EXAMPLE 3: Create and save an Order
|
||||
//=====================================
|
||||
|
||||
// create a new Order object
|
||||
Order newOrder = new Order();
|
||||
newOrder.setStatus(Order.Status.NEW);
|
||||
newOrder.setCustomer(custRef);
|
||||
|
||||
ArrayList orderLines = new ArrayList();
|
||||
newOrder.setLines(orderLines);
|
||||
...
|
||||
// get a Customer reference so we don't hit the database
|
||||
Customer custRef = Ebean.getReference(Customer.class, 7);
|
||||
|
||||
// add a line to the order
|
||||
Product prodRef = Ebean.getReference(Product.class, 41);
|
||||
OrderLine line = new OrderLine();
|
||||
line.setProduct(prodRef);
|
||||
line.setQuantity(10);
|
||||
orderLines.add(line);
|
||||
...
|
||||
// create a new Order object
|
||||
Order newOrder = new Order();
|
||||
newOrder.setStatus(Order.Status.NEW);
|
||||
newOrder.setCustomer(custRef);
|
||||
|
||||
// save the order and its lines in a single transaction
|
||||
// NB: assumes CascadeType.PERSIST is set on the order lines association
|
||||
Ebean.save(newOrder);
|
||||
ArrayList orderLines = new ArrayList();
|
||||
newOrder.setLines(orderLines);
|
||||
...
|
||||
|
||||
// add a line to the order
|
||||
Product prodRef = Ebean.getReference(Product.class, 41);
|
||||
OrderLine line = new OrderLine();
|
||||
line.setProduct(prodRef);
|
||||
line.setQuantity(10);
|
||||
orderLines.add(line);
|
||||
...
|
||||
|
||||
// save the order and its lines in a single transaction
|
||||
// NB: assumes CascadeType.PERSIST is set on the order lines association
|
||||
Ebean.save(newOrder);
|
||||
|
||||
|
||||
|
||||
// EXAMPLE 4: Use another database
|
||||
//=================================
|
||||
// EXAMPLE 4: Use another database
|
||||
//=================================
|
||||
|
||||
// Get access to the Human Resources EbeanServer/Database
|
||||
EbeanServer hrServer = Ebean.getServer("HR");
|
||||
|
||||
|
||||
// fetch contact 3 from the HR database
|
||||
Contact contact = hrServer.find(Contact.class, 3);
|
||||
|
||||
contact.setStatus(Contact.Status.INACTIVE);
|
||||
...
|
||||
|
||||
// save the contact back to the HR database
|
||||
hrServer.save(contact);
|
||||
|
||||
</pre>
|
||||
// Get access to the Human Resources EbeanServer/Database
|
||||
EbeanServer hrServer = Ebean.getServer("HR");
|
||||
|
||||
|
||||
// fetch contact 3 from the HR database
|
||||
Contact contact = hrServer.find(Contact.class, 3);
|
||||
|
||||
contact.setStatus(Contact.Status.INACTIVE);
|
||||
...
|
||||
|
||||
// save the contact back to the HR database
|
||||
hrServer.save(contact);
|
||||
}</pre>
|
||||
|
||||
</Body>
|
||||
</HTML>
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.avaje.ebean.plugin;
|
||||
|
||||
import com.avaje.ebean.FetchPath;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdateContext;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Doc store functions for a specific entity bean type.
|
||||
*
|
||||
* @param <T> The type of entity bean
|
||||
*/
|
||||
public interface BeanDocType<T> {
|
||||
|
||||
/**
|
||||
* Return the doc store index type for this bean type.
|
||||
*/
|
||||
String getIndexType();
|
||||
|
||||
/**
|
||||
* Return the doc store index name for this bean type.
|
||||
*/
|
||||
String getIndexName();
|
||||
|
||||
/**
|
||||
* Apply the appropriate fetch path to the query such that the query returns beans matching
|
||||
* the document store structure with the expected embedded properties.
|
||||
*/
|
||||
void applyPath(Query<T> spiQuery);
|
||||
|
||||
/**
|
||||
* Return the FetchPath for the embedded document.
|
||||
*/
|
||||
FetchPath getEmbedded(String path);
|
||||
|
||||
/**
|
||||
* For embedded 'many' properties we need a FetchPath relative to the root which is used to
|
||||
* build and replace the embedded list.
|
||||
*/
|
||||
FetchPath getEmbeddedManyRoot(String path);
|
||||
|
||||
/**
|
||||
* Return a 'raw' property mapped for the given property.
|
||||
* If none exists the given property is returned.
|
||||
*/
|
||||
String rawProperty(String property);
|
||||
|
||||
/**
|
||||
* Store the bean in the doc store index.
|
||||
* <p>
|
||||
* This somewhat assumes the bean is fetched with appropriate path properties
|
||||
* to match the expected document structure.
|
||||
*/
|
||||
void index(Object idValue, T bean, DocStoreUpdateContext txn) throws IOException;
|
||||
|
||||
/**
|
||||
* Add a delete by Id to the doc store.
|
||||
*/
|
||||
void deleteById(Object idValue, DocStoreUpdateContext txn) throws IOException;
|
||||
|
||||
/**
|
||||
* Add a embedded document update to the doc store.
|
||||
*
|
||||
* @param idValue the Id value of the bean holding the embedded document
|
||||
* @param embeddedProperty the embedded property
|
||||
* @param embeddedRawContent the content of the embedded document in JSON form
|
||||
* @param txn the doc store transaction to add the update to
|
||||
*/
|
||||
void updateEmbedded(Object idValue, String embeddedProperty, String embeddedRawContent, DocStoreUpdateContext txn) throws IOException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package com.avaje.ebean.plugin;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.IdType;
|
||||
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.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocumentMapping;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Information and methods on BeanDescriptors made available to plugins.
|
||||
*/
|
||||
public interface BeanType<T> {
|
||||
|
||||
/**
|
||||
* Return the short name of the bean type.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the full name of the bean type.
|
||||
*/
|
||||
String getFullName();
|
||||
|
||||
/**
|
||||
* Return the class type this BeanDescriptor describes.
|
||||
*/
|
||||
Class<T> getBeanType();
|
||||
|
||||
/**
|
||||
* Return the type bean for an OneToMany or ManyToOne or ManyToMany property.
|
||||
*/
|
||||
BeanType<?> getBeanTypeAtPath(String propertyName);
|
||||
|
||||
/**
|
||||
* Return all the properties for this bean type.
|
||||
*/
|
||||
Collection<? extends Property> allProperties();
|
||||
|
||||
/**
|
||||
* Return the Id property.
|
||||
*/
|
||||
Property getIdProperty();
|
||||
|
||||
/**
|
||||
* Return the when modified property if there is one defined.
|
||||
*/
|
||||
Property getWhenModifiedProperty();
|
||||
|
||||
/**
|
||||
* Return the when created property if there is one defined.
|
||||
*/
|
||||
Property getWhenCreatedProperty();
|
||||
|
||||
/**
|
||||
* Return the Property to read values from a bean.
|
||||
*/
|
||||
Property getProperty(String propertyName);
|
||||
|
||||
/**
|
||||
* Return the ExpressionPath for a given property path.
|
||||
* <p>
|
||||
* This can return a property or nested property path.
|
||||
* </p>
|
||||
*/
|
||||
ExpressionPath getExpressionPath(String path);
|
||||
|
||||
/**
|
||||
* Return true if the property is a valid known property or path for the given bean type.
|
||||
*/
|
||||
boolean isValidExpression(String property);
|
||||
|
||||
/**
|
||||
* Return the base table this bean type maps to.
|
||||
*/
|
||||
String getBaseTable();
|
||||
|
||||
/**
|
||||
* Create a new instance of the bean.
|
||||
*/
|
||||
T createBean();
|
||||
|
||||
/**
|
||||
* Return the bean id. This is the same as getBeanId() but without the generic type.
|
||||
*/
|
||||
Object beanId(Object bean);
|
||||
|
||||
/**
|
||||
* Return the id value for the given bean.
|
||||
*/
|
||||
Object getBeanId(T bean);
|
||||
|
||||
/**
|
||||
* Set the id value to the bean.
|
||||
*/
|
||||
void setBeanId(T bean, Object idValue);
|
||||
|
||||
/**
|
||||
* Return the bean persist controller.
|
||||
*/
|
||||
BeanPersistController getPersistController();
|
||||
|
||||
/**
|
||||
* Return the bean persist listener.
|
||||
*/
|
||||
BeanPersistListener getPersistListener();
|
||||
|
||||
/**
|
||||
* Return the beanFinder. Usually null unless overriding the finder.
|
||||
*/
|
||||
BeanFindController getFindController();
|
||||
|
||||
/**
|
||||
* Return the BeanQueryAdapter or null if none is defined.
|
||||
*/
|
||||
BeanQueryAdapter getQueryAdapter();
|
||||
|
||||
/**
|
||||
* Return the identity generation type.
|
||||
*/
|
||||
IdType getIdType();
|
||||
|
||||
/**
|
||||
* Return the sequence name associated to this entity bean type (if there is one).
|
||||
*/
|
||||
String getSequenceName();
|
||||
|
||||
/**
|
||||
* Return true if this bean type has doc store backing.
|
||||
*/
|
||||
boolean isDocStoreMapped();
|
||||
|
||||
/**
|
||||
* Return the DocumentMapping for this bean type.
|
||||
* <p>
|
||||
* This is the document structure and mapping options for how this bean type is mapped
|
||||
* for the document store.
|
||||
* </p>
|
||||
*/
|
||||
DocumentMapping getDocMapping();
|
||||
|
||||
/**
|
||||
* Return the doc store queueId for this bean type.
|
||||
*/
|
||||
String getDocStoreQueueId();
|
||||
|
||||
/**
|
||||
* Return the doc store support for this bean type.\
|
||||
*/
|
||||
BeanDocType<T> docStore();
|
||||
|
||||
/**
|
||||
* Add the discriminator value to the query if needed.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.avaje.ebean.plugin;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.text.StringParser;
|
||||
|
||||
/**
|
||||
* A dot notation expression path.
|
||||
*/
|
||||
public interface ExpressionPath {
|
||||
|
||||
/**
|
||||
* Return true if there is a property on the path that is a many property.
|
||||
*/
|
||||
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 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);
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@ package com.avaje.ebean.plugin;
|
||||
/**
|
||||
* A 'plugin' that wants to be configured on startup so it can use features of the EbeanServer itself.
|
||||
*/
|
||||
public interface SpiServerPlugin {
|
||||
public interface Plugin {
|
||||
|
||||
/**
|
||||
* Configure the plugin.
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.avaje.ebean.plugin;
|
||||
|
||||
/**
|
||||
* Property of a entity bean that can be read.
|
||||
*/
|
||||
public interface Property {
|
||||
|
||||
/**
|
||||
* Return the name of the property.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the value of the property on the given bean.
|
||||
*/
|
||||
Object getVal(Object bean);
|
||||
|
||||
/**
|
||||
* Return true if this is a OneToMany or ManyToMany property.
|
||||
*/
|
||||
boolean isMany();
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package com.avaje.ebean.plugin;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.IdType;
|
||||
import com.avaje.ebean.event.BeanFindController;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
|
||||
/**
|
||||
* Information and methods on BeanDescriptors made available to plugins.
|
||||
*/
|
||||
public interface SpiBeanType<T> {
|
||||
|
||||
/**
|
||||
* Return the class type this BeanDescriptor describes.
|
||||
*/
|
||||
Class<T> getBeanType();
|
||||
|
||||
/**
|
||||
* Return true if the property is a valid known property or path for the given bean type.
|
||||
*/
|
||||
boolean isValidExpression(String property);
|
||||
|
||||
/**
|
||||
* Return the base table this bean type maps to.
|
||||
*/
|
||||
String getBaseTable();
|
||||
|
||||
/**
|
||||
* Return the id value for the given bean.
|
||||
*/
|
||||
Object getBeanId(T bean);
|
||||
|
||||
/**
|
||||
* Return the bean persist controller.
|
||||
*/
|
||||
BeanPersistController getPersistController();
|
||||
|
||||
/**
|
||||
* Return the bean persist listener.
|
||||
*/
|
||||
BeanPersistListener getPersistListener();
|
||||
|
||||
/**
|
||||
* Return the beanFinder. Usually null unless overriding the finder.
|
||||
*/
|
||||
BeanFindController getFindController();
|
||||
|
||||
/**
|
||||
* Return the BeanQueryAdapter or null if none is defined.
|
||||
*/
|
||||
BeanQueryAdapter getQueryAdapter();
|
||||
|
||||
/**
|
||||
* Return the identity generation type.
|
||||
*/
|
||||
IdType getIdType();
|
||||
|
||||
/**
|
||||
* Return the sequence name associated to this entity bean type (if there is one).
|
||||
*/
|
||||
String getSequenceName();
|
||||
|
||||
}
|
||||
@@ -24,16 +24,20 @@ public interface SpiServer extends EbeanServer {
|
||||
/**
|
||||
* Return all the bean types registered on this server instance.
|
||||
*/
|
||||
List<? extends SpiBeanType<?>> getBeanTypes();
|
||||
List<? extends BeanType<?>> getBeanTypes();
|
||||
|
||||
/**
|
||||
* Return the bean type for a given entity bean class.
|
||||
*/
|
||||
<T> SpiBeanType<T> getBeanType(Class<T> beanClass);
|
||||
<T> BeanType<T> getBeanType(Class<T> beanClass);
|
||||
|
||||
/**
|
||||
* Return the bean types mapped to the given base table.
|
||||
*/
|
||||
List<? extends SpiBeanType<?>> getBeanTypes(String baseTableName);
|
||||
List<? extends BeanType<?>> getBeanTypes(String baseTableName);
|
||||
|
||||
/**
|
||||
* Return the bean type for a given doc store queueId.
|
||||
*/
|
||||
BeanType<?> getBeanTypeForQueueId(String queueId);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides text search expressions like Match, TextQueryString etc.
|
||||
*/
|
||||
package com.avaje.ebean.search;
|
||||
@@ -1,14 +1,16 @@
|
||||
package com.avaje.ebean.text;
|
||||
|
||||
import com.avaje.ebean.FetchPath;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebeaninternal.server.query.SplitName;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This is a Tree like structure of paths and properties that can be used for
|
||||
@@ -20,7 +22,7 @@ import com.avaje.ebean.Query;
|
||||
* render (JAX-RS JSON / XML).
|
||||
* </p>
|
||||
*/
|
||||
public class PathProperties {
|
||||
public class PathProperties implements FetchPath {
|
||||
|
||||
private final Map<String, Props> pathMap;
|
||||
|
||||
@@ -44,39 +46,6 @@ public class PathProperties {
|
||||
this.pathMap.put(null, rootProps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for creating copy.
|
||||
*/
|
||||
private PathProperties(PathProperties orig) {
|
||||
this.rootProps = orig.rootProps.copy(this);
|
||||
this.pathMap = new LinkedHashMap<String, Props>(orig.pathMap.size());
|
||||
Set<Entry<String, Props>> entrySet = orig.pathMap.entrySet();
|
||||
for (Entry<String, Props> e : entrySet) {
|
||||
pathMap.put(e.getKey(), e.getValue().copy(this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this instance so that it can be modified.
|
||||
* <p>
|
||||
* For example, you may want to create a copy to add extra properties to a
|
||||
* path so that they are fetching in a ORM query but perhaps not rendered by
|
||||
* default. That is, use a PathProperties for JSON or XML rendering, but
|
||||
* create a copy, add some extra properties and then use that copy to define
|
||||
* an ORM query.
|
||||
* </p>
|
||||
*/
|
||||
public PathProperties copy() {
|
||||
return new PathProperties(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are no paths defined.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return pathMap.isEmpty();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return pathMap.toString();
|
||||
}
|
||||
@@ -84,6 +53,7 @@ public class PathProperties {
|
||||
/**
|
||||
* Return true if the path is defined and has properties.
|
||||
*/
|
||||
@Override
|
||||
public boolean hasPath(String path) {
|
||||
Props props = pathMap.get(path);
|
||||
return props != null && !props.isEmpty();
|
||||
@@ -92,40 +62,38 @@ public class PathProperties {
|
||||
/**
|
||||
* Get the properties for a given path.
|
||||
*/
|
||||
public Set<String> get(String path) {
|
||||
@Override
|
||||
public Set<String> getProperties(String path) {
|
||||
Props props = pathMap.get(path);
|
||||
return props == null ? null : props.getProperties();
|
||||
}
|
||||
|
||||
public void addToPath(String path, String property) {
|
||||
getProps(path).getProperties().add(property);
|
||||
}
|
||||
|
||||
public void addNested(String prefix, PathProperties pathProps) {
|
||||
|
||||
for (Entry<String, Props> entry : pathProps.pathMap.entrySet()) {
|
||||
|
||||
String path = pathAdd(prefix, entry.getKey());
|
||||
String[] split = SplitName.split(path);
|
||||
getProps(split[0]).addProperty(split[1]);
|
||||
getProps(path).addProps(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private String pathAdd(String prefix, String key) {
|
||||
return key == null ? prefix : prefix + "." + key;
|
||||
}
|
||||
|
||||
Props getProps(String path) {
|
||||
Props props = pathMap.get(path);
|
||||
if (props == null) {
|
||||
props = new Props(this, null, path);
|
||||
pathMap.put(path, props);
|
||||
}
|
||||
props.getProperties().add(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the properties for a given path.
|
||||
*/
|
||||
public void put(String path, Set<String> properties) {
|
||||
pathMap.put(path, new Props(this, null, path, properties));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a path returning the properties set for that path.
|
||||
*/
|
||||
public Set<String> remove(String path) {
|
||||
Props props = pathMap.remove(path);
|
||||
return props == null ? null : props.getProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a shallow copy of the paths.
|
||||
*/
|
||||
public Set<String> getPaths() {
|
||||
return new LinkedHashSet<String>(pathMap.keySet());
|
||||
return props;
|
||||
}
|
||||
|
||||
public Collection<Props> getPathProps() {
|
||||
@@ -135,7 +103,7 @@ public class PathProperties {
|
||||
/**
|
||||
* Apply these path properties as fetch paths to the query.
|
||||
*/
|
||||
public void apply(Query<?> query) {
|
||||
public <T> void apply(Query<T> query) {
|
||||
|
||||
for (Entry<String, Props> entry : pathMap.entrySet()) {
|
||||
String path = entry.getKey();
|
||||
@@ -153,6 +121,40 @@ public class PathProperties {
|
||||
return rootProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the property (dot notation) is included in the PathProperties.
|
||||
*/
|
||||
public boolean includesProperty(String name) {
|
||||
|
||||
String[] split = SplitName.split(name);
|
||||
Props props = pathMap.get(split[0]);
|
||||
return (props != null && props.includes(split[1]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the property is included using a prefix.
|
||||
*/
|
||||
public boolean includesProperty(String prefix, String name) {
|
||||
return includesProperty(SplitName.add(prefix, name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the fetch path is included in the PathProperties.
|
||||
* <p>
|
||||
* The fetch path is a OneToMany or ManyToMany path in dot notation.
|
||||
* </p>
|
||||
*/
|
||||
public boolean includesPath(String path) {
|
||||
return pathMap.containsKey(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the path is included using a prefix.
|
||||
*/
|
||||
public boolean includesPath(String prefix, String name) {
|
||||
return includesPath(SplitName.add(prefix, name));
|
||||
}
|
||||
|
||||
public static class Props {
|
||||
|
||||
private final PathProperties owner;
|
||||
@@ -160,9 +162,9 @@ public class PathProperties {
|
||||
private final String parentPath;
|
||||
private final String path;
|
||||
|
||||
private final Set<String> propSet;
|
||||
private final LinkedHashSet<String> propSet;
|
||||
|
||||
private Props(PathProperties owner, String parentPath, String path, Set<String> propSet) {
|
||||
private Props(PathProperties owner, String parentPath, String path, LinkedHashSet<String> propSet) {
|
||||
this.owner = owner;
|
||||
this.path = path;
|
||||
this.parentPath = parentPath;
|
||||
@@ -173,13 +175,6 @@ public class PathProperties {
|
||||
this(owner, parentPath, path, new LinkedHashSet<String>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a shallow copy of this Props instance.
|
||||
*/
|
||||
public Props copy(PathProperties newOwner) {
|
||||
return new Props(newOwner, parentPath, path, new LinkedHashSet<String>(propSet));
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
@@ -195,7 +190,7 @@ public class PathProperties {
|
||||
/**
|
||||
* Return the properties for this property set.
|
||||
*/
|
||||
public Set<String> getProperties() {
|
||||
public LinkedHashSet<String> getProperties() {
|
||||
return propSet;
|
||||
}
|
||||
|
||||
@@ -228,15 +223,15 @@ public class PathProperties {
|
||||
/**
|
||||
* Add a child Property set.
|
||||
*/
|
||||
protected Props addChild(String subpath) {
|
||||
protected Props addChild(String subPath) {
|
||||
|
||||
subpath = subpath.trim();
|
||||
addProperty(subpath);
|
||||
subPath = subPath.trim();
|
||||
addProperty(subPath);
|
||||
|
||||
// build the subpath
|
||||
String p = path == null ? subpath : path + "." + subpath;
|
||||
Props nested = new Props(owner, path, p);
|
||||
owner.pathMap.put(p, nested);
|
||||
// build the subPath
|
||||
String fullPath = path == null ? subPath : path + "." + subPath;
|
||||
Props nested = new Props(owner, path, fullPath);
|
||||
owner.pathMap.put(fullPath, nested);
|
||||
return nested;
|
||||
}
|
||||
|
||||
@@ -246,6 +241,14 @@ public class PathProperties {
|
||||
protected void addProperty(String property) {
|
||||
propSet.add(property.trim());
|
||||
}
|
||||
|
||||
private void addProps(Props value) {
|
||||
propSet.addAll(value.propSet);
|
||||
}
|
||||
|
||||
private boolean includes(String prop) {
|
||||
return propSet.isEmpty() || propSet.contains(prop) || propSet.contains("*");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.avaje.ebean.text;
|
||||
/**
|
||||
* Parses Uri segments like :(id,name,shippingAddress(*),contacts(*)) so that
|
||||
* the response can be customised for performance.
|
||||
*
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
class PathPropertiesParser {
|
||||
@@ -50,12 +50,12 @@ class PathPropertiesParser {
|
||||
do {
|
||||
char c1 = chars[pos++];
|
||||
switch (c1) {
|
||||
case '(':
|
||||
return currentWord();
|
||||
default:
|
||||
if (pos == 1) {
|
||||
return "";
|
||||
}
|
||||
case '(':
|
||||
return currentWord();
|
||||
default:
|
||||
if (pos == 1) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
} while (pos < eof);
|
||||
throw new RuntimeException("Hit EOF while reading sectionTitle from " + startPos);
|
||||
@@ -72,28 +72,30 @@ class PathPropertiesParser {
|
||||
}
|
||||
|
||||
private void parseSection() {
|
||||
do {
|
||||
char c1 = chars[pos++];
|
||||
switch (c1) {
|
||||
case '(':
|
||||
addSubpath();
|
||||
break;
|
||||
case ',':
|
||||
addCurrentProperty();
|
||||
break;
|
||||
case ':':
|
||||
// start new section
|
||||
startPos = pos;
|
||||
return;
|
||||
case ')':
|
||||
// end of section
|
||||
addCurrentProperty();
|
||||
popSubpath();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
if (pos < eof) {
|
||||
do {
|
||||
char c1 = chars[pos++];
|
||||
switch (c1) {
|
||||
case '(':
|
||||
addSubpath();
|
||||
break;
|
||||
case ',':
|
||||
addCurrentProperty();
|
||||
break;
|
||||
case ':':
|
||||
// start new section
|
||||
startPos = pos;
|
||||
return;
|
||||
case ')':
|
||||
// end of section
|
||||
addCurrentProperty();
|
||||
popSubpath();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
} while (pos < eof);
|
||||
} while (pos < eof);
|
||||
}
|
||||
if (startPos < pos) {
|
||||
String currentWord = source.substring(startPos, pos);
|
||||
currentPathProps.addProperty(currentWord);
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
|
||||
/**
|
||||
* Provides a JSON reader that can hold a persistence context and load context while reading JSON.
|
||||
* <p>
|
||||
* This provides a mechanism such that an object loaded from JSON can have unique instances
|
||||
* by using a persistence context and also support further lazy loading (via a load context).
|
||||
* </p>
|
||||
*/
|
||||
public interface JsonBeanReader<T> {
|
||||
|
||||
/**
|
||||
* Read the JSON returning a bean.
|
||||
*/
|
||||
T read();
|
||||
|
||||
/**
|
||||
* Create a new reader taking the context from the existing one but using a new JsonParser.
|
||||
*/
|
||||
JsonBeanReader<T> forJson(JsonParser moreJson, boolean resetContext);
|
||||
|
||||
/**
|
||||
* Add a bean explicitly to the persistence context.
|
||||
*/
|
||||
void persistenceContextPut(Object beanId, T currentBean);
|
||||
|
||||
/**
|
||||
* Return the persistence context if one is being used.
|
||||
*/
|
||||
PersistenceContext getPersistenceContext();
|
||||
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
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;
|
||||
@@ -56,6 +58,26 @@ public interface JsonContext {
|
||||
*/
|
||||
<T> T toBean(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(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.
|
||||
*
|
||||
@@ -144,21 +166,21 @@ public interface JsonContext {
|
||||
void toJson(Object value, JsonGenerator generator) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Return the bean or collection as JSON string using PathProperties.
|
||||
* Return the bean or collection as JSON string using FetchPath.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
String toJson(Object value, PathProperties pathProperties) throws JsonIOException;
|
||||
String toJson(Object value, FetchPath fetchPath) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection as json to the writer using the PathProperties.
|
||||
* Write the bean or collection as json to the writer using the FetchPath.
|
||||
*/
|
||||
void toJson(Object value, Writer writer, PathProperties pathProperties) throws JsonIOException;
|
||||
void toJson(Object value, Writer writer, FetchPath fetchPath) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection to the JsonGenerator using the PathProperties.
|
||||
* Write the bean or collection to the JsonGenerator using the FetchPath.
|
||||
*/
|
||||
void toJson(Object value, JsonGenerator generator, PathProperties pathProperties) throws JsonIOException;
|
||||
void toJson(Object value, JsonGenerator generator, FetchPath fetchPath) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Deprecated in favour of using PathProperties by itself.
|
||||
@@ -203,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;
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -17,6 +19,12 @@ public class JsonReadOptions {
|
||||
|
||||
protected Object objectMapper;
|
||||
|
||||
protected boolean enableLazyLoading;
|
||||
|
||||
protected PersistenceContext persistenceContext;
|
||||
|
||||
protected Object loadContext;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
@@ -46,6 +54,25 @@ public class JsonReadOptions {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if lazy loading is enabled after the objects are loaded.
|
||||
*/
|
||||
public boolean isEnableLazyLoading() {
|
||||
return enableLazyLoading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to enable lazy loading on partially populated beans.
|
||||
* <p>
|
||||
* If this is set to true a persistence context will be created if one has
|
||||
* not already been supplied.
|
||||
* </p>
|
||||
*/
|
||||
public JsonReadOptions setEnableLazyLoading(boolean enableLazyLoading) {
|
||||
this.enableLazyLoading = enableLazyLoading;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Jackson ObjectMapper to use (if not wanted to use the objectMapper set on the ServerConfig).
|
||||
*/
|
||||
@@ -56,7 +83,38 @@ public class JsonReadOptions {
|
||||
/**
|
||||
* Set the Jackson ObjectMapper to use (if not wanted to use the objectMapper set on the ServerConfig).
|
||||
*/
|
||||
public void setObjectMapper(Object objectMapper) {
|
||||
public JsonReadOptions setObjectMapper(Object objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the persistence context to use when building the object graph from the JSON.
|
||||
*/
|
||||
public JsonReadOptions setPersistenceContext(PersistenceContext persistenceContext) {
|
||||
this.persistenceContext = persistenceContext;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the persistence context to use when marshalling JSON.
|
||||
*/
|
||||
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,11 +0,0 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Writes any scalar type known to Ebean the Jackson generator.
|
||||
*/
|
||||
public interface JsonScalar {
|
||||
|
||||
void write(String name, Object value) throws IOException;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import com.avaje.ebean.FetchPath;
|
||||
import com.avaje.ebean.config.JsonConfig;
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
|
||||
@@ -15,7 +16,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class JsonWriteOptions {
|
||||
|
||||
protected PathProperties pathProperties;
|
||||
protected FetchPath pathProperties;
|
||||
|
||||
protected Object objectMapper;
|
||||
|
||||
@@ -38,7 +39,7 @@ public class JsonWriteOptions {
|
||||
/**
|
||||
* Construct JsonWriteOptions with the given pathProperties.
|
||||
*/
|
||||
public static JsonWriteOptions pathProperties(PathProperties pathProperties) {
|
||||
public static JsonWriteOptions pathProperties(FetchPath pathProperties) {
|
||||
JsonWriteOptions o = new JsonWriteOptions();
|
||||
o.setPathProperties(pathProperties);
|
||||
return o;
|
||||
@@ -47,14 +48,14 @@ public class JsonWriteOptions {
|
||||
/**
|
||||
* Set the Map of properties to include by path.
|
||||
*/
|
||||
public void setPathProperties(PathProperties pathProperties) {
|
||||
public void setPathProperties(FetchPath pathProperties) {
|
||||
this.pathProperties = pathProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties to include by path.
|
||||
*/
|
||||
public PathProperties getPathProperties() {
|
||||
public FetchPath getPathProperties() {
|
||||
return pathProperties;
|
||||
}
|
||||
|
||||
|
||||
@@ -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).
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
/**
|
||||
* Key used for caching query plans for ORM and RawSql queries.
|
||||
*/
|
||||
public interface CQueryPlanKey {
|
||||
|
||||
/**
|
||||
* Used by read audit such that we can log read audit entries without the full sql
|
||||
* (which would make the read audit logs verbose).
|
||||
*/
|
||||
String getPartialKey();
|
||||
|
||||
}
|
||||
@@ -5,32 +5,18 @@ package com.avaje.ebeaninternal.api;
|
||||
*/
|
||||
public class HashQuery {
|
||||
|
||||
private final HashQueryPlan planHash;
|
||||
private final CQueryPlanKey planHash;
|
||||
|
||||
private final int bindHash;
|
||||
|
||||
/**
|
||||
* Create the HashQuery.
|
||||
*/
|
||||
public HashQuery(HashQueryPlan planHash, int bindHash) {
|
||||
public HashQuery(CQueryPlanKey planHash, int bindHash) {
|
||||
this.planHash = planHash;
|
||||
this.bindHash = bindHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query plan hash.
|
||||
*/
|
||||
public HashQueryPlan getPlanHash() {
|
||||
return planHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bind values hash.
|
||||
*/
|
||||
public int getBindHash() {
|
||||
return bindHash;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = 31 * planHash.hashCode();
|
||||
hc = 31 * hc + bindHash;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Used to build HashQueryPlan instances.
|
||||
*/
|
||||
@@ -9,21 +11,19 @@ public class HashQueryPlanBuilder {
|
||||
|
||||
private int bindCount;
|
||||
|
||||
private String rawSql;
|
||||
|
||||
public HashQueryPlanBuilder() {
|
||||
this.planHash = 31;
|
||||
this.planHash = 92821;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return planHash+":"+bindCount+(rawSql != null ? ":r" : "");
|
||||
return planHash+":"+bindCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a class to the hash calculation.
|
||||
*/
|
||||
public HashQueryPlanBuilder add(Class<?> cls) {
|
||||
planHash = planHash * 31 + cls.getName().hashCode();
|
||||
planHash = planHash * 92821 + cls.getName().hashCode();
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,22 @@ public class HashQueryPlanBuilder {
|
||||
* Add an object to the hash calculation.
|
||||
*/
|
||||
public HashQueryPlanBuilder add(Object object) {
|
||||
planHash = planHash * 31 + (object == null ? 0 : object.hashCode());
|
||||
planHash = planHash * 92821 + (object == null ? 0 : object.hashCode());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the set with order being important.
|
||||
*/
|
||||
public HashQueryPlanBuilder addOrdered(Set<?> set) {
|
||||
if (set == null) {
|
||||
add(false);
|
||||
} else {
|
||||
add(true);
|
||||
for (Object o : set) {
|
||||
add(o);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -39,7 +54,7 @@ public class HashQueryPlanBuilder {
|
||||
* Add an integer to the hash calculation.
|
||||
*/
|
||||
public HashQueryPlanBuilder add(int hashValue) {
|
||||
planHash = planHash * 31 + (hashValue);
|
||||
planHash = planHash * 92821 + (hashValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -47,7 +62,7 @@ public class HashQueryPlanBuilder {
|
||||
* Add a boolean to the hash calculation.
|
||||
*/
|
||||
public HashQueryPlanBuilder add(boolean booleanValue) {
|
||||
planHash = planHash * 31 + (booleanValue ? 31 : 0);
|
||||
planHash = planHash * 92821 + (booleanValue ? 92821 : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -58,19 +73,24 @@ public class HashQueryPlanBuilder {
|
||||
bindCount += extraBindCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw sql to the hash.
|
||||
*/
|
||||
public void addRawSql(String rawSql) {
|
||||
this.rawSql = rawSql;
|
||||
public void bindIfNotNull(Object someValue) {
|
||||
if (someValue != null) {
|
||||
bindCount++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and return the calculated HashQueryPlan.
|
||||
*/
|
||||
public HashQueryPlan build() {
|
||||
return new HashQueryPlan(rawSql, planHash, bindCount);
|
||||
public String build() {
|
||||
return planHash+"_"+bindCount;
|
||||
}
|
||||
|
||||
|
||||
public int getPlanHash() {
|
||||
return planHash;
|
||||
}
|
||||
|
||||
public int getBindCount() {
|
||||
return bindCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,48 +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);
|
||||
|
||||
/**
|
||||
* Register any secondary queries (+query or +lazy) with their
|
||||
* appropriate LoadBeanContext or LoadManyContext.
|
||||
* <p>
|
||||
* This is so the LoadBeanContext or LoadManyContext use the
|
||||
* defined query for +query and +lazy execution.
|
||||
* </p>
|
||||
*/
|
||||
void registerSecondaryQueries(SpiQuery<?> query);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
}
|
||||
|
||||
@@ -29,4 +29,5 @@ public interface LoadManyBuffer {
|
||||
|
||||
void configureQuery(SpiQuery<?> query);
|
||||
|
||||
boolean isUseDocStore();
|
||||
}
|
||||
@@ -144,7 +144,7 @@ public class LoadManyRequest extends LoadRequest {
|
||||
query.setLazyLoadForParents(many);
|
||||
|
||||
List<Object> idList = getParentIdList(batchSize);
|
||||
many.addWhereParentIdIn(query, idList);
|
||||
many.addWhereParentIdIn(query, idList, loadContext.isUseDocStore());
|
||||
|
||||
query.setPersistenceContext(loadContext.getPersistenceContext());
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user