mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
203
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4d49161af | ||
|
|
8a68e72305 | ||
|
|
07fe1cde6b | ||
|
|
9da5ce01a7 | ||
|
|
5bcfce9cd4 | ||
|
|
a6d276d4d3 | ||
|
|
5b100e6d37 | ||
|
|
bf75af85c1 | ||
|
|
5cf2d3c39a | ||
|
|
840c5f8992 | ||
|
|
f867cd4c01 | ||
|
|
ad17da5b36 | ||
|
|
9350155c00 | ||
|
|
8a84eaf7a7 | ||
|
|
f0fab77ff7 | ||
|
|
41aace9dc4 | ||
|
|
7c9d752c3d | ||
|
|
81531b6cda | ||
|
|
b70f3574d9 | ||
|
|
be214273cc | ||
|
|
69c2810fbe | ||
|
|
82da81116e | ||
|
|
7d5e135f56 | ||
|
|
6b05d2343b | ||
|
|
fc748ea9c1 | ||
|
|
7b8d2a2f9d | ||
|
|
f8b5a7f312 | ||
|
|
ae261d3782 | ||
|
|
d2ae044d1f | ||
|
|
03189ac92a | ||
|
|
2067568a5e | ||
|
|
57417610a6 | ||
|
|
4cec878242 | ||
|
|
2e7aec3b3d | ||
|
|
104dc599e8 | ||
|
|
e769abf737 | ||
|
|
b79bb892f7 | ||
|
|
8f93f780fd | ||
|
|
158a23a34d | ||
|
|
523ddbab63 | ||
|
|
00d4298065 | ||
|
|
4eb1aded2d | ||
|
|
221f5ad879 | ||
|
|
75e3b9276e | ||
|
|
29c51ecb95 | ||
|
|
8c535ba837 | ||
|
|
11e02710d9 | ||
|
|
658ce3c5d3 | ||
|
|
2de78cd20f | ||
|
|
1b8b05790e | ||
|
|
444b848c22 | ||
|
|
707dda636d | ||
|
|
e8a979bc9d | ||
|
|
3fb9a7414c | ||
|
|
061652a48e | ||
|
|
57b03cf86d | ||
|
|
45dbe3bb9a | ||
|
|
24037eeb73 | ||
|
|
2c6f637dab | ||
|
|
a85f9c4be8 | ||
|
|
5d9f11a362 | ||
|
|
3d484c79a2 | ||
|
|
5881047606 | ||
|
|
333eaf08c2 | ||
|
|
a1ff83e9e4 | ||
|
|
640db2267f | ||
|
|
4059034891 | ||
|
|
c58db0033d | ||
|
|
da90eccc12 | ||
|
|
524be4ce55 | ||
|
|
649c14644e | ||
|
|
c504256579 | ||
|
|
97d803e3e0 | ||
|
|
46bc09a09b | ||
|
|
fe387cf456 | ||
|
|
b4cd66e28c | ||
|
|
7c11acaf89 | ||
|
|
7b4d6f2d17 | ||
|
|
8f100f2786 | ||
|
|
6233392548 | ||
|
|
abaa1ff934 | ||
|
|
a7b239a1b7 | ||
|
|
e8c0756ee9 | ||
|
|
e5179432a0 | ||
|
|
d25123eb23 | ||
|
|
27602c15b9 | ||
|
|
bdc81bf6f4 | ||
|
|
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 | ||
|
|
84fa373728 | ||
|
|
12e6c0b139 | ||
|
|
6f702098bc | ||
|
|
ad3292b92d |
@@ -0,0 +1,9 @@
|
||||
## Expected behavior
|
||||
|
||||
## Actual behavior
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
```java
|
||||
// some java code
|
||||
```
|
||||
@@ -1,14 +1,17 @@
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm) - avaje-ebeanorm
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent) - avaje-ebeanorm-agent
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer) - avaje-ebeanorm-mavenenhancer
|
||||
# Need help?
|
||||
Post questions or issues to the Ebean google group - https://groups.google.com/forum/#!forum/ebean
|
||||
|
||||
|
||||
Ebean ORM
|
||||
==============
|
||||
[https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
|
||||
# Documentation
|
||||
Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
|
||||
|
||||
|
||||
## Maven cental links:
|
||||
[Maven central - avaje-ebeanorm](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebeanorm%22%20AND%20a%3A%22avaje-ebeanorm%22 "maven central ebeanorm")
|
||||
|
||||
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cavaje-ebeanorm "maven central ebeanorm")
|
||||
|
||||
## Current versions
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm) - avaje-ebeanorm
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent) - avaje-ebeanorm-agent
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer) - avaje-ebeanorm-mavenenhancer
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
<parent>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-javaparent</artifactId>
|
||||
<version>1.2</version>
|
||||
<artifactId>oss-parent</artifactId>
|
||||
<version>1.1</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>7.1.1</version>
|
||||
<version>7.9.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
@@ -36,9 +36,8 @@
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git</developerConnection>
|
||||
<url>https://github.com/ebean-orm/avaje-ebeanorm.git</url>
|
||||
<tag>avaje-ebeanorm-7.9.1</tag>
|
||||
</scm>
|
||||
|
||||
<dependencies>
|
||||
@@ -56,17 +55,40 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.7</version>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-datasource-api</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope for Spring boot loader classpath scanning support -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-loader</artifactId>
|
||||
<version>1.2.7.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-datasource</artifactId>
|
||||
<version>1.1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-classpath-scanner-api</artifactId>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-classpath-scanner</artifactId>
|
||||
<version>2.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>[1.7.1,1.7.99)</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope for JsonNode support -->
|
||||
@@ -77,13 +99,6 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.transaction</groupId>
|
||||
<artifactId>jta</artifactId>
|
||||
@@ -121,6 +136,8 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Test scope -->
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>oracle</groupId>-->
|
||||
<!--<artifactId>oracle-jdbc</artifactId>-->
|
||||
@@ -135,13 +152,6 @@
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>2.4.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-agentloader</artifactId>
|
||||
@@ -152,7 +162,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 +178,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>
|
||||
|
||||
@@ -204,9 +214,9 @@
|
||||
</dependencies>
|
||||
|
||||
|
||||
<!-- Enhance the meta beans -->
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
@@ -216,12 +226,12 @@
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<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>
|
||||
<id>test</id>
|
||||
<phase>process-test-classes</phase>
|
||||
@@ -258,7 +268,8 @@
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
@@ -268,12 +279,13 @@
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<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,9 +304,7 @@
|
||||
</additionalparam>
|
||||
<linksource>true</linksource>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
|
||||
</configuration>
|
||||
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
@@ -304,6 +314,7 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebeanservice.docstore.api.DocQueryRequest;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -26,13 +27,16 @@ public interface DocumentStore {
|
||||
* that will fetch a lot of beans. The default bulkBatchSize is used.
|
||||
* </p>
|
||||
*
|
||||
* @param query The query used to update the associated document store.
|
||||
* @param query The query that selects object to send to the document store.
|
||||
*/
|
||||
<T> void indexByQuery(Query<T> query);
|
||||
|
||||
/**
|
||||
* Update the associated document store index using the result of the query additionally specifying a
|
||||
* bulkBatchSize to use for sending the messages to ElasticSearch.
|
||||
*
|
||||
* @param query The query that selects object to send to the document store.
|
||||
* @param bulkBatchSize The batch size to use when bulk sending to the document store.
|
||||
*/
|
||||
<T> void indexByQuery(Query<T> query, int bulkBatchSize);
|
||||
|
||||
@@ -40,28 +44,68 @@ public interface DocumentStore {
|
||||
* Update the document store for all beans of this type.
|
||||
* <p>
|
||||
* This is the same as indexByQuery where the query has no predicates and so fetches all rows.
|
||||
* </p>
|
||||
*/
|
||||
void indexAll(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the bean by fetching it's content from the document store.
|
||||
* If the document is not found null is returned.
|
||||
* <p>
|
||||
* Typically this is called indirectly by findUnique() on the query.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer =
|
||||
* server.find(Customer.class)
|
||||
* .setUseDocStore(true)
|
||||
* .setId(42)
|
||||
* .findUnique();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Nullable
|
||||
<T> T getById(Class<T> beanType, Object id);
|
||||
<T> T find(DocQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the query against the document store returning the list.
|
||||
* Execute the find list query. This request is prepared to execute secondary queries.
|
||||
* <p>
|
||||
* Typically this is called indirectly by findList() on the query that has setUseDocStore(true).
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> newCustomers =
|
||||
* server.find(Customer.class)
|
||||
* .setUseDocStore(true)
|
||||
* .where().eq("status, Customer.Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
<T> List<T> findList(Query<T> query);
|
||||
<T> List<T> findList(DocQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the query against the document store returning the paged list.
|
||||
* <p>
|
||||
* The query should have <code>firstRow</code> or <code>maxRows</code> set prior to calling this method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Typically this is called indirectly by findPagedList() on the query that has setUseDocStore(true).
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Customer> newCustomers =
|
||||
* server.find(Customer.class)
|
||||
* .setUseDocStore(true)
|
||||
* .where().eq("status, Customer.Status.NEW)
|
||||
* .setMaxRows(50)
|
||||
* .findPagedList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
<T> PagedList<T> findPagedList(Query<T> query);
|
||||
<T> PagedList<T> findPagedList(DocQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the query against the document store with the expectation of a large set of results
|
||||
@@ -69,8 +113,59 @@ public interface DocumentStore {
|
||||
* <p>
|
||||
* For example, with the ElasticSearch doc store this uses SCROLL.
|
||||
* </p>
|
||||
* <p>
|
||||
* Typically this is called indirectly by findEach() on the query that has setUseDocStore(true).
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* server.find(Order.class)
|
||||
* .setUseDocStore(true)
|
||||
* .where()... // perhaps add predicates
|
||||
* .findEach(new QueryEachConsumer<Order>() {
|
||||
* @Override
|
||||
* public void accept(Order bean) {
|
||||
* // process the bean
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
<T> void findEach(Query<T> query, QueryEachConsumer<T> consumer);
|
||||
<T> void findEach(DocQueryRequest<T> query, QueryEachConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query against the document store with the expectation of a large set of results
|
||||
* that are processed in a scrolling resultSet fashion.
|
||||
* <p>
|
||||
* Unlike findEach() this provides the opportunity to stop iterating through the large query.
|
||||
* </p>
|
||||
* <p>
|
||||
* For example, with the ElasticSearch doc store this uses SCROLL.
|
||||
* </p>
|
||||
* <p>
|
||||
* Typically this is called indirectly by findEachWhile() on the query that has setUseDocStore(true).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* server.find(Order.class)
|
||||
* .setUseDocStore(true)
|
||||
* .where()... // perhaps add predicates
|
||||
* .findEachWhile(new QueryEachWhileConsumer<Order>() {
|
||||
* @Override
|
||||
* public void accept(Order bean) {
|
||||
* // process the bean
|
||||
*
|
||||
* // return true to continue, false to stop
|
||||
* // boolean shouldContinue = ...
|
||||
* return shouldContinue;
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
<T> void findEachWhile(DocQueryRequest<T> query, QueryEachWhileConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Process the queue entries sending updates to the document store or queuing them for later processing.
|
||||
@@ -79,17 +174,36 @@ public interface DocumentStore {
|
||||
|
||||
/**
|
||||
* Drop the index from the document store (similar to DDL drop table).
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* DocumentStore documentStore = server.docStore();
|
||||
*
|
||||
* documentStore.dropIndex("product_copy");
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
void dropIndex(String indexName);
|
||||
|
||||
/**
|
||||
* Create an index given a mapping file as a resource in the classPath (similar to DDL create table).
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* DocumentStore documentStore = server.docStore();
|
||||
*
|
||||
* // uses product_copy.mapping.json resource
|
||||
* // ... to define mappings for the index
|
||||
*
|
||||
* documentStore.createIndex("product_copy", null);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param indexName the name of the new index
|
||||
* @param alias the alias of the index
|
||||
* @param mappingResource the path of the mapping file as a resource in the classpath
|
||||
*/
|
||||
void createIndex(String indexName, String alias, String mappingResource);
|
||||
void createIndex(String indexName, String alias);
|
||||
|
||||
/**
|
||||
* Copy the index to a new index.
|
||||
@@ -97,9 +211,14 @@ public interface DocumentStore {
|
||||
* This copy process does not use the database but instead will copy from the source index to a destination index.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* long copyCount = documentStore.copyIndex(Product.class, "product_copy");
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The bean type of the source index
|
||||
* @param newIndex The name of the index to copy to
|
||||
*
|
||||
* @return the number of documents copied to the new index
|
||||
*/
|
||||
long copyIndex(Class<?> beanType, String newIndex);
|
||||
@@ -111,11 +230,41 @@ public interface DocumentStore {
|
||||
* To support this the document needs to have a <code>@WhenModified</code> property.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* long copyCount = documentStore.copyIndex(Product.class, "product_copy", sinceMillis);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The bean type of the source index
|
||||
* @param newIndex The name of the index to copy to
|
||||
*
|
||||
* @return the number of documents copied to the new index
|
||||
*/
|
||||
long copyIndex(Class<?> beanType, String newIndex, long sinceEpochMillis);
|
||||
|
||||
/**
|
||||
* Copy from a source index to a new index taking only the documents
|
||||
* matching the given query.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // predicates to select the source documents to copy
|
||||
* Query<Product> query = server.find(Product.class)
|
||||
* .where()
|
||||
* .ge("whenModified", new Timestamp(since))
|
||||
* .ge("name", "A")
|
||||
* .lt("name", "D")
|
||||
* .query();
|
||||
*
|
||||
* // copy from the source index to "product_copy" index
|
||||
* long copyCount = documentStore.copyIndex(query, "product_copy", 1000);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param query The query to select the source documents to copy
|
||||
* @param newIndex The target index to copy the documents to
|
||||
* @param bulkBatchSize The ElasticSearch bulk batch size, if 0 uses the default.
|
||||
* @return The number of documents copied to the new index.
|
||||
*/
|
||||
long copyIndex(Query<?> query, String newIndex, int bulkBatchSize);
|
||||
}
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.text.csv.CsvReader;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheStrategy;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.text.csv.CsvReader;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
|
||||
/**
|
||||
* This Ebean object is effectively a singleton that holds a map of registered
|
||||
* {@link EbeanServer}s. It additionally provides a convenient way to use the
|
||||
@@ -731,11 +728,25 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().delete(beanType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete permanent the bean given its type and id.
|
||||
*/
|
||||
public static int deletePermanent(Class<?> beanType, Object id) {
|
||||
return serverMgr.getDefaultServer().deletePermanent(beanType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete several beans given their type and id values.
|
||||
*/
|
||||
public static void deleteAll(Class<?> beanType, Collection<?> ids) {
|
||||
serverMgr.getDefaultServer().deleteAll(beanType, ids);
|
||||
public static int deleteAll(Class<?> beanType, Collection<?> ids) {
|
||||
return serverMgr.getDefaultServer().deleteAll(beanType, ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete permanent several beans given their type and id values.
|
||||
*/
|
||||
public static int deleteAllPermanent(Class<?> beanType, Collection<?> ids) {
|
||||
return serverMgr.getDefaultServer().deleteAllPermanent(beanType, ids);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1484,29 +1495,6 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().getBackgroundExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the cache warming queries on all bean types that have one defined for
|
||||
* the default/primary EbeanServer.
|
||||
* <p>
|
||||
* A cache warming query can be defined via {@link CacheStrategy}.
|
||||
* </p>
|
||||
*/
|
||||
public static void runCacheWarming() {
|
||||
serverMgr.getDefaultServer().runCacheWarming();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the cache warming query for a specific bean type for the
|
||||
* default/primary EbeanServer.
|
||||
* <p>
|
||||
* A cache warming query can be defined via {@link CacheStrategy}.
|
||||
* </p>
|
||||
*/
|
||||
public static void runCacheWarming(Class<?> beanType) {
|
||||
|
||||
serverMgr.getDefaultServer().runCacheWarming(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JsonContext for reading/writing JSON.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheStrategy;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.meta.MetaInfoManager;
|
||||
@@ -146,6 +145,17 @@ public interface EbeanServer {
|
||||
*/
|
||||
Object getBeanId(Object bean);
|
||||
|
||||
/**
|
||||
* Set the Id value onto the bean converting the type of the id value if necessary.
|
||||
* <p>
|
||||
* For example, if the id value passed in is a String but ought to be a Long or UUID etc
|
||||
* then it will automatically be converted.
|
||||
* </p>
|
||||
* @param bean The entity bean to set the id value on.
|
||||
* @param id The id value to set.
|
||||
*/
|
||||
Object setBeanId(Object bean, Object id);
|
||||
|
||||
/**
|
||||
* Return a map of the differences between two objects of the same type.
|
||||
* <p>
|
||||
@@ -1003,22 +1013,6 @@ public interface EbeanServer {
|
||||
*/
|
||||
<T> FutureList<T> findFutureList(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute find list SQL query in a background thread.
|
||||
* <p>
|
||||
* This returns a Future object which can be used to cancel, check the
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
* @param query
|
||||
* the query to execute in the background
|
||||
* @param transaction
|
||||
* the transaction (can be null).
|
||||
* @return a Future object for the list result of the query
|
||||
*/
|
||||
SqlFutureList findFutureList(SqlQuery query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query using pageIndex and pageSize.
|
||||
* <p>
|
||||
@@ -1183,40 +1177,23 @@ public interface EbeanServer {
|
||||
List<SqlRow> findList(SqlQuery query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the sql query returning a set of MapBean.
|
||||
* Execute the SqlQuery iterating a row at a time.
|
||||
* <p>
|
||||
* Generally you are able to use {@link SqlQuery#findSet()} rather than
|
||||
* explicitly calling this method. You could use this method if you wish to
|
||||
* explicitly control the transaction used for the query.
|
||||
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
|
||||
* </p>
|
||||
*
|
||||
* @param query
|
||||
* the query to execute.
|
||||
* @param transaction
|
||||
* the transaction to use (can be null).
|
||||
* @return the set of fetched MapBean.
|
||||
*
|
||||
* @see SqlQuery#findSet()
|
||||
*/
|
||||
Set<SqlRow> findSet(SqlQuery query, Transaction transaction);
|
||||
void findEach(SqlQuery query, QueryEachConsumer<SqlRow> consumer, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the sql query returning a map of MapBean.
|
||||
* Execute the SqlQuery iterating a row at a time with the ability to stop consuming part way through.
|
||||
* <p>
|
||||
* Generally you are able to use {@link SqlQuery#findMap()} rather than
|
||||
* explicitly calling this method. You could use this method if you wish to
|
||||
* explicitly control the transaction used for the query.
|
||||
* Returning false after processing a row stops the iteration through the query results.
|
||||
* </p>
|
||||
* <p>
|
||||
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
|
||||
* </p>
|
||||
*
|
||||
* @param query
|
||||
* the query to execute.
|
||||
* @param transaction
|
||||
* the transaction to use (can be null).
|
||||
* @return the set of fetched MapBean.
|
||||
*
|
||||
* @see SqlQuery#findMap()
|
||||
*/
|
||||
Map<?, SqlRow> findMap(SqlQuery query, Transaction transaction);
|
||||
void findEachWhile(SqlQuery query, QueryEachWhileConsumer<SqlRow> consumer, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the sql query returning a single MapBean or null.
|
||||
@@ -1340,6 +1317,16 @@ public interface EbeanServer {
|
||||
*/
|
||||
int delete(Class<?> beanType, Object id, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Delete permanent given the bean type and id.
|
||||
*/
|
||||
int deletePermanent(Class<?> beanType, Object id);
|
||||
|
||||
/**
|
||||
* Delete permanent given the bean type and id with an explicit transaction.
|
||||
*/
|
||||
int deletePermanent(Class<?> beanType, Object id, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Delete all the beans in the collection.
|
||||
*/
|
||||
@@ -1353,13 +1340,22 @@ public interface EbeanServer {
|
||||
/**
|
||||
* Delete several beans given their type and id values.
|
||||
*/
|
||||
void deleteAll(Class<?> beanType, Collection<?> ids);
|
||||
int deleteAll(Class<?> beanType, Collection<?> ids);
|
||||
|
||||
/**
|
||||
* Delete several beans given their type and id values with an explicit
|
||||
* transaction.
|
||||
* Delete several beans given their type and id values with an explicit transaction.
|
||||
*/
|
||||
void deleteAll(Class<?> beanType, Collection<?> ids, Transaction transaction);
|
||||
int deleteAll(Class<?> beanType, Collection<?> ids, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Delete permanent for several beans given their type and id values.
|
||||
*/
|
||||
int deleteAllPermanent(Class<?> beanType, Collection<?> ids);
|
||||
|
||||
/**
|
||||
* Delete permanent for several beans given their type and id values with an explicit transaction.
|
||||
*/
|
||||
int deleteAllPermanent(Class<?> beanType, Collection<?> ids, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute a Sql Update Delete or Insert statement. This returns the number of
|
||||
@@ -1835,22 +1831,6 @@ public interface EbeanServer {
|
||||
*/
|
||||
BackgroundExecutor getBackgroundExecutor();
|
||||
|
||||
/**
|
||||
* Run the cache warming queries on all bean types that have one defined.
|
||||
* <p>
|
||||
* A cache warming query can be defined via {@link CacheStrategy}.
|
||||
* </p>
|
||||
*/
|
||||
void runCacheWarming();
|
||||
|
||||
/**
|
||||
* Run the cache warming query for a specific bean type.
|
||||
* <p>
|
||||
* A cache warming query can be defined via {@link CacheStrategy}.
|
||||
* </p>
|
||||
*/
|
||||
void runCacheWarming(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the JsonContext for reading/writing JSON.
|
||||
* <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);
|
||||
|
||||
|
||||
@@ -209,6 +209,20 @@ public class Expr {
|
||||
return Ebean.getExpressionFactory().icontains(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* For collection properties that are empty (have not existing elements).
|
||||
*/
|
||||
public static Expression isEmpty(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isEmpty(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* For collection properties that are not empty (have existing elements).
|
||||
*/
|
||||
public static Expression isNotEmpty(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNotEmpty(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the array of values.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
@@ -240,11 +246,26 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression notExists(Query<?> subQuery);
|
||||
|
||||
/**
|
||||
* Is empty expression for collection properties.
|
||||
*/
|
||||
Expression isEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Is not empty expression for collection properties.
|
||||
*/
|
||||
Expression isNotEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Id Equal to - ID property is equal to the value.
|
||||
*/
|
||||
Expression idEq(Object value);
|
||||
|
||||
/**
|
||||
* Id IN a list of Id values.
|
||||
*/
|
||||
Expression idIn(Object... idValues);
|
||||
|
||||
/**
|
||||
* Id IN a list of Id values.
|
||||
*/
|
||||
@@ -285,6 +306,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 +365,13 @@ public interface ExpressionFactory {
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
*/
|
||||
<T> Junction<T> disjunction(Query<T> query, ExpressionList<T> parent);
|
||||
|
||||
/**
|
||||
* Return a Text query junction for MUST, SHOULD or MUST NOT.
|
||||
* <p>
|
||||
* This is doc store Elastic only.
|
||||
* </p>
|
||||
*/
|
||||
<T> Junction<T> junction(Junction.Type type, Query<T> query, ExpressionList<T> parent);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.search.Match;
|
||||
import com.avaje.ebean.search.MultiMatch;
|
||||
import com.avaje.ebean.search.TextCommonTerms;
|
||||
import com.avaje.ebean.search.TextQueryString;
|
||||
import com.avaje.ebean.search.TextSimple;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -30,7 +34,7 @@ import java.util.Set;
|
||||
*
|
||||
* @see Query#where()
|
||||
*/
|
||||
public interface ExpressionList<T> extends Serializable {
|
||||
public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Return the query that owns this expression list.
|
||||
@@ -112,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
|
||||
@@ -380,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>
|
||||
@@ -718,6 +754,16 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
ExpressionList<T> notIn(String propertyName, Query<?> subQuery);
|
||||
|
||||
/**
|
||||
* Is empty expression for collection properties.
|
||||
*/
|
||||
ExpressionList<T> isEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Is not empty expression for collection properties.
|
||||
*/
|
||||
ExpressionList<T> isNotEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Exists expression
|
||||
*/
|
||||
@@ -728,6 +774,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.
|
||||
*/
|
||||
@@ -802,6 +853,47 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
ExpressionList<T> raw(String raw);
|
||||
|
||||
/**
|
||||
* Add a match expression.
|
||||
*
|
||||
* @param propertyName The property name for the match
|
||||
* @param search The search value
|
||||
*/
|
||||
ExpressionList<T> match(String propertyName, String search);
|
||||
|
||||
/**
|
||||
* Add a match expression with options.
|
||||
*
|
||||
* @param propertyName The property name for the match
|
||||
* @param search The search value
|
||||
*/
|
||||
ExpressionList<T> match(String propertyName, String search, Match options);
|
||||
|
||||
/**
|
||||
* Add a multi-match expression.
|
||||
*/
|
||||
ExpressionList<T> multiMatch(String search, String... properties);
|
||||
|
||||
/**
|
||||
* Add a multi-match expression using options.
|
||||
*/
|
||||
ExpressionList<T> multiMatch(String search, MultiMatch options);
|
||||
|
||||
/**
|
||||
* Add a simple query string expression.
|
||||
*/
|
||||
ExpressionList<T> textSimple(String search, TextSimple options);
|
||||
|
||||
/**
|
||||
* Add a query string expression.
|
||||
*/
|
||||
ExpressionList<T> textQueryString(String search, TextQueryString options);
|
||||
|
||||
/**
|
||||
* Add common terms expression.
|
||||
*/
|
||||
ExpressionList<T> textCommonTerms(String search, TextCommonTerms options);
|
||||
|
||||
/**
|
||||
* And - join two expressions with a logical and.
|
||||
*/
|
||||
@@ -818,20 +910,168 @@ public interface ExpressionList<T> extends Serializable {
|
||||
ExpressionList<T> not(Expression exp);
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by AND's.
|
||||
* Start a list of expressions that will be joined by AND's
|
||||
* returning the expression list the expressions are added to.
|
||||
* <p>
|
||||
* This is exactly the same as conjunction();
|
||||
* </p>
|
||||
* <p>
|
||||
* Use endJunction() to end the AND junction.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that a where() clause defaults to an AND junction so
|
||||
* typically you only explicitly need to use the and() junction
|
||||
* when it is nested inside an or() or not() junction.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Example: Nested and()
|
||||
*
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .and() // nested and
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end AND junction
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction() // end AND junction
|
||||
* .orderBy().asc("name")
|
||||
* .findList();
|
||||
* }</pre>
|
||||
*/
|
||||
Junction<T> and();
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
* This is exactly the same as disjunction();
|
||||
*
|
||||
* <p>
|
||||
* Use endJunction() to end the OR junction.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Example: Use or() to join
|
||||
* // two nested and() expressions
|
||||
*
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .and()
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end AND junction
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction() // end AND junction
|
||||
* .orderBy().asc("name")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Junction<T> or();
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be wrapped by NOT.
|
||||
* <p>
|
||||
* Use endJunction() to end expressions being added to the
|
||||
* NOT expression list.
|
||||
* </p>
|
||||
*
|
||||
* <pre>@{code
|
||||
*
|
||||
* .where()
|
||||
* .not()
|
||||
* .gt("id", 1)
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end the not expressions
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <pre>@{code
|
||||
*
|
||||
* // Example: nested not()
|
||||
*
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .not()
|
||||
* .gt("id", 1)
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end the not expressions
|
||||
* .orderBy()
|
||||
* .asc("name")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Junction<T> not();
|
||||
|
||||
/**
|
||||
* Start (and return) a list of expressions that will be joined by AND's.
|
||||
* <p>
|
||||
* This is the same as and().
|
||||
* </p>
|
||||
*/
|
||||
Junction<T> conjunction();
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
* Start (and return) a list of expressions that will be joined by OR's.
|
||||
* <p>
|
||||
* This is the same as or().
|
||||
* </p>
|
||||
*/
|
||||
Junction<T> disjunction();
|
||||
|
||||
/**
|
||||
* End a Conjunction or Disjunction returning the parent expression list.
|
||||
* Start a list of expressions that will be joined by MUST.
|
||||
* <p>
|
||||
* Alternatively you can always use where() to return the top level expression
|
||||
* list.
|
||||
* This automatically makes the query a useDocStore(true) query that
|
||||
* will execute against the document store (ElasticSearch etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* This is logically similar to and().
|
||||
* </p>
|
||||
*/
|
||||
Junction<T> must();
|
||||
|
||||
/**
|
||||
* Start a list of expressions that will be joined by SHOULD.
|
||||
* <p>
|
||||
* This automatically makes the query a useDocStore(true) query that
|
||||
* will execute against the document store (ElasticSearch etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* This is logically similar to or().
|
||||
* </p>
|
||||
*/
|
||||
Junction<T> should();
|
||||
|
||||
/**
|
||||
* Start a list of expressions that will be joined by MUST NOT.
|
||||
* <p>
|
||||
* This automatically makes the query a useDocStore(true) query that
|
||||
* will execute against the document store (ElasticSearch etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* This is logically similar to not().
|
||||
* </p>
|
||||
*/
|
||||
Junction<T> mustNot();
|
||||
|
||||
/**
|
||||
* End a junction returning the parent expression list.
|
||||
* <p>
|
||||
* Ends a and(), or(), not(), must(), mustNot() or should() junction
|
||||
* such that you get the parent expression.
|
||||
* </p>
|
||||
* <p>
|
||||
* Alternatively you can always use where() to return the top level expression list.
|
||||
* </p>
|
||||
*/
|
||||
ExpressionList<T> endJunction();
|
||||
|
||||
@@ -9,70 +9,129 @@ package com.avaje.ebean;
|
||||
* <p>
|
||||
* Note: where() always takes you to the top level WHERE expression list.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* <pre>{@code
|
||||
* Query q =
|
||||
* Ebean.find(Person.class)
|
||||
* .where().disjunction()
|
||||
* .like("name", "Rob%")
|
||||
* .eq("status", Status.NEW)
|
||||
*
|
||||
* // where() returns us to the top level expression list
|
||||
* .where().gt("id", 10);
|
||||
*
|
||||
* .where()
|
||||
* .or()
|
||||
* .like("name", "Rob%")
|
||||
* .eq("status", Status.NEW)
|
||||
*
|
||||
* // where() returns us to the top level expression list
|
||||
* .where().gt("id", 10);
|
||||
*
|
||||
* // read as...
|
||||
* // where ( ((name like Rob%) or (status = NEW)) AND (id > 10) )
|
||||
* </pre>
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Note: endJunction() takes you to the parent expression list
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* <pre>{@code
|
||||
* Query q =
|
||||
* Ebean.find(Person.class)
|
||||
* .where().disjunction()
|
||||
* .like("name", "Rob%")
|
||||
* .eq("status", Status.NEW)
|
||||
* .endJunction()
|
||||
*
|
||||
* // endJunction().. takes us to the 'parent' expression list
|
||||
* // which in this case is the top level (same as where())
|
||||
*
|
||||
* .gt("id", 10);
|
||||
*
|
||||
* .where()
|
||||
* .or()
|
||||
* .like("name", "Rob%")
|
||||
* .eq("status", Status.NEW)
|
||||
* .endJunction()
|
||||
*
|
||||
* // endJunction().. takes us to the 'parent' expression list
|
||||
* // which in this case is the top level (same as where())
|
||||
*
|
||||
* .gt("id", 10);
|
||||
*
|
||||
* // read as...
|
||||
* // where ( ((name like Rob%) or (status = NEW)) AND (id > 10) )
|
||||
* </pre>
|
||||
*
|
||||
* // where ( ((name like Rob%) or (status = NEW)) AND (id > 10) )
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Example of a nested disjunction.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Query<Customer> q =
|
||||
*
|
||||
* <pre>{@code
|
||||
* Query<Customer> q =
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .disjunction()
|
||||
* .conjunction()
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction()
|
||||
* .conjunction()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction()
|
||||
* .order().asc("name");
|
||||
*
|
||||
* .or()
|
||||
* .and()
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction()
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction()
|
||||
* .order().asc("name");
|
||||
*
|
||||
* q.findList();
|
||||
* String s = q.getGeneratedSql();
|
||||
*
|
||||
*
|
||||
* // this produces an expression like:
|
||||
*
|
||||
* ( name like ? and c.anniversary = ? ) or (c.status = ? and c.id > ? )
|
||||
*
|
||||
* </pre>
|
||||
* ( name like ? and c.anniversary = ? ) or (c.status = ? and c.id > ? )
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public interface Junction<T> extends Expression, ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* The type of Junction used in full text expressions.
|
||||
*/
|
||||
enum Type {
|
||||
|
||||
/**
|
||||
* AND group.
|
||||
*/
|
||||
AND(" and ", ""),
|
||||
|
||||
/**
|
||||
* OR group.
|
||||
*/
|
||||
OR(" or ", ""),
|
||||
|
||||
/**
|
||||
* NOT group.
|
||||
*/
|
||||
NOT(" and ", "not "),
|
||||
|
||||
/**
|
||||
* Text search AND group.
|
||||
*/
|
||||
MUST("must", ""),
|
||||
|
||||
/**
|
||||
* Text search NOT group.
|
||||
*/
|
||||
MUST_NOT("must_not", ""),
|
||||
|
||||
/**
|
||||
* Text search OR group.
|
||||
*/
|
||||
SHOULD("should", "");
|
||||
|
||||
String prefix;
|
||||
String literal;
|
||||
|
||||
Type(String literal, String prefix) {
|
||||
this.literal = literal;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the literal value for this type.
|
||||
*/
|
||||
public String literal() {
|
||||
return literal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the prefix value for this type.
|
||||
*/
|
||||
public String prefix() {
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -270,6 +270,19 @@ public abstract class Model {
|
||||
return db().delete(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bean permanently without soft delete.
|
||||
* <p>
|
||||
* This is used when the bean contains a <code>@SoftDelete</code> property and we
|
||||
* want to perform a hard/permanent delete.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#deletePermanent(Object)
|
||||
*/
|
||||
public boolean deletePermanent() {
|
||||
return db().deletePermanent(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an update using this entity against the specified server.
|
||||
*/
|
||||
@@ -349,29 +362,6 @@ public abstract class Model {
|
||||
super(serverName, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Please migrate to use {@link Find} or constructor <code>Finder(Class)</code> that
|
||||
* does not have the idType parameter.
|
||||
* <p/>
|
||||
* Create with the type of the ID property and entity bean and specific server name.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public Finder(Class<I> idType, Class<T> type) {
|
||||
super(null, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Please migrate to use the constructor <code>Finder(String, Class)</code> that
|
||||
* does not have the idType parameter.
|
||||
* <p/>
|
||||
* Create with the type of the ID property and entity bean and specific server name.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public Finder(String serverName, Class<I> idType, Class<T> type) {
|
||||
super(serverName, type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -221,24 +221,39 @@ public final class OrderBy<T> implements Serializable {
|
||||
|
||||
private boolean ascending;
|
||||
|
||||
private String nulls;
|
||||
|
||||
private String highLow;
|
||||
|
||||
public Property(String property, boolean ascending) {
|
||||
this.property = property;
|
||||
this.ascending = ascending;
|
||||
}
|
||||
|
||||
public Property(String property, boolean ascending, String nulls, String highLow) {
|
||||
this.property = property;
|
||||
this.ascending = ascending;
|
||||
this.nulls = nulls;
|
||||
this.highLow = highLow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this Property with the path trimmed.
|
||||
*/
|
||||
public Property copyWithTrim(String path) {
|
||||
return new Property(property.substring(path.length() + 1), ascending);
|
||||
return new Property(property.substring(path.length() + 1), ascending, nulls, highLow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc = property.hashCode();
|
||||
hc = hc * 31 + (ascending ? 0 : 1);
|
||||
hc = hc * 31 + (nulls == null ? 0 : nulls.hashCode());
|
||||
hc = hc * 31 + (highLow == null ? 0 : highLow.hashCode());
|
||||
return hc;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
@@ -246,10 +261,11 @@ public final class OrderBy<T> implements Serializable {
|
||||
if (!(obj instanceof Property)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Property e = (Property) obj;
|
||||
return e.ascending == ascending
|
||||
&& e.property.equals(property);
|
||||
if (ascending != e.ascending) return false;
|
||||
if (!property.equals(e.property)) return false;
|
||||
if (nulls != null ? !nulls.equals(e.nulls) : e.nulls != null) return false;
|
||||
return highLow != null ? highLow.equals(e.highLow) : e.highLow == null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
@@ -257,10 +273,20 @@ public final class OrderBy<T> implements Serializable {
|
||||
}
|
||||
|
||||
public String toStringFormat() {
|
||||
if (ascending) {
|
||||
return property;
|
||||
if (nulls == null) {
|
||||
if (ascending) {
|
||||
return property;
|
||||
} else {
|
||||
return property + " desc";
|
||||
}
|
||||
} else {
|
||||
return property + " desc";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(property);
|
||||
if (!ascending) {
|
||||
sb.append(" ").append("desc");
|
||||
}
|
||||
sb.append(" ").append(nulls).append(" ").append(highLow);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,7 +308,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Return a copy of this property.
|
||||
*/
|
||||
public Property copy() {
|
||||
return new Property(property, ascending);
|
||||
return new Property(property, ascending, nulls, highLow);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -323,7 +349,6 @@ public final class OrderBy<T> implements Serializable {
|
||||
|
||||
String[] chunks = orderByClause.split(",");
|
||||
for (int i = 0; i < chunks.length; i++) {
|
||||
|
||||
String[] pairs = chunks[i].split(" ");
|
||||
Property p = parseProperty(pairs);
|
||||
if (p != null) {
|
||||
@@ -353,8 +378,12 @@ public final class OrderBy<T> implements Serializable {
|
||||
boolean asc = isAscending(wordList.get(1));
|
||||
return new Property(wordList.get(0), asc);
|
||||
}
|
||||
String m = "Expecting a max of 2 words in [" + Arrays.toString(pairs)
|
||||
+ "] but got " + wordList.size();
|
||||
if (wordList.size() == 4) {
|
||||
// nulls high or nulls low as 3rd and 4th
|
||||
boolean asc = isAscending(wordList.get(1));
|
||||
return new Property(wordList.get(0), asc, wordList.get(2), wordList.get(3));
|
||||
}
|
||||
String m = "Expecting a 1, 2 or 4 words in [" + Arrays.toString(pairs) + "] but got " + wordList;
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.avaje.ebean;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -303,8 +302,9 @@ public interface Query<T> {
|
||||
Query<T> asDraft();
|
||||
|
||||
/**
|
||||
* Execute the query including soft deleted rows.
|
||||
* Deprecated in favour of setIncludeSoftDeletes().
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> includeSoftDeletes();
|
||||
|
||||
/**
|
||||
@@ -376,6 +376,11 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> setLazyLoadBatchSize(int lazyLoadBatchSize);
|
||||
|
||||
/**
|
||||
* Execute the query including soft deleted rows.
|
||||
*/
|
||||
Query<T> setIncludeSoftDeletes();
|
||||
|
||||
/**
|
||||
* Disable read auditing for this query.
|
||||
* <p>
|
||||
@@ -1042,6 +1047,27 @@ public interface Query<T> {
|
||||
*/
|
||||
ExpressionList<T> where();
|
||||
|
||||
/**
|
||||
* Add Full text search expressions for Document store queries.
|
||||
* <p>
|
||||
* This is currently ElasticSearch only and provides the full text
|
||||
* expressions such as Match and Multi-Match.
|
||||
* </p>
|
||||
* <p>
|
||||
* This automatically makes this query a "Doc Store" query and will execute
|
||||
* against the document store (ElasticSearch).
|
||||
* </p>
|
||||
* <p>
|
||||
* Expressions added here are added to the "query" section of an ElasticSearch
|
||||
* query rather than the "filter" section.
|
||||
* </p>
|
||||
* <p>
|
||||
* Expressions added to the where() are added to the "filter" section of an
|
||||
* ElasticSearch query.
|
||||
* </p>
|
||||
*/
|
||||
ExpressionList<T> text();
|
||||
|
||||
/**
|
||||
* This applies a filter on the 'many' property list rather than the root
|
||||
* level objects.
|
||||
@@ -1373,9 +1399,4 @@ public interface Query<T> {
|
||||
*/
|
||||
Set<String> validate();
|
||||
|
||||
/**
|
||||
* Return the query in JSON form for ElasticSearch doc store.
|
||||
*/
|
||||
String asElasticQuery();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* The SqlFutureList represents the result of a background SQL query execution.
|
||||
*
|
||||
* <p>
|
||||
* It extends the java.util.concurrent.Future.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // create a query
|
||||
* String sql = ... ;
|
||||
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
|
||||
*
|
||||
* // execute the query in a background thread
|
||||
* SqlFutureList sqlFuture = sqlQuery.findFutureList();
|
||||
*
|
||||
* // do something else ... we will sleep
|
||||
* Thread.sleep(3000);
|
||||
* System.out.println("end of sleep");
|
||||
*
|
||||
* if (!futureList.isDone()){
|
||||
* // we can cancel the query execution
|
||||
* futureList.cancel(true);
|
||||
* }
|
||||
*
|
||||
* System.out.println("and... done:"+futureList.isDone());
|
||||
*
|
||||
* if (!futureList.isCancelled()){
|
||||
* // wait for the query to finish and return the list
|
||||
* List<SqlRow> list = futureList.get();
|
||||
* System.out.println("list:"+list);
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author rob
|
||||
*
|
||||
*/
|
||||
public interface SqlFutureList extends Future<List<SqlRow>> {
|
||||
|
||||
SqlQuery getQuery();
|
||||
|
||||
}
|
||||
@@ -21,45 +21,48 @@ import java.util.Set;
|
||||
* conversion support added.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // its typically a good idea to use a named query
|
||||
* // and put the sql in the orm.xml instead of in your code
|
||||
* <pre>{@code
|
||||
*
|
||||
* // its typically a good idea to use a named query
|
||||
* // and put the sql in the orm.xml instead of in your code
|
||||
*
|
||||
* String sql = "select id, name from customer where name like :name and status_code = :status";
|
||||
* String sql = "select id, name from customer where name like :name and status_code = :status";
|
||||
*
|
||||
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
|
||||
* sqlQuery.setParameter("name", "Acme%");
|
||||
* sqlQuery.setParameter("status", "ACTIVE");
|
||||
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
|
||||
* sqlQuery.setParameter("name", "Acme%");
|
||||
* sqlQuery.setParameter("status", "ACTIVE");
|
||||
*
|
||||
* // execute the query returning a List of MapBean objects
|
||||
* List<SqlRow> list = sqlQuery.findList();
|
||||
* </pre>
|
||||
* // execute the query returning a List of MapBean objects
|
||||
* List<SqlRow> list = sqlQuery.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
public interface SqlQuery extends Serializable {
|
||||
|
||||
/**
|
||||
* Cancel the query if support by the underlying database and driver.
|
||||
* <p>
|
||||
* This must be called from a different thread to the one executing the query.
|
||||
* </p>
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* Execute the query returning a list.
|
||||
*/
|
||||
List<SqlRow> findList();
|
||||
|
||||
/**
|
||||
* Execute the query returning a set.
|
||||
* Execute the SqlQuery iterating a row at a time.
|
||||
* <p>
|
||||
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
|
||||
* </p>
|
||||
*/
|
||||
Set<SqlRow> findSet();
|
||||
void findEach(QueryEachConsumer<SqlRow> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query returning a map.
|
||||
* Execute the SqlQuery iterating a row at a time with the ability to stop consuming part way through.
|
||||
* <p>
|
||||
* Returning false after processing a row stops the iteration through the query results.
|
||||
* </p>
|
||||
* <p>
|
||||
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
|
||||
* </p>
|
||||
*/
|
||||
Map<?, SqlRow> findMap();
|
||||
void findEachWhile(QueryEachWhileConsumer<SqlRow> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query returning a single row or null.
|
||||
@@ -70,19 +73,6 @@ public interface SqlQuery extends Serializable {
|
||||
*/
|
||||
SqlRow findUnique();
|
||||
|
||||
/**
|
||||
* Execute find list SQL query in a background thread.
|
||||
* <p>
|
||||
* This returns a Future object which can be used to cancel, check the
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
* @return a Future object for the list result of the query
|
||||
* @deprecated
|
||||
*/
|
||||
SqlFutureList findFutureList();
|
||||
|
||||
/**
|
||||
* The same as bind for named parameters.
|
||||
*/
|
||||
@@ -93,19 +83,6 @@ public interface SqlQuery extends Serializable {
|
||||
*/
|
||||
SqlQuery setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set a listener to process the query on a row by row basis.
|
||||
* <p>
|
||||
* It this case the rows are not loaded into the persistence context and
|
||||
* instead can be processed by the query listener.
|
||||
* </p>
|
||||
* <p>
|
||||
* Use this when you want to process a large query and do not want to hold the
|
||||
* entire query result in memory.
|
||||
* </p>
|
||||
*/
|
||||
SqlQuery setListener(SqlQueryListener queryListener);
|
||||
|
||||
/**
|
||||
* Set the index of the first row of the results to return.
|
||||
*/
|
||||
@@ -116,16 +93,6 @@ public interface SqlQuery extends Serializable {
|
||||
*/
|
||||
SqlQuery setMaxRows(int maxRows);
|
||||
|
||||
/**
|
||||
* Set the index after which fetching continues in a background thread.
|
||||
*/
|
||||
SqlQuery setBackgroundFetchAfter(int backgroundFetchAfter);
|
||||
|
||||
/**
|
||||
* Set the column to use to determine the keys for a Map.
|
||||
*/
|
||||
SqlQuery setMapKey(String mapKey);
|
||||
|
||||
/**
|
||||
* Set a timeout on this query.
|
||||
* <p>
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Provides a mechanism for processing a SqlQuery one SqlRow at a time.
|
||||
* <p>
|
||||
* This is useful when the query will return a large number of results and you
|
||||
* want to process the beans one at a time rather than have all of the beans in
|
||||
* memory at once.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* SqlQueryListener listener = ...;
|
||||
*
|
||||
* SqlQuery query = Ebean.createSqlQuery("my.large.query");
|
||||
*
|
||||
* // set the listener that will process each row one at a time
|
||||
* query.setListener(listener);
|
||||
*
|
||||
* // execute the query. Note that the returned
|
||||
* // list will be empty ... so don't bother assigning it...
|
||||
* query.findList();
|
||||
* </pre>
|
||||
*/
|
||||
public interface SqlQueryListener {
|
||||
|
||||
/**
|
||||
* Process the bean that has just been read.
|
||||
* <p>
|
||||
* Note this bean will not be added to the List Set or Map.
|
||||
* </p>
|
||||
*/
|
||||
void process(SqlRow bean);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.annotation.DocStoreEvent;
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
import com.avaje.ebean.config.DocStoreConfig;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
@@ -92,7 +92,7 @@ public interface Transaction extends Closeable {
|
||||
* to control how that is sent to the document store.
|
||||
* </p>
|
||||
*/
|
||||
void setDocStoreUpdateMode(DocStoreEvent updateMode);
|
||||
void setDocStoreMode(DocStoreMode mode);
|
||||
|
||||
/**
|
||||
* Set the batch size to use for sending messages to the document store.
|
||||
@@ -104,7 +104,7 @@ public interface Transaction extends Closeable {
|
||||
* Setting this overrides the default of {@link DocStoreConfig#getBulkBatchSize()}
|
||||
* </p>
|
||||
*/
|
||||
void setDocStoreUpdateBatchSize(int batchSize);
|
||||
void setDocStoreBatchSize(int batchSize);
|
||||
|
||||
/**
|
||||
* Explicitly turn off or on the cascading nature of save() and delete(). This
|
||||
|
||||
+22
-24
@@ -5,25 +5,36 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
/**
|
||||
* Specify the default cache use specific entity type.
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CacheStrategy {
|
||||
public @interface Cache {
|
||||
|
||||
/**
|
||||
* When set to true the bean cache will be used unless explicitly stated not
|
||||
* to in a query via {@link Query#setUseCache(boolean)}.
|
||||
*/
|
||||
boolean useBeanCache() default true;
|
||||
|
||||
/**
|
||||
* A single property that is a natural unique identifier for the bean.
|
||||
* Set this to true to enable the use of query cache.
|
||||
* <p>
|
||||
* When a findUnique query is used with this property as the sole expression
|
||||
* By default query caching is disabled as the query cache invalidates
|
||||
* frequently and so it is typically used for specific bean types and cases.
|
||||
* </p>
|
||||
*/
|
||||
boolean enableQueryCache() default false;
|
||||
|
||||
/**
|
||||
* Set this to false to disable the use of bean cache.
|
||||
* <p>
|
||||
* By default bean caching is expected so this defaults to true. We might
|
||||
* set this to false on a bean type that we want to use query caching but no
|
||||
* bean caching (and this is expected to be a rare case).
|
||||
* </p>
|
||||
*/
|
||||
boolean enableBeanCache() default true;
|
||||
|
||||
/**
|
||||
* Specify the property that is a natural unique identifier for the bean.
|
||||
* <p>
|
||||
* When a findUnique() query is used with this property as the sole expression
|
||||
* then there will be a lookup into the L2 natural key cache.
|
||||
* </p>
|
||||
*/
|
||||
@@ -42,17 +53,4 @@ public @interface CacheStrategy {
|
||||
*/
|
||||
boolean readOnly() default false;
|
||||
|
||||
/**
|
||||
* Specify a query that can be used to warm the cache.
|
||||
* <p>
|
||||
* All the beans fetched by this query will be loaded into the bean cache and
|
||||
* the query itself will be loaded into the query cache.
|
||||
* </p>
|
||||
* <p>
|
||||
* The warming query will typically be executed at startup time after a short
|
||||
* delay (defaults to a 30 seconds delay).
|
||||
* </p>
|
||||
*/
|
||||
String warmingQuery() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* Cache tuning hints for the L2 bean cache of a specific entity type.
|
||||
* <p>
|
||||
* Note that this is not useful when distributed L2 bean caches are used like
|
||||
* ElasticSearch, Hazelcast, Ignite etc.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CacheBeanTuning {
|
||||
|
||||
/**
|
||||
* The maximum size for the cache.
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxSize() default 0;
|
||||
|
||||
/**
|
||||
* The maximum time (in seconds) that a cache entry is allowed to stay in the
|
||||
* cache when it has not been accessed.
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxIdleSecs() default 0;
|
||||
|
||||
/**
|
||||
* The maximum time (in seconds) a cache entry is allowed to stay in the
|
||||
* cache.
|
||||
* <p>
|
||||
* This is not generally required as the cache entries are automatically
|
||||
* evicted when related data changes are committed.
|
||||
* </p>
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxSecsToLive() default 0;
|
||||
|
||||
/**
|
||||
* The frequency (in seconds) that cache trimming should occur.
|
||||
* <p>
|
||||
* This is a hint for cache implementations that use background cache trimming.
|
||||
* </p>
|
||||
*/
|
||||
int trimFrequency() default 0;
|
||||
}
|
||||
+2
-2
@@ -6,14 +6,14 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify cache tuning for a specific entity type.
|
||||
* Specify cache tuning for query caching on a specific entity type.
|
||||
* <p>
|
||||
* If this is not specified then the system default settings are used.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CacheTuning {
|
||||
public @interface CacheQueryTuning {
|
||||
|
||||
/**
|
||||
* The maximum size for the cache.
|
||||
+2
-2
@@ -18,7 +18,7 @@ import java.lang.annotation.Target;
|
||||
* ...
|
||||
* // include some customer details including
|
||||
* // nested billingAddress
|
||||
* @DocStoreEmbedded(doc = "id,status,name,billingAddress(*,country(*)")
|
||||
* @DocEmbedded(doc = "id,status,name,billingAddress(*,country(*)")
|
||||
* @ManyToOne
|
||||
* Customer customer;
|
||||
*
|
||||
@@ -27,7 +27,7 @@ import java.lang.annotation.Target;
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocStoreEmbedded {
|
||||
public @interface DocEmbedded {
|
||||
|
||||
/**
|
||||
* The properties on the embedded bean to include in the index.
|
||||
@@ -18,27 +18,7 @@ public @interface DocMapping {
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Set this to true to indicate that this property should be un-analysed.
|
||||
* Mapping options.
|
||||
*/
|
||||
boolean code() default false;
|
||||
|
||||
/**
|
||||
* Set this to true to get an additional un-analysed 'raw' field to use for sorting etc.
|
||||
*/
|
||||
boolean sortable() default false;
|
||||
|
||||
/**
|
||||
* Set to true to have the property additionally stored separately from _source.
|
||||
*/
|
||||
boolean store() default false;
|
||||
|
||||
/**
|
||||
* Set a boost value specific to this property.
|
||||
*/
|
||||
float boost() default 1;
|
||||
|
||||
/**
|
||||
* Set a value to use instead of null.
|
||||
*/
|
||||
String nullValue() default "";
|
||||
DocProperty options();
|
||||
}
|
||||
|
||||
@@ -36,4 +36,75 @@ public @interface DocProperty {
|
||||
* Set a value to use instead of null.
|
||||
*/
|
||||
String nullValue() default "";
|
||||
|
||||
/**
|
||||
* Set this to false to exclude this from the _all property.
|
||||
*/
|
||||
boolean includeInAll() default true;
|
||||
|
||||
/**
|
||||
* The analyzer to use.
|
||||
*/
|
||||
String analyzer() default "";
|
||||
|
||||
/**
|
||||
* The analyzer to use for searches.
|
||||
*/
|
||||
String searchAnalyzer() default "";
|
||||
|
||||
/**
|
||||
* The index options for this property.
|
||||
*/
|
||||
Option options() default Option.DEFAULT;
|
||||
|
||||
/**
|
||||
* Set this to false such that doc values are not stored separately for this property.
|
||||
*/
|
||||
boolean docValues() default true;
|
||||
|
||||
/**
|
||||
* Set a copyTo field.
|
||||
*/
|
||||
String copyTo() default "";
|
||||
|
||||
/**
|
||||
* Set to false to disable the field from indexing, it will only be get/set in _source.
|
||||
*/
|
||||
boolean enabled() default true;
|
||||
|
||||
/**
|
||||
* Set to false such that norms are not stored.
|
||||
*/
|
||||
boolean norms() default true;
|
||||
|
||||
/**
|
||||
* Index options for a property.
|
||||
*/
|
||||
enum Option {
|
||||
|
||||
/**
|
||||
* Only index the doc number.
|
||||
*/
|
||||
DOCS,
|
||||
|
||||
/**
|
||||
* Doc number and term frequencies are indexed.
|
||||
*/
|
||||
FREQS,
|
||||
|
||||
/**
|
||||
* Doc number, term frequencies and term positions are indexed.
|
||||
*/
|
||||
POSITIONS,
|
||||
|
||||
/**
|
||||
* Doc number, term frequencies, term positions and start/end offsets are indexed.
|
||||
*/
|
||||
OFFSETS,
|
||||
|
||||
/**
|
||||
* Use the default which means analysed string properties use POSITIONS as the default and all other types use DOCS.
|
||||
*/
|
||||
DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,22 +45,22 @@ public @interface DocStore {
|
||||
/**
|
||||
* Specify the behavior when bean Insert, Update, Delete events occur.
|
||||
*/
|
||||
DocStoreEvent persist() default DocStoreEvent.DEFAULT;
|
||||
DocStoreMode persist() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Insert occurs.
|
||||
*/
|
||||
DocStoreEvent insert() default DocStoreEvent.DEFAULT;
|
||||
DocStoreMode insert() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Update occurs.
|
||||
*/
|
||||
DocStoreEvent update() default DocStoreEvent.DEFAULT;
|
||||
DocStoreMode update() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Delete occurs.
|
||||
*/
|
||||
DocStoreEvent delete() default DocStoreEvent.DEFAULT;
|
||||
DocStoreMode delete() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify to include only some properties in the doc store document.
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ package com.avaje.ebean.annotation;
|
||||
* for later processing rather than look to update ElasticSearch at that time.
|
||||
* </p>
|
||||
*/
|
||||
public enum DocStoreEvent {
|
||||
public enum DocStoreMode {
|
||||
|
||||
/**
|
||||
* Add the event to the queue for processing later (delaying the update to the document store).
|
||||
@@ -1,19 +0,0 @@
|
||||
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 explicit ConcurrencyMode for entity bean.
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EntityConcurrencyMode {
|
||||
|
||||
/**
|
||||
* The ConcurrencyMode value.
|
||||
*/
|
||||
ConcurrencyMode value();
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* For mapping the values of an Enum to and from Database values.
|
||||
* <p>
|
||||
* Also refer to the {@link EnumValue} approach which probably the preferred now
|
||||
* (preferred over using this EnumMapping annotation).
|
||||
* </p>
|
||||
* <p>
|
||||
* Both of the approaches defined in the JPA have significant problems!!!
|
||||
* </p>
|
||||
* <p>
|
||||
* Using the ordinal value is VERY RISKY because that depends on the compile
|
||||
* order of the enum values. Aka if you change the order of the enum values you
|
||||
* have changed their ordinal values and now your DB values are WRONG - a HUGE
|
||||
* disaster!!!.
|
||||
* </p>
|
||||
* <p>
|
||||
* Using the String values of enums is fairly restrictive because in a Database
|
||||
* these values are usually truncated into short codes (e.g. "A" short for
|
||||
* "ACTIVE") so space used in the database is minimised. Making your enum names
|
||||
* match the database values would give them very short less meaningful names -
|
||||
* not a great solution.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can use this annotation to control the mapping of your enums to database
|
||||
* values.
|
||||
* </p>
|
||||
* <p>
|
||||
* The design of this using nameValuePairs is not optimal for safety or
|
||||
* refactoring so if you have a better solution I'm all ears. The other
|
||||
* solutions would probably involve modifying each enumeration with a method
|
||||
* which may be ok.
|
||||
* </p>
|
||||
* <p>
|
||||
* An example mapping the UserState enum.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* ...
|
||||
* @EnumMapping(nameValuePairs="NEW=N, ACTIVE=A, INACTIVE=I")
|
||||
* public enum UserState {
|
||||
* NEW,
|
||||
* ACTIVE,
|
||||
* INACTIVE;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see EnumValue
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EnumMapping {
|
||||
|
||||
/**
|
||||
* A comma delimited list of name=value pairs.
|
||||
* <p>
|
||||
* e.g. "ACTIVE=A, INACTIVE=I, NEW=N".
|
||||
* </p>
|
||||
* <p>
|
||||
* Where ACTIVE, INACTIVE and NEW are the enumeration values and "A", "I" and
|
||||
* "N" are the database values.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is not really an optimal approach so if you have a better one I'm all
|
||||
* ears - thanks.
|
||||
* </p>
|
||||
*/
|
||||
String nameValuePairs();
|
||||
|
||||
/**
|
||||
* Defaults to mapping values to database VARCHAR type. If this is set to true
|
||||
* then the values will be converted to INTEGER and mapped to the database
|
||||
* integer type.
|
||||
* <p>
|
||||
* e.g. "ACTIVE=1, INACTIVE=0, NEW=2".
|
||||
* </p>
|
||||
*/
|
||||
boolean integerType() default false;
|
||||
|
||||
/**
|
||||
* The length of DB column if mapping to string values.
|
||||
*/
|
||||
int length() default 0;
|
||||
}
|
||||
@@ -6,19 +6,13 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify explicit sql for multiple select statements. Need to use this if you
|
||||
* have more than one SqlSelect for a given bean.
|
||||
* Mark and entity bean that is used solely via RawSql.
|
||||
* <p>
|
||||
* FUTURE: Support explicit sql for SqlInsert, SqlUpdate and SqlDelete.
|
||||
* This means the entity bean has no base table specified (via @Table).
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Sql {
|
||||
|
||||
/**
|
||||
* The sql select statements.
|
||||
*/
|
||||
SqlSelect[] select() default { @SqlSelect };
|
||||
|
||||
}
|
||||
|
||||
@@ -1,298 +0,0 @@
|
||||
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;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
/**
|
||||
* Specify an explicit sql select statement to use for querying an entity bean.
|
||||
* <p>
|
||||
* The reason for using explicit sql is that you want better control over the
|
||||
* exact sql or sql that Ebean does not generate for you (such as group by,
|
||||
* union, intersection, window functions, recursive queries).
|
||||
* </p>
|
||||
* <p>
|
||||
* An example of two sql select queries deployed on the ReportTopic entity bean.
|
||||
* The first one has no name specified so it becomes the default query. The
|
||||
* second query extends the first adding a where clause with a named parameter.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* ...
|
||||
* @Entity
|
||||
* @Sql(select = {
|
||||
* @SqlSelect(query =
|
||||
* "select t.id, t.title, count(p.id) as score "+
|
||||
* "from f_topic t "+
|
||||
* "join f_topic_post p on p.topic_id = t.id "+
|
||||
* "group by t.id, t.title"),
|
||||
* @SqlSelect(
|
||||
* name = "with.title",
|
||||
* extend = "default",
|
||||
* debug = true,
|
||||
* where = "title like :likeTitle")
|
||||
* })
|
||||
* public class ReportTopic
|
||||
* @Id Integer id;
|
||||
* String title;
|
||||
* Double score;
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* An example using the first "default" query.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* List<ReportTopic> list =
|
||||
* Ebean.find(ReportTopic.class)
|
||||
* .having().gt("score", 0)
|
||||
* .findList();
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* The resulting sql, note the having clause has been added.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* select t.id, t.title, count(p.id) as score
|
||||
* from f_topic t join f_topic_post p on p.topic_id = t.id
|
||||
* group by t.id, t.title
|
||||
* having count(p.id) > ?
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* An example using the second query. Note the named parameter "likeTitle" must
|
||||
* be set.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* List<ReportTopic> list =
|
||||
* Ebean.find(ReportTopic.class, "with.title")
|
||||
* .set("likeTitle", "a%")
|
||||
* .findList();
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Ebean tries to parse the sql in the query to determine 4 things
|
||||
* <li>Location for inserting WHERE expressions (if required)</li>
|
||||
* <li>Location for inserting HAVING expressions (if required)</li>
|
||||
* <li>Mapping of columns to bean properties</li>
|
||||
* <li>The order by clause</li>
|
||||
* </p>
|
||||
* <p>
|
||||
* If Ebean is unable to parse out this information (perhaps because the sql
|
||||
* contains multiple select from keywords etc) then you need to manually specify
|
||||
* it.
|
||||
* </p>
|
||||
* <p>
|
||||
* Insert ${where} or ${andWhere} into the location where Ebean can insert any
|
||||
* expressions added to the where clause. Use ${andWhere} if the sql already has
|
||||
* the WHERE keyword and Ebean will instead start with a AND keyword.
|
||||
* </p>
|
||||
* <p>
|
||||
* Insert ${having} or ${andHaving} into the location where Ebean can insert any
|
||||
* expressions added to the having clause. Use ${andHaving} if the sql already
|
||||
* has a HAVING keyword and Ebean will instead start with a AND keyword.
|
||||
* </p>
|
||||
* <p>
|
||||
* Use the columnMapping property if Ebean is unable to determine the columns
|
||||
* and map them to bean properties.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example with ${andWhere} & ${having}.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* @SqlSelect(
|
||||
* name = "explicit.where",
|
||||
* query =
|
||||
* "select t.id, t.title, count(p.id) as score "+
|
||||
* "from f_topic t, f_topic_post p "+
|
||||
* "where p.topic_id = t.id ${andWhere} "+
|
||||
* "group by t.id, t.title ${having}"),
|
||||
* </pre>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Deprecated
|
||||
public @interface SqlSelect {
|
||||
|
||||
/**
|
||||
* The name of the query. If left blank this is assumed to be the default
|
||||
* query for this bean type.
|
||||
* <p>
|
||||
* This will default to "default" and in that case becomes the default query
|
||||
* used for the bean.
|
||||
* </p>
|
||||
*/
|
||||
String name() default "default";
|
||||
|
||||
/**
|
||||
* The tableAlias used when adding where expressions to the query.
|
||||
*/
|
||||
String tableAlias() default "";
|
||||
|
||||
/**
|
||||
* The sql select statement.
|
||||
* <p>
|
||||
* If this query <em>extends</em> another then this string is appended to the
|
||||
* parent query string. Often when using <em>extend</em> you will leave the
|
||||
* query part blank and just specify a where and/or having clauses.
|
||||
* </p>
|
||||
* <p>
|
||||
* This sql <em>CAN NOT</em> contain named parameters. You have to put these
|
||||
* in the separate where and/or having sections.
|
||||
* </p>
|
||||
* <p>
|
||||
* Ebean automatically tries to determine the location in the sql string for
|
||||
* putting in additional where or having clauses. If Ebean is unable to
|
||||
* successfully determine this then you have to explicitly specify these
|
||||
* locations by including
|
||||
* <em>${where} or ${andWhere} and ${having} or ${andHaving}</em> in the sql.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>${where}</b> location of where clause (and will add WHERE ... ) <br/>
|
||||
* Use this when there is no where clause in the sql. If expressions are added
|
||||
* to the where clause Ebean will put them in at this location starting with
|
||||
* the WHERE keyword.
|
||||
* <p>
|
||||
* <p>
|
||||
* <b>${andWhere}</b> <br/>
|
||||
* Use this instead of ${where} if there IS an existing where clause in the
|
||||
* sql. Ebean will add the expressions starting with the AND keyword.
|
||||
* <p>
|
||||
* <b>${having}</b> location of having clause (and will add HAVING... ) <br/>
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>${andHaving}</b> <br/>
|
||||
* Use this instead of ${having} when there IS an existing HAVING clause.
|
||||
* Ebean will add the expressions starting with the AND keyword.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can include one of ${where} OR ${andWhere} but not both.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can include one of ${having} OR ${andHaving} but not both.
|
||||
* </p>
|
||||
*/
|
||||
String query() default "";
|
||||
|
||||
/**
|
||||
* Specify the name of a sql-select query that this one 'extends'.
|
||||
* <p>
|
||||
* When a query is extended the sql query contents are appended together. The
|
||||
* where and having clauses are NOT appended but overridden.
|
||||
* </p>
|
||||
*/
|
||||
String extend() default "";
|
||||
|
||||
/**
|
||||
* Specify a where clause typically containing named parameters.
|
||||
* <p>
|
||||
* If a where clause is specified with named parameters then they will need to
|
||||
* be set on the query via {@link Query#setParameter(String, Object)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* In the example below the query specifies a where clause that includes a
|
||||
* named parameter "likeTitle".
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* ...
|
||||
* @Entity
|
||||
* @Sql(select = {
|
||||
* ...
|
||||
* @SqlSelect(
|
||||
* name = "with.title",
|
||||
* extend = "default",
|
||||
* debug = true,
|
||||
* where = "title like :likeTitle")
|
||||
* })
|
||||
* public class ReportTopic
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Example use of the above named query.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<ReportTopic> query0 = Ebean.createQuery(ReportTopic.class, "with.title");
|
||||
*
|
||||
* query0.set("likeTitle", "Bana%");
|
||||
*
|
||||
* List<ReportTopic> list0 = query0.findList();
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
String where() default "";
|
||||
|
||||
/**
|
||||
* Specify a having clause typically containing named parameters.
|
||||
* <p>
|
||||
* If a having clause is specified with named parameters then they will need
|
||||
* to be set on the query via {@link Query#setParameter(String, Object)}.
|
||||
* </p>
|
||||
*/
|
||||
String having() default "";
|
||||
|
||||
/**
|
||||
* (Optional) Explicitly specify column to property mapping.
|
||||
* <p>
|
||||
* This is required when Ebean is unable to parse the sql. This could occur if
|
||||
* the sql contains multiple select keywords etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* Specify the columns and property names they map to in the format.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* column1 propertyName1, column2 propertyName2, ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Optionally put a AS keyword between the column and property.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // the AS keyword is optional
|
||||
* column1 AS propertyName1, column2 propertyName2, ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* <b>column</b> should contain the table alias if there is one
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>propertyName</b> should match the property name.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Example mapping 5 columns to properties.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* columnMapping="t.id, t.bug_body description, t.bug_title as title, count(p.id) as scoreValue",
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Without this set Ebean will parse the sql looking for the select clause and
|
||||
* try to map the columns to property names. It is expected that Ebean will
|
||||
* not be able to successfully parse some sql and for those cases you should
|
||||
* specify the column to property mapping explicitly.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
String columnMapping() default "";
|
||||
|
||||
/**
|
||||
* Set this to true to have debug output when Ebean parses the sql-select.
|
||||
*/
|
||||
boolean debug() default false;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* Annotate an entity bean with @View to indicates the bean is based on a view.
|
||||
* <p>
|
||||
* As such typically the view is defined in <code>extra-ddl.xml</code> using
|
||||
* <code>create or replace view ...</code>.
|
||||
* </p>
|
||||
* <p>
|
||||
* When using extra-ddl.xml Ebean will run the resulting DDL script after the
|
||||
* <code>create-all</code> DDL (which is typically used during development) and for
|
||||
* DB Migration will copy the scripts as <code>repeatable migration scripts</code> that
|
||||
* will be run by FlywayDb (or Ebean's own migration runner) when their MD5 hash changes.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface View {
|
||||
|
||||
/**
|
||||
* The name of the view this entity bean is based on.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Tables this view is dependent on.
|
||||
* <p>
|
||||
* This is used with l2 caching to invalidate the query cache. Changes to these
|
||||
* tables invalidate the query cache for the entity based on this view.
|
||||
* </p>
|
||||
*/
|
||||
String[] dependentTables() 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.
|
||||
*/
|
||||
|
||||
@@ -12,7 +12,7 @@ public interface PersistenceContext {
|
||||
/**
|
||||
* Put the entity bean into the PersistenceContext.
|
||||
*/
|
||||
void put(Object id, Object bean);
|
||||
void put(Class<?> rootType, Object id, Object bean);
|
||||
|
||||
/**
|
||||
* Put the entity bean into the PersistenceContext if one is not already
|
||||
@@ -22,19 +22,19 @@ public interface PersistenceContext {
|
||||
* returns null.
|
||||
* </p>
|
||||
*/
|
||||
Object putIfAbsent(Object id, Object bean);
|
||||
Object putIfAbsent(Class<?> rootType, Object id, Object bean);
|
||||
|
||||
/**
|
||||
* Return an object given its type and unique id.
|
||||
*/
|
||||
Object get(Class<?> beanType, Object uid);
|
||||
Object get(Class<?> rootType, Object uid);
|
||||
|
||||
/**
|
||||
* Get the bean from the persistence context also checked to see if it had
|
||||
* been previously deleted (if so then you also can't hit the L2 cache to
|
||||
* fetch the bean for this particular persistence context).
|
||||
*/
|
||||
WithOption getWithOption(Class<?> beanType, Object uid);
|
||||
WithOption getWithOption(Class<?> rootType, Object uid);
|
||||
|
||||
/**
|
||||
* Clear all the references.
|
||||
@@ -44,22 +44,22 @@ public interface PersistenceContext {
|
||||
/**
|
||||
* Clear all the references for a given type of entity bean.
|
||||
*/
|
||||
void clear(Class<?> beanType);
|
||||
void clear(Class<?> rootType);
|
||||
|
||||
/**
|
||||
* Clear the reference to a specific entity bean.
|
||||
*/
|
||||
void clear(Class<?> beanType, Object uid);
|
||||
void clear(Class<?> rootType, Object uid);
|
||||
|
||||
/**
|
||||
* Clear the reference as a result of an entity being deleted.
|
||||
*/
|
||||
void deleted(Class<?> beanType, Object id);
|
||||
void deleted(Class<?> rootType, Object id);
|
||||
|
||||
/**
|
||||
* Return the number of beans of the given type in the persistence context.
|
||||
*/
|
||||
int size(Class<?> beanType);
|
||||
int size(Class<?> rootType);
|
||||
|
||||
/**
|
||||
* Wrapper on a bean to also indicate if a bean has been deleted.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
/**
|
||||
* Utility to find the root bean type.
|
||||
*/
|
||||
public class PersistenceContextUtil {
|
||||
|
||||
/**
|
||||
* Find and return the root bean type for the given class.
|
||||
*/
|
||||
public static Class<?> root(Class<?> beanType) {
|
||||
Class<?> parent = beanType.getSuperclass();
|
||||
while (parent != null && parent.isAnnotationPresent(Entity.class)) {
|
||||
beanType = parent;
|
||||
parent = parent.getSuperclass();
|
||||
}
|
||||
return beanType;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
|
||||
/**
|
||||
* Represents part of the "L2" server side cache.
|
||||
* <p>
|
||||
@@ -17,27 +15,6 @@ import com.avaje.ebean.EbeanServer;
|
||||
*/
|
||||
public interface ServerCache {
|
||||
|
||||
/**
|
||||
* Just after a cache is created this init method is called. This is so that a
|
||||
* cache implementation can make use of the BackgroundExecutor service to
|
||||
* trim/cleanup itself or use the EbeanServer to populate itself.
|
||||
* <p>
|
||||
* This method is called after the cache is constructed but before the cache
|
||||
* is made available for use.
|
||||
* </p>
|
||||
*/
|
||||
void init(EbeanServer ebeanServer);
|
||||
|
||||
/**
|
||||
* Return the configuration options for this cache.
|
||||
*/
|
||||
ServerCacheOptions getOptions();
|
||||
|
||||
/**
|
||||
* Update the configuration options for this cache.
|
||||
*/
|
||||
void setOptions(ServerCacheOptions options);
|
||||
|
||||
/**
|
||||
* Return the value given the key.
|
||||
*/
|
||||
|
||||
+1
-14
@@ -1,26 +1,13 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
|
||||
/**
|
||||
* Defines method for constructing caches for beans and queries.
|
||||
*/
|
||||
public interface ServerCacheFactory {
|
||||
|
||||
/**
|
||||
* Just after the ServerCacheFactory is constructed this method is called
|
||||
* passing the EbeanServer.
|
||||
* <p>
|
||||
* This is so that a cache implementation can utilise the EbeanServer to
|
||||
* populate itself or use the BackgroundExecutor service to schedule periodic
|
||||
* cache trimming/cleanup.
|
||||
* </p>
|
||||
*/
|
||||
void init(EbeanServer ebeanServer);
|
||||
|
||||
/**
|
||||
* Create the cache for the given type with options.
|
||||
*/
|
||||
ServerCache createCache(String cacheKey, ServerCacheOptions cacheOptions);
|
||||
ServerCache createCache(ServerCacheType type, String cacheKey, ServerCacheOptions cacheOptions);
|
||||
|
||||
}
|
||||
|
||||
+3
-15
@@ -1,25 +1,10 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
|
||||
/**
|
||||
* The cache service for server side caching of beans and query results.
|
||||
*/
|
||||
public interface ServerCacheManager {
|
||||
|
||||
/**
|
||||
* This method is called just after the construction of the
|
||||
* ServerCacheManager.
|
||||
* <p>
|
||||
* The EbeanServer is provided so that cache implementations can make use of
|
||||
* EbeanServer and BackgroundExecutor for automatically populating and
|
||||
* background trimming of the cache.
|
||||
* </p>
|
||||
*/
|
||||
void init(EbeanServer server);
|
||||
|
||||
void setCaching(Class<?> beanType, boolean useCache);
|
||||
|
||||
/**
|
||||
* Return true if there is an active bean cache for this type of bean.
|
||||
*/
|
||||
@@ -35,6 +20,9 @@ public interface ServerCacheManager {
|
||||
*/
|
||||
ServerCache getBeanCache(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the cache for associated many properties of a bean type.
|
||||
*/
|
||||
ServerCache getCollectionIdsCache(Class<?> beanType, String propertyName);
|
||||
|
||||
/**
|
||||
|
||||
+13
-12
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheTuning;
|
||||
import com.avaje.ebean.annotation.CacheQueryTuning;
|
||||
import com.avaje.ebean.annotation.CacheBeanTuning;
|
||||
|
||||
/**
|
||||
* Options for controlling a cache.
|
||||
@@ -22,23 +23,23 @@ public class ServerCacheOptions {
|
||||
/**
|
||||
* Create from the cacheTuning deployment annotation.
|
||||
*/
|
||||
public ServerCacheOptions(CacheTuning cacheTuning) {
|
||||
public ServerCacheOptions(CacheBeanTuning tuning) {
|
||||
this.maxSize = tuning.maxSize();
|
||||
this.maxIdleSecs = tuning.maxIdleSecs();
|
||||
this.maxSecsToLive = tuning.maxSecsToLive();
|
||||
this.trimFrequency = tuning.trimFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from the cacheTuning deployment annotation.
|
||||
*/
|
||||
public ServerCacheOptions(CacheQueryTuning cacheTuning) {
|
||||
this.maxSize = cacheTuning.maxSize();
|
||||
this.maxIdleSecs = cacheTuning.maxIdleSecs();
|
||||
this.maxSecsToLive = cacheTuning.maxSecsToLive();
|
||||
this.trimFrequency = cacheTuning.trimFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create merging default options with the deployment specified ones.
|
||||
*/
|
||||
public ServerCacheOptions(ServerCacheOptions defaults) {
|
||||
this.maxSize = defaults.getMaxSize();
|
||||
this.maxIdleSecs = defaults.getMaxIdleSecs();
|
||||
this.maxSecsToLive = defaults.getMaxIdleSecs();
|
||||
this.trimFrequency = defaults.getTrimFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any settings from the default settings that have not already been
|
||||
* specifically set.
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
/**
|
||||
* The plugin interface that creates a ServerCacheFactory.
|
||||
*/
|
||||
public interface ServerCachePlugin {
|
||||
|
||||
/**
|
||||
* Create the ServerCacheFactory given the server config and background executor service.
|
||||
*/
|
||||
ServerCacheFactory create(ServerConfig config, BackgroundExecutor executor);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
/**
|
||||
* The type of L2 caches.
|
||||
*/
|
||||
public enum ServerCacheType {
|
||||
|
||||
/**
|
||||
* Bean cache.
|
||||
*/
|
||||
BEAN,
|
||||
|
||||
/**
|
||||
* Natural key cache.
|
||||
*/
|
||||
NATURAL_KEY,
|
||||
|
||||
/**
|
||||
* Collection Ids for Many properties.
|
||||
*/
|
||||
COLLECTION_IDS,
|
||||
|
||||
/**
|
||||
* Query cache.
|
||||
*/
|
||||
QUERY
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
@@ -64,6 +65,15 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
list.add((E) bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void loadFrom(BeanCollection<?> other) {
|
||||
if (list == null) {
|
||||
list = new ArrayList<E>();
|
||||
}
|
||||
list.addAll((Collection<? extends E>) other.getActualDetails());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalAdd(Object bean) {
|
||||
if (list == null) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
@@ -51,6 +52,14 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
return !touched && (map == null || map.isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void loadFrom(BeanCollection<?> other) {
|
||||
BeanMap<K,E> otherMap = (BeanMap<K,E>)other;
|
||||
internalPutNull();
|
||||
map.putAll(otherMap.getActualMap());
|
||||
}
|
||||
|
||||
public void internalPutNull() {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
@@ -57,6 +58,15 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
set.add((E) bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void loadFrom(BeanCollection<?> other) {
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<E>();
|
||||
}
|
||||
set.addAll((Collection<? extends E>) other.getActualDetails());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void internalAddWithCheck(Object bean) {
|
||||
if (set == null || !set.contains(bean)) {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* Helper to find classes taking into account the context class loader.
|
||||
*/
|
||||
@@ -29,6 +33,13 @@ public class ClassLoadConfig {
|
||||
return isPresent("java.time.LocalDate");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Java7 is present.
|
||||
*/
|
||||
public boolean isJava7Present() {
|
||||
return isPresent("java.nio.file.Path");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the Joda types are available and should be supported.
|
||||
*/
|
||||
@@ -70,6 +81,13 @@ public class ClassLoadConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resources for the given name.
|
||||
*/
|
||||
public Enumeration<URL> getResources(String name) throws IOException {
|
||||
return context.getResources(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given class is present.
|
||||
*/
|
||||
@@ -122,6 +140,13 @@ public class ClassLoadConfig {
|
||||
return (loader != null) ? loader: callerLoader;
|
||||
}
|
||||
|
||||
Enumeration<URL> getResources(String name) throws IOException {
|
||||
if (preferredLoader != null) {
|
||||
return preferredLoader.getResources(name);
|
||||
}
|
||||
return contextLoader().getResources(name);
|
||||
}
|
||||
|
||||
Class<?> forName(String name) throws ClassNotFoundException {
|
||||
|
||||
if (preferredLoader != null) {
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import com.avaje.ebean.dbmigration.DbMigration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Configuration for the DB migration processing.
|
||||
*/
|
||||
@@ -58,6 +60,11 @@ public class DbMigrationConfig {
|
||||
|
||||
protected String applySuffix = ".sql";
|
||||
|
||||
/**
|
||||
* Set this to "V" to be compatible with FlywayDB.
|
||||
*/
|
||||
protected String applyPrefix = "";
|
||||
|
||||
protected String modelSuffix = ".model.xml";
|
||||
|
||||
protected boolean includeGeneratedFileComment;
|
||||
@@ -67,6 +74,36 @@ public class DbMigrationConfig {
|
||||
*/
|
||||
protected String generatePendingDrop;
|
||||
|
||||
/**
|
||||
* For running migration the DB table that holds migration execution status.
|
||||
*/
|
||||
protected String metaTable = "db_migration";
|
||||
|
||||
/**
|
||||
* Flag set to true means to run any outstanding migrations on startup.
|
||||
*/
|
||||
protected boolean runMigration;
|
||||
|
||||
/**
|
||||
* Comma and equals delimited key/value placeholders to replace in DDL scripts.
|
||||
*/
|
||||
protected String runPlaceholders;
|
||||
|
||||
/**
|
||||
* Map of key/value placeholders to replace in DDL scripts.
|
||||
*/
|
||||
protected Map<String,String> runPlaceholderMap;
|
||||
|
||||
/**
|
||||
* DB user used to run the DB migration.
|
||||
*/
|
||||
protected String dbUser;
|
||||
|
||||
/**
|
||||
* DB password used to run the DB migration.
|
||||
*/
|
||||
protected String dbPassword;
|
||||
|
||||
/**
|
||||
* Return the DB platform to generate migration DDL for.
|
||||
*
|
||||
@@ -145,6 +182,20 @@ public class DbMigrationConfig {
|
||||
this.applySuffix = applySuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the apply prefix.
|
||||
*/
|
||||
public String getApplyPrefix() {
|
||||
return applyPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the apply prefix. This might be set to "V" for use with FlywayDB.
|
||||
*/
|
||||
public void setApplyPrefix(String applyPrefix) {
|
||||
this.applyPrefix = applyPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the generated file comment should be included.
|
||||
*/
|
||||
@@ -199,10 +250,119 @@ public class DbMigrationConfig {
|
||||
this.modelPath = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the table name that holds the migration run details
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public String getMetaTable() {
|
||||
return metaTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table name that holds the migration run details
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public void setMetaTable(String metaTable) {
|
||||
this.metaTable = metaTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a comma and equals delimited placeholders that are substituted in SQL scripts when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public String getRunPlaceholders() {
|
||||
// environment properties take precedence
|
||||
String placeholders = readEnvironment("ddl.migration.placeholders");
|
||||
if (placeholders != null) {
|
||||
return placeholders;
|
||||
}
|
||||
return runPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a comma and equals delimited placeholders that are substituted in SQL scripts when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public void setRunPlaceholders(String runPlaceholders) {
|
||||
this.runPlaceholders = runPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of placeholder values that are substituted in SQL scripts when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public Map<String, String> getRunPlaceholderMap() {
|
||||
return runPlaceholderMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a map of placeholder values that are substituted when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public void setRunPlaceholderMap(Map<String, String> runPlaceholderMap) {
|
||||
this.runPlaceholderMap = runPlaceholderMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the DB migration should be run on startup.
|
||||
*/
|
||||
public boolean isRunMigration() {
|
||||
// environment properties take precedence
|
||||
String run = readEnvironment("ddl.migration.run");
|
||||
if (run != null) {
|
||||
return "true".equalsIgnoreCase(run.trim());
|
||||
}
|
||||
return runMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to run the DB migration on startup.
|
||||
*/
|
||||
public void setRunMigration(boolean runMigration) {
|
||||
this.runMigration = runMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB user to use for running DB migrations.
|
||||
*/
|
||||
public String getDbUser() {
|
||||
// environment properties take precedence
|
||||
String user = readEnvironment("ddl.migration.user");
|
||||
if (user != null) {
|
||||
return user;
|
||||
}
|
||||
return dbUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB user to use for running DB migrations.
|
||||
*/
|
||||
public void setDbUser(String dbUser) {
|
||||
this.dbUser = dbUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB password to use for running DB migrations.
|
||||
*/
|
||||
public String getDbPassword() {
|
||||
String user = readEnvironment("ddl.migration.password");
|
||||
if (user != null) {
|
||||
return user;
|
||||
}
|
||||
return dbPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB password to use for running DB migrations.
|
||||
*/
|
||||
public void setDbPassword(String dbPassword) {
|
||||
this.dbPassword = dbPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from the PropertiesWrapper.
|
||||
*/
|
||||
public void loadSettings(PropertiesWrapper properties) {
|
||||
public void loadSettings(PropertiesWrapper properties, String serverName) {
|
||||
|
||||
migrationPath = properties.get("migration.migrationPath", migrationPath);
|
||||
if (properties.getBoolean("migration.singleDirectory", false)) {
|
||||
@@ -210,6 +370,7 @@ public class DbMigrationConfig {
|
||||
} else {
|
||||
modelPath = properties.get("migration.modelPath", modelPath);
|
||||
}
|
||||
applyPrefix = properties.get("migration.applyPrefix", applyPrefix);
|
||||
applySuffix = properties.get("migration.applySuffix", applySuffix);
|
||||
modelSuffix = properties.get("migration.modelSuffix", modelSuffix);
|
||||
includeGeneratedFileComment = properties.getBoolean("migration.includeGeneratedFileComment", includeGeneratedFileComment);
|
||||
@@ -220,6 +381,18 @@ public class DbMigrationConfig {
|
||||
generate = properties.getBoolean("migration.generate", generate);
|
||||
version = properties.get("migration.version", version);
|
||||
name = properties.get("migration.name", name);
|
||||
|
||||
runMigration = properties.getBoolean("migration.run", runMigration);
|
||||
metaTable = properties.get("migration.metaTable", metaTable);
|
||||
runPlaceholders = properties.get("migration.placeholders", runPlaceholders);
|
||||
|
||||
String adminUser = properties.get("datasource."+serverName+".username", dbUser);
|
||||
adminUser = properties.get("datasource."+serverName+".adminusername", adminUser);
|
||||
dbUser = properties.get("migration.dbuser", adminUser);
|
||||
|
||||
String adminPwd = properties.get("datasource."+serverName+".password", dbPassword);
|
||||
adminPwd = properties.get("datasource."+serverName+".adminpassword", adminPwd);
|
||||
dbPassword = properties.get("migration.dbpassword", adminPwd);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,42 +1,70 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.annotation.DocStoreEvent;
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
|
||||
/**
|
||||
* Configuration for the Document store (ElasticSearch) integration.
|
||||
* Configuration for the Document store integration (e.g. ElasticSearch).
|
||||
*/
|
||||
public class DocStoreConfig {
|
||||
|
||||
/**
|
||||
* True when the Document store integration is active/on.
|
||||
*/
|
||||
boolean active;
|
||||
protected boolean active;
|
||||
|
||||
/**
|
||||
* When true the Document store should drop and re-create any document mapping (like DDL).
|
||||
* Set to true means Ebean will generate mapping files on startup.
|
||||
*/
|
||||
boolean dropCreate;
|
||||
protected boolean generateMapping;
|
||||
|
||||
/**
|
||||
* When true the Document store should drop and re-create document indexes.
|
||||
*/
|
||||
protected boolean dropCreate;
|
||||
|
||||
/**
|
||||
* When true the Document store should create any document indexes that don't already exist.
|
||||
*/
|
||||
protected boolean create;
|
||||
|
||||
/**
|
||||
* The URL of the Document store server. For example: http://localhost:9200.
|
||||
*/
|
||||
String url;
|
||||
protected String url;
|
||||
|
||||
/**
|
||||
* The default mode used by indexes.
|
||||
*/
|
||||
DocStoreEvent persist = DocStoreEvent.UPDATE;
|
||||
protected DocStoreMode persist = DocStoreMode.UPDATE;
|
||||
|
||||
/**
|
||||
* The default batch size to use for the Bulk API calls.
|
||||
*/
|
||||
int bulkBatchSize = 1000;
|
||||
protected int bulkBatchSize = 1000;
|
||||
|
||||
/**
|
||||
* Resource path for the Document store mapping files.
|
||||
*/
|
||||
protected String mappingPath;
|
||||
|
||||
/**
|
||||
* Suffix used for mapping files.
|
||||
*/
|
||||
protected String mappingSuffix;
|
||||
|
||||
/**
|
||||
* Location of resources that mapping files are generated into.
|
||||
*/
|
||||
protected String pathToResources = "src/main/resources";
|
||||
|
||||
/**
|
||||
* Return true if the Document store (ElasticSearch) integration is active.
|
||||
*/
|
||||
public boolean isActive() {
|
||||
String systemValue = System.getProperty("ebean.docstore.active");
|
||||
if (systemValue != null) {
|
||||
return Boolean.parseBoolean(systemValue);
|
||||
}
|
||||
return active;
|
||||
}
|
||||
|
||||
@@ -48,24 +76,134 @@ public class DocStoreConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the document store should recreate mappings.
|
||||
* Return the URL to the Document store.
|
||||
*/
|
||||
public String getUrl() {
|
||||
String systemValue = System.getProperty("ebean.docstore.url");
|
||||
if (systemValue != null) {
|
||||
return systemValue;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL to the Document store server.
|
||||
* <p>
|
||||
* For a local ElasticSearch server this would be: http://localhost:9200
|
||||
*/
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Ebean should generate mapping files on server startup.
|
||||
*/
|
||||
public boolean isGenerateMapping() {
|
||||
return generateMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if Ebean should generate mapping files on server startup.
|
||||
*/
|
||||
public void setGenerateMapping(boolean generateMapping) {
|
||||
this.generateMapping = generateMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the document store should recreate mapped indexes.
|
||||
*/
|
||||
public boolean isDropCreate() {
|
||||
return dropCreate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the document store should recreate mappings.
|
||||
* Set to true if the document store should recreate mapped indexes.
|
||||
*/
|
||||
public void setDropCreate(boolean dropCreate) {
|
||||
this.dropCreate = dropCreate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create true if the document store should create mapped indexes that don't yet exist.
|
||||
* This is only used if dropCreate is false.
|
||||
*/
|
||||
public boolean isCreate() {
|
||||
return create;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the document store should create mapped indexes that don't yet exist.
|
||||
* This is only used if dropCreate is false.
|
||||
*/
|
||||
public void setCreate(boolean create) {
|
||||
this.create = create;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default batch size to use for calls to the Bulk API.
|
||||
*/
|
||||
public int getBulkBatchSize() {
|
||||
return bulkBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default batch size to use for calls to the Bulk API.
|
||||
* <p>
|
||||
* The batch size can be set on a transaction via {@link com.avaje.ebean.Transaction#setDocStoreBatchSize(int)}.
|
||||
* </p>
|
||||
*/
|
||||
public void setBulkBatchSize(int bulkBatchSize) {
|
||||
this.bulkBatchSize = bulkBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mapping path.
|
||||
*/
|
||||
public String getMappingPath() {
|
||||
return mappingPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mapping path.
|
||||
*/
|
||||
public void setMappingPath(String mappingPath) {
|
||||
this.mappingPath = mappingPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mapping suffix.
|
||||
*/
|
||||
public String getMappingSuffix() {
|
||||
return mappingSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mapping suffix.
|
||||
*/
|
||||
public void setMappingSuffix(String mappingSuffix) {
|
||||
this.mappingSuffix = mappingSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the relative file system path to resources when generating mapping files.
|
||||
*/
|
||||
public String getPathToResources() {
|
||||
return pathToResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the relative file system path to resources when generating mapping files.
|
||||
*/
|
||||
public void setPathToResources(String pathToResources) {
|
||||
this.pathToResources = pathToResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default behavior for when Insert, Update and Delete events occur on beans that have an associated
|
||||
* Document store.
|
||||
*/
|
||||
public DocStoreEvent getPersist() {
|
||||
public DocStoreMode getPersist() {
|
||||
return persist;
|
||||
}
|
||||
|
||||
@@ -87,44 +225,10 @@ public class DocStoreConfig {
|
||||
* you don't want Ebean to do anything when the data changes.
|
||||
* </p>
|
||||
*/
|
||||
public void setPersist(DocStoreEvent persist) {
|
||||
public void setPersist(DocStoreMode persist) {
|
||||
this.persist = persist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL to the Document store.
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL to the Document store server.
|
||||
*
|
||||
* For a local ElasticSearch server this would be: http://localhost:9200
|
||||
*/
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the default batch size to use for calls to the Bulk API.
|
||||
*/
|
||||
public int getBulkBatchSize() {
|
||||
return bulkBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default batch size to use for calls to the Bulk API.
|
||||
* <p>
|
||||
* The batch size can be set on a transaction via {@link com.avaje.ebean.Transaction#setDocStoreUpdateBatchSize(int)}.
|
||||
* </p>
|
||||
*/
|
||||
public void setBulkBatchSize(int bulkBatchSize) {
|
||||
this.bulkBatchSize = bulkBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load settings specified in properties files.
|
||||
*/
|
||||
@@ -132,7 +236,13 @@ public class DocStoreConfig {
|
||||
|
||||
active = properties.getBoolean("docstore.active", active);
|
||||
url = properties.get("docstore.url", url);
|
||||
persist = properties.getEnum(DocStoreEvent.class, "docstore.persist", persist);
|
||||
persist = properties.getEnum(DocStoreMode.class, "docstore.persist", persist);
|
||||
bulkBatchSize = properties.getInt("docstore.bulkBatchSize", bulkBatchSize);
|
||||
generateMapping = properties.getBoolean("docstore.generateMapping", generateMapping);
|
||||
dropCreate = properties.getBoolean("docstore.dropCreate", dropCreate);
|
||||
create = properties.getBoolean("docstore.create", create);
|
||||
mappingPath = properties.get("docstore.mappingPath", mappingPath);
|
||||
mappingSuffix = properties.get("docstore.mappingSuffix", mappingSuffix);
|
||||
pathToResources = properties.get("docstore.pathToResources", pathToResources);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.avaje.ebean.PersistenceContextScope;
|
||||
import com.avaje.ebean.annotation.Encrypted;
|
||||
import com.avaje.ebean.cache.ServerCacheFactory;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.cache.ServerCachePlugin;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncrypt;
|
||||
import com.avaje.ebean.event.BeanFindController;
|
||||
@@ -22,11 +23,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.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
@@ -81,6 +85,12 @@ public class ServerConfig {
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Typically configuration type objects that are passed by this ServerConfig
|
||||
* to plugins. For example - IgniteConfiguration passed to Ignite plugin.
|
||||
*/
|
||||
private Map<String,Object> serviceObject = new HashMap<String, Object>();
|
||||
|
||||
private ContainerConfig containerConfig;
|
||||
|
||||
/**
|
||||
@@ -215,6 +225,11 @@ public class ServerConfig {
|
||||
|
||||
private boolean eagerFetchLobs;
|
||||
|
||||
/**
|
||||
* Timezone used to get/set Timestamp values via JDBC.
|
||||
*/
|
||||
private String dataTimeZone;
|
||||
|
||||
private boolean ddlGenerate;
|
||||
|
||||
private boolean ddlRun;
|
||||
@@ -342,7 +357,7 @@ public class ServerConfig {
|
||||
|
||||
private DbEncrypt dbEncrypt;
|
||||
|
||||
private ServerCacheFactory serverCacheFactory;
|
||||
private ServerCachePlugin serverCachePlugin;
|
||||
|
||||
private ServerCacheManager serverCacheManager;
|
||||
|
||||
@@ -396,12 +411,34 @@ public class ServerConfig {
|
||||
|
||||
private String jodaLocalTimeMode;
|
||||
|
||||
/**
|
||||
* Set to true to globally disable L2 caching (typically for performance testing).
|
||||
*/
|
||||
private boolean disableL2Cache;
|
||||
|
||||
/**
|
||||
* Construct a Server Configuration for programmatically creating an EbeanServer.
|
||||
*/
|
||||
public ServerConfig() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a service object into configuration such that it can be passed to a plugin.
|
||||
* <p>
|
||||
* For example, put IgniteConfiguration in to be passed to the Ignite plugin.
|
||||
* </p>
|
||||
*/
|
||||
public void putServiceObject(String key, Object configObject) {
|
||||
serviceObject.put(key, configObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the service object given the key.
|
||||
*/
|
||||
public Object getServiceObject(String key) {
|
||||
return serviceObject.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Jackson JsonFactory to use.
|
||||
@@ -810,6 +847,23 @@ public class ServerConfig {
|
||||
this.migrationConfig = migrationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time zone to use when reading/writing Timestamps via JDBC.
|
||||
* <p>
|
||||
* When set a Calendar object is used in JDBC calls when reading/writing Timestamp objects.
|
||||
* </p>
|
||||
*/
|
||||
public String getDataTimeZone() {
|
||||
return System.getProperty("ebean.dataTimeZone", dataTimeZone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time zone to use when reading/writing Timestamps via JDBC.
|
||||
*/
|
||||
public void setDataTimeZone(String dataTimeZone) {
|
||||
this.dataTimeZone = dataTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the suffix appended to the base table to derive the view that contains the union
|
||||
* of the base table and the history table in order to support asOf queries.
|
||||
@@ -885,17 +939,17 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ServerCacheFactory.
|
||||
* Return the ServerCachePlugin.
|
||||
*/
|
||||
public ServerCacheFactory getServerCacheFactory() {
|
||||
return serverCacheFactory;
|
||||
public ServerCachePlugin getServerCachePlugin() {
|
||||
return serverCachePlugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ServerCacheFactory to use.
|
||||
* Set the ServerCachePlugin to use.
|
||||
*/
|
||||
public void setServerCacheFactory(ServerCacheFactory serverCacheFactory) {
|
||||
this.serverCacheFactory = serverCacheFactory;
|
||||
public void setServerCachePlugin(ServerCachePlugin serverCachePlugin) {
|
||||
this.serverCachePlugin = serverCachePlugin;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1391,8 +1445,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;
|
||||
@@ -2246,18 +2298,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 for the same reason as above - preserve existing behaviour but let it be overridden.
|
||||
* This is broken out to allow overridden behaviour.
|
||||
*/
|
||||
protected void loadAutoTuneSettings(PropertiesWrapper p) {
|
||||
autoTuneConfig.loadSettings(p);
|
||||
@@ -2268,7 +2320,7 @@ public class ServerConfig {
|
||||
*/
|
||||
protected void loadSettings(PropertiesWrapper p) {
|
||||
|
||||
migrationConfig.loadSettings(p);
|
||||
migrationConfig.loadSettings(p, name);
|
||||
|
||||
namingConvention = createNamingConvention(p, namingConvention);
|
||||
if (namingConvention != null) {
|
||||
@@ -2287,8 +2339,9 @@ public class ServerConfig {
|
||||
if (docStoreConfig == null) {
|
||||
docStoreConfig = new DocStoreConfig();
|
||||
}
|
||||
docStoreConfig.loadSettings(p);
|
||||
loadDocStoreSettings(p);
|
||||
|
||||
disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache);
|
||||
explicitTransactionBeginMode = p.getBoolean("explicitTransactionBeginMode", explicitTransactionBeginMode);
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
|
||||
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager);
|
||||
@@ -2300,7 +2353,7 @@ public class ServerConfig {
|
||||
encryptDeployManager = createInstance(p, EncryptDeployManager.class, "encryptDeployManager", encryptDeployManager);
|
||||
encryptor = createInstance(p, Encryptor.class, "encryptor", encryptor);
|
||||
dbEncrypt = createInstance(p, DbEncrypt.class, "dbEncrypt", dbEncrypt);
|
||||
serverCacheFactory = createInstance(p, ServerCacheFactory.class, "serverCacheFactory", serverCacheFactory);
|
||||
serverCachePlugin = createInstance(p, ServerCachePlugin.class, "serverCachePlugin", serverCachePlugin);
|
||||
serverCacheManager = createInstance(p, ServerCacheManager.class, "serverCacheManager", serverCacheManager);
|
||||
cacheWarmingDelay = p.getInt("cacheWarmingDelay", cacheWarmingDelay);
|
||||
classPathReaderClassName = p.get("classpathreader");
|
||||
@@ -2339,6 +2392,7 @@ public class ServerConfig {
|
||||
changeLogIncludeInserts = p.getBoolean("changeLogIncludeInserts", changeLogIncludeInserts);
|
||||
expressionEqualsWithNullAsNoop = p.getBoolean("expressionEqualsWithNullAsNoop", expressionEqualsWithNullAsNoop);
|
||||
|
||||
dataTimeZone = p.get("dataTimeZone", dataTimeZone);
|
||||
asOfViewSuffix = p.get("asOfViewSuffix", asOfViewSuffix);
|
||||
asOfSysPeriod = p.get("asOfSysPeriod", asOfSysPeriod);
|
||||
historyTableSuffix = p.get("historyTableSuffix", historyTableSuffix);
|
||||
@@ -2477,6 +2531,20 @@ public class ServerConfig {
|
||||
this.expressionEqualsWithNullAsNoop = expressionEqualsWithNullAsNoop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if L2 cache is disabled.
|
||||
*/
|
||||
public boolean isDisableL2Cache() {
|
||||
return disableL2Cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to disable L2 caching. Typically useful in performance testing.
|
||||
*/
|
||||
public void setDisableL2Cache(boolean disableL2Cache) {
|
||||
this.disableL2Cache = disableL2Cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify how UUID is stored.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -9,7 +9,12 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Database platform specific settings.
|
||||
@@ -18,7 +23,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 +76,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.
|
||||
*/
|
||||
@@ -167,6 +176,10 @@ public class DatabasePlatform {
|
||||
public DatabasePlatform() {
|
||||
}
|
||||
|
||||
public void configure(Properties properties) {
|
||||
// by default do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the DatabasePlatform.
|
||||
* <p>
|
||||
@@ -291,6 +304,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 +445,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>
|
||||
@@ -497,4 +531,28 @@ public class DatabasePlatform {
|
||||
return disallowBatchOnCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the table exists.
|
||||
*/
|
||||
public boolean tableExists(Connection connection, String catalog, String schema, String table) throws SQLException {
|
||||
|
||||
DatabaseMetaData metaData = connection.getMetaData();
|
||||
ResultSet tables = metaData.getTables(catalog, schema, table, null);
|
||||
try {
|
||||
return tables.next();
|
||||
} finally {
|
||||
close(tables);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the resultSet.
|
||||
*/
|
||||
protected void close(ResultSet resultSet) {
|
||||
try {
|
||||
resultSet.close();
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error closing resultSet", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* DB Column default values mapping to database platform specific literals.
|
||||
*/
|
||||
public class DbDefaultValue {
|
||||
|
||||
/**
|
||||
* The key for FALSE.
|
||||
*/
|
||||
public static final String FALSE = "false";
|
||||
|
||||
/**
|
||||
* The key for TRUE.
|
||||
*/
|
||||
public static final String TRUE = "true";
|
||||
|
||||
/**
|
||||
* The key for the NOW / current timestamp.
|
||||
*/
|
||||
public static final String NOW = "now";
|
||||
|
||||
protected Map<String,String> map = new LinkedHashMap<String,String>();
|
||||
|
||||
/**
|
||||
* Set the DB now function.
|
||||
*/
|
||||
public void setNow(String dbFunction) {
|
||||
put(NOW, dbFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB false literal.
|
||||
*/
|
||||
public void setFalse(String dbFalseLiteral) {
|
||||
put(FALSE, dbFalseLiteral);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB true literal.
|
||||
*/
|
||||
public void setTrue(String dbTrueLiteral) {
|
||||
put(TRUE, dbTrueLiteral);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an translation entry.
|
||||
*/
|
||||
public void put(String dbLiteral, String dbTranslated) {
|
||||
map.put(dbLiteral, dbTranslated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the DB default literal to platform specific type or function.
|
||||
* <p>
|
||||
* This is intended for the DB column default clause in DDL.
|
||||
* </p>
|
||||
*/
|
||||
public String convert(String dbDefaultLiteral) {
|
||||
if (dbDefaultLiteral == null) {
|
||||
return null;
|
||||
}
|
||||
String val = map.get(dbDefaultLiteral);
|
||||
return val != null ? val : dbDefaultLiteral;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,9 +14,10 @@ public class H2Platform extends DatabasePlatform {
|
||||
super();
|
||||
this.name = "h2";
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
this.platformDdl = new H2Ddl(this.dbTypeMap, dbIdentity);
|
||||
this.platformDdl = new H2Ddl(this);
|
||||
this.historySupport = new H2HistorySupport();
|
||||
this.nativeUuidType = true;
|
||||
this.dbDefaultValue.setNow("now()");
|
||||
|
||||
// only support getGeneratedKeys with non-batch JDBC
|
||||
// so generally use SEQUENCE instead of IDENTITY for H2
|
||||
|
||||
@@ -15,7 +15,7 @@ public class HsqldbPlatform extends DatabasePlatform {
|
||||
super();
|
||||
this.name = "hsqldb";
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
this.platformDdl = new HsqldbDdl(dbTypeMap, dbIdentity);
|
||||
this.platformDdl = new HsqldbDdl(this);
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
|
||||
@@ -25,7 +25,7 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
|
||||
this.idInExpandedForm = true;
|
||||
this.selectCountWithAlias = true;
|
||||
this.sqlLimiter = new MsSqlServer2005SqlLimiter();
|
||||
this.platformDdl = new MsSqlServerDdl(dbTypeMap, dbIdentity);
|
||||
this.platformDdl = new MsSqlServerDdl(this);
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
@@ -25,7 +25,7 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
this.likeClause = "like ? escape''";
|
||||
this.selectCountWithAlias = true;
|
||||
this.dbEncrypt = new MySqlDbEncrypt();
|
||||
this.platformDdl = new MySqlDdl(this.dbTypeMap, this.dbIdentity);
|
||||
this.platformDdl = new MySqlDdl(this);
|
||||
this.historySupport = new MySqlHistorySupport();
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
|
||||
@@ -18,7 +18,7 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
this.maxConstraintNameLength = 30;
|
||||
this.dbEncrypt = new OracleDbEncrypt();
|
||||
this.sqlLimiter = new RownumSqlLimiter();
|
||||
this.platformDdl = new Oracle10Ddl(this.dbTypeMap, this.dbIdentity);
|
||||
this.platformDdl = new Oracle10Ddl(this);
|
||||
this.historySupport = new OracleDbHistorySupport();
|
||||
|
||||
// Not using getGeneratedKeys as instead we will
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.avaje.ebean.dbmigration.ddlgeneration.platform.PostgresDdl;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Types;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Postgres v9 specific platform.
|
||||
@@ -27,7 +28,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);
|
||||
@@ -50,6 +51,7 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(Types.DOUBLE, new DbType("float"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 38));
|
||||
dbTypeMap.put(Types.TIMESTAMP, new DbType("timestamptz"));
|
||||
|
||||
dbTypeMap.put(Types.BINARY, dbBytea);
|
||||
dbTypeMap.put(Types.VARBINARY, dbBytea);
|
||||
@@ -58,7 +60,16 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(Types.CLOB, dbTypeText);
|
||||
dbTypeMap.put(Types.LONGVARBINARY, dbBytea);
|
||||
dbTypeMap.put(Types.LONGVARCHAR, dbTypeText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Properties properties) {
|
||||
super.configure(properties);
|
||||
String tsType = properties.getProperty("ebean.postgres.timestamp");
|
||||
if (tsType != null) {
|
||||
// set timestamp type to "timestamp" without time zone
|
||||
dbTypeMap.put(Types.TIMESTAMP, new DbType(tsType));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -25,10 +25,14 @@ import com.avaje.ebean.dbmigration.model.ModelContainer;
|
||||
import com.avaje.ebean.dbmigration.model.ModelDiff;
|
||||
import com.avaje.ebean.dbmigration.model.PlatformDdlWriter;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.extraddl.model.DdlScript;
|
||||
import com.avaje.ebeaninternal.extraddl.model.ExtraDdl;
|
||||
import com.avaje.ebeaninternal.extraddl.model.ExtraDdlXmlReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -42,7 +46,7 @@ import java.util.List;
|
||||
* and drop objects (drop tables, drop columns).
|
||||
* </p>
|
||||
* <p>
|
||||
* This does not run the migration or ddl scripts but just generates them.
|
||||
* This does not run the migration or ddl scripts but just generates them.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
@@ -98,7 +102,7 @@ public class DbMigration {
|
||||
|
||||
/**
|
||||
* Set the path from the current working directory to the application resources.
|
||||
*
|
||||
* <p>
|
||||
* This defaults to maven style 'src/main/resources'.
|
||||
*/
|
||||
public void setPathToResources(String pathToResources) {
|
||||
@@ -169,7 +173,7 @@ public class DbMigration {
|
||||
/**
|
||||
* Generate the next migration xml file and associated apply and rollback sql scripts.
|
||||
* <p>
|
||||
* This does not run the migration or ddl scripts but just generates them.
|
||||
* This does not run the migration or ddl scripts but just generates them.
|
||||
* </p>
|
||||
* <h3>Example: Run for a single specific platform</h3>
|
||||
* <pre>{@code
|
||||
@@ -181,7 +185,7 @@ public class DbMigration {
|
||||
* migration.generateMigration();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* <h3>Example: Run migration generating DDL for multiple platforms</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
@@ -206,6 +210,8 @@ public class DbMigration {
|
||||
try {
|
||||
Request request = createRequest();
|
||||
|
||||
generateExtraDdl(request);
|
||||
|
||||
String pendingVersion = generatePendingDrop();
|
||||
if (pendingVersion != null) {
|
||||
generatePendingDrop(request, pendingVersion);
|
||||
@@ -220,6 +226,49 @@ public class DbMigration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate "repeatable" migration scripts.
|
||||
* <p>
|
||||
* These take scrips from extra-dll.xml (typically views) and outputs "repeatable"
|
||||
* migration scripts (starting with "R__") to be run by FlywayDb or Ebean's own
|
||||
* migration runner.
|
||||
* </p>
|
||||
*/
|
||||
private void generateExtraDdl(Request request) throws IOException {
|
||||
|
||||
if (databasePlatform != null) {
|
||||
ExtraDdl extraDdl = ExtraDdlXmlReader.read("/extra-ddl.xml");
|
||||
if (extraDdl != null) {
|
||||
List<DdlScript> ddlScript = extraDdl.getDdlScript();
|
||||
for (DdlScript script : ddlScript) {
|
||||
if (ExtraDdlXmlReader.matchPlatform(databasePlatform.getName(), script.getPlatforms())) {
|
||||
writeExtraDdl(request, script);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write (or override) the "repeatable" migration script.
|
||||
*/
|
||||
private void writeExtraDdl(Request request, DdlScript script) throws IOException {
|
||||
|
||||
String fullName = repeatableMigrationName(script.getName());
|
||||
|
||||
logger.info("writing repeatable script {}", fullName);
|
||||
|
||||
File file = new File(request.migrationDir, fullName);
|
||||
FileWriter writer = new FileWriter(file);
|
||||
writer.write(script.getValue());
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
|
||||
private String repeatableMigrationName(String scriptName) {
|
||||
return "R__" + scriptName.replace(' ', '_') + migrationConfig.getApplySuffix();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the diff migration.
|
||||
*/
|
||||
@@ -319,7 +368,7 @@ public class DbMigration {
|
||||
// history ddl generation (triggers, history tables etc)
|
||||
DdlWrite write = new DdlWrite(new MConfiguration(), request.current);
|
||||
PlatformDdlWriter writer = createDdlWriter(databasePlatform, "");
|
||||
writer.processMigration(dbMigration, write, request.migrationDir , fullVersion);
|
||||
writer.processMigration(dbMigration, write, request.migrationDir, fullVersion);
|
||||
}
|
||||
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
|
||||
}
|
||||
@@ -339,7 +388,7 @@ public class DbMigration {
|
||||
|
||||
/**
|
||||
* Return the full version for the migration being generated.
|
||||
*
|
||||
* <p>
|
||||
* The full version can contain a comment suffix after a "__" double underscore.
|
||||
*/
|
||||
private String getFullVersion(MigrationModel migrationModel, String dropsFor) {
|
||||
@@ -349,7 +398,7 @@ public class DbMigration {
|
||||
version = migrationModel.getNextVersion(initialVersion);
|
||||
}
|
||||
|
||||
String fullVersion = version;
|
||||
String fullVersion = migrationConfig.getApplyPrefix() + version;
|
||||
if (migrationConfig.getName() != null) {
|
||||
fullVersion += "__" + toUnderScore(migrationConfig.getName());
|
||||
|
||||
@@ -366,7 +415,7 @@ public class DbMigration {
|
||||
* Replace spaces with underscores.
|
||||
*/
|
||||
private String toUnderScore(String name) {
|
||||
return name.replace(' ','_');
|
||||
return name.replace(' ', '_');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -444,7 +493,7 @@ public class DbMigration {
|
||||
*/
|
||||
protected File getModelDirectory(File migrationDirectory) {
|
||||
String modelPath = migrationConfig.getModelPath();
|
||||
if (modelPath == null || modelPath.isEmpty()) {
|
||||
if (modelPath == null || modelPath.isEmpty()) {
|
||||
return migrationDirectory;
|
||||
}
|
||||
File modelDir = new File(migrationDirectory, migrationConfig.getModelPath());
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.model.CurrentModel;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.extraddl.model.ExtraDdlXmlReader;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.File;
|
||||
@@ -13,6 +15,8 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.io.Reader;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Controls the generation and execution of "Create All" and "Drop All" DDL scripts.
|
||||
@@ -81,6 +85,28 @@ public class DdlGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all the DDL statements in the script.
|
||||
*/
|
||||
public int runScript(boolean expectErrors, String content, String scriptName) {
|
||||
|
||||
DdlRunner runner = new DdlRunner(expectErrors, scriptName);
|
||||
|
||||
Transaction transaction = server.createTransaction();
|
||||
Connection connection = transaction.getConnection();
|
||||
try {
|
||||
int count = runner.runAll(content, connection);
|
||||
transaction.commit();
|
||||
return count;
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new PersistenceException("Failed to run script", e);
|
||||
|
||||
} finally {
|
||||
transaction.end();
|
||||
}
|
||||
}
|
||||
|
||||
protected void runDropSql() throws IOException {
|
||||
if (!createOnly) {
|
||||
if (dropAllContent == null) {
|
||||
@@ -95,6 +121,14 @@ public class DdlGenerator {
|
||||
createAllContent = readFile(getCreateFileName());
|
||||
}
|
||||
runScript(false, createAllContent, getCreateFileName());
|
||||
|
||||
String ignoreExtraDdl = System.getProperty("ebean.ignoreExtraDdl");
|
||||
if (!"true".equalsIgnoreCase(ignoreExtraDdl)) {
|
||||
String extraApply = ExtraDdlXmlReader.buildExtra(server.getDatabasePlatform().getName());
|
||||
if (extraApply != null) {
|
||||
runScript(false, extraApply, "extra-dll");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void runInitSql() throws IOException {
|
||||
@@ -110,9 +144,8 @@ public class DdlGenerator {
|
||||
if (sqlScript != null) {
|
||||
InputStream is = getClassLoader().getResourceAsStream(sqlScript);
|
||||
if (is != null) {
|
||||
DdlRunner runner = new DdlRunner(false, sqlScript);
|
||||
String content = readContent(new InputStreamReader(is));
|
||||
runner.runAll(content, server);
|
||||
runScript(false, content, sqlScript);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,13 +254,4 @@ public class DdlGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all the DDL statements in the script.
|
||||
*/
|
||||
public int runScript(boolean expectErrors, String content, String scriptName) {
|
||||
|
||||
DdlRunner runner = new DdlRunner(expectErrors, scriptName);
|
||||
return runner.runAll(content, server);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.StringReader;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
@@ -20,11 +17,11 @@ public class DdlRunner {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(DdlRunner.class);
|
||||
|
||||
protected DdlParser ddlParser = new DdlParser();
|
||||
private DdlParser ddlParser = new DdlParser();
|
||||
|
||||
protected final String scriptName;
|
||||
private final String scriptName;
|
||||
|
||||
protected final boolean expectErrors;
|
||||
private final boolean expectErrors;
|
||||
|
||||
/**
|
||||
* Construct with a script name (for logging) and flag indicating if errors are expected.
|
||||
@@ -37,36 +34,16 @@ public class DdlRunner {
|
||||
/**
|
||||
* Parse the content into sql statements and execute them in a transaction.
|
||||
*/
|
||||
public int runAll(String content, SpiEbeanServer server) {
|
||||
public int runAll(String content, Connection connection) throws SQLException {
|
||||
|
||||
List<String> statements = ddlParser.parse(new StringReader(content));
|
||||
return runStatements(statements, server);
|
||||
return runStatements(statements, connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all the statements in a single transaction.
|
||||
*/
|
||||
public int runStatements(List<String> statements, SpiEbeanServer server) {
|
||||
|
||||
Transaction t = server.createTransaction();
|
||||
try {
|
||||
int statementCount = runStatements(expectErrors, statements, t.getConnection());
|
||||
t.commit();
|
||||
|
||||
return statementCount;
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new PersistenceException("Error: " + e.getMessage(), e);
|
||||
|
||||
} finally {
|
||||
t.end();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the list of statements.
|
||||
*/
|
||||
private int runStatements(boolean expectErrors, List<String> statements, Connection c) {
|
||||
private int runStatements(List<String> statements, Connection connection) throws SQLException {
|
||||
|
||||
List<String> noDuplicates = new ArrayList<String>();
|
||||
|
||||
@@ -80,7 +57,7 @@ public class DdlRunner {
|
||||
|
||||
for (int i = 0; i < noDuplicates.size(); i++) {
|
||||
String xOfy = (i + 1) + " of " + noDuplicates.size();
|
||||
runStatement(expectErrors, xOfy, noDuplicates.get(i), c);
|
||||
runStatement(expectErrors, xOfy, noDuplicates.get(i), connection);
|
||||
}
|
||||
|
||||
return noDuplicates.size();
|
||||
@@ -89,7 +66,7 @@ public class DdlRunner {
|
||||
/**
|
||||
* Execute the statement.
|
||||
*/
|
||||
private void runStatement(boolean expectErrors, String oneOf, String stmt, Connection c) {
|
||||
private void runStatement(boolean expectErrors, String oneOf, String stmt, Connection c) throws SQLException {
|
||||
|
||||
PreparedStatement pstmt = null;
|
||||
try {
|
||||
@@ -109,12 +86,12 @@ public class DdlRunner {
|
||||
pstmt = c.prepareStatement(stmt);
|
||||
pstmt.execute();
|
||||
|
||||
} catch (Exception e) {
|
||||
} catch (SQLException e) {
|
||||
if (expectErrors) {
|
||||
logger.debug(" ... ignoring error executing " + getSummary(stmt) + " error: " + e.getMessage());
|
||||
} else {
|
||||
String msg = "Error executing stmt[" + stmt + "] error[" + e.getMessage() + "]";
|
||||
throw new RuntimeException(msg, e);
|
||||
throw new SQLException(msg, e);
|
||||
}
|
||||
|
||||
} finally {
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.DbMigrationConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.runner.LocalMigrationResource;
|
||||
import com.avaje.ebean.dbmigration.runner.LocalMigrationResources;
|
||||
import com.avaje.ebean.dbmigration.runner.MigrationTable;
|
||||
import com.avaje.ebeaninternal.util.JdbcClose;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Runs the DB migration typically on application start.
|
||||
*/
|
||||
public class MigrationRunner {
|
||||
|
||||
public static final Logger logger = LoggerFactory.getLogger("org.avaje.ebean.DbMigration");
|
||||
|
||||
private final EbeanServer server;
|
||||
|
||||
private final ServerConfig config;
|
||||
|
||||
private final DbMigrationConfig migrationConfig;
|
||||
|
||||
public MigrationRunner(EbeanServer server, DbMigrationConfig migrationConfig) {
|
||||
this.server = server;
|
||||
this.config = server.getPluginApi().getServerConfig();
|
||||
this.migrationConfig = migrationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations if there are any that need running.
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
LocalMigrationResources resources = new LocalMigrationResources(config, migrationConfig);
|
||||
if (!resources.readResources()) {
|
||||
logger.debug("no migrations to check");
|
||||
return;
|
||||
}
|
||||
|
||||
String migrationUser = migrationConfig.getDbUser();
|
||||
String migrationPwd = migrationConfig.getDbPassword();
|
||||
if (migrationUser == null) {
|
||||
throw new IllegalStateException("No DB migration user specified (to run the db migration) ?");
|
||||
}
|
||||
|
||||
DataSource dataSource = server.getPluginApi().getDataSource();
|
||||
if (dataSource == null) {
|
||||
throw new IllegalStateException("No dataSource when trying to run migration? "
|
||||
+"Maybe trying to generate DBMigration when ebean.migration.run=true is set? "
|
||||
+"Perhaps need to set ebean.migration.run=false in test-ebean.properties?");
|
||||
}
|
||||
|
||||
Connection connection;
|
||||
try {
|
||||
connection = dataSource.getConnection(migrationUser, migrationPwd);
|
||||
} catch (SQLException e) {
|
||||
throw new IllegalArgumentException("Error trying to connect to database using DB Migration user [" + migrationUser + "]", e);
|
||||
}
|
||||
|
||||
try {
|
||||
logger.debug("using db user [{}] to run migrations ...");
|
||||
connection.setAutoCommit(false);
|
||||
runMigrations(resources, connection);
|
||||
|
||||
connection.commit();
|
||||
|
||||
} catch (Exception e) {
|
||||
JdbcClose.rollback(connection);
|
||||
throw new RuntimeException(e);
|
||||
|
||||
} finally {
|
||||
JdbcClose.close(connection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all the migrations as needed.
|
||||
*/
|
||||
private void runMigrations(LocalMigrationResources resources, Connection connection) throws SQLException, IOException {
|
||||
|
||||
MigrationTable table = new MigrationTable(server, migrationConfig, connection);
|
||||
table.createIfNeeded();
|
||||
|
||||
// get the migrations in version order
|
||||
List<LocalMigrationResource> localVersions = resources.getVersions();
|
||||
|
||||
logger.info("local migrations:{} existing migrations:{}", localVersions.size(), table.size());
|
||||
|
||||
LocalMigrationResource priorVersion = null;
|
||||
|
||||
// run migrations in order
|
||||
for (int i = 0; i < localVersions.size(); i++) {
|
||||
LocalMigrationResource localVersion = localVersions.get(i);
|
||||
if (!table.shouldRun(localVersion, priorVersion)) {
|
||||
break;
|
||||
}
|
||||
priorVersion = localVersion;
|
||||
connection.commit();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -123,6 +123,9 @@ public class BaseTableDdl implements TableDdl {
|
||||
// defined on the columns
|
||||
writePrimaryKeyConstraint(apply, createTable.getPkName(), toColumnNames(pk));
|
||||
}
|
||||
if (platformDdl.isInlineForeignKeys()) {
|
||||
writeInlineForeignKeys(writer, createTable);
|
||||
}
|
||||
|
||||
apply.newLine().append(")");
|
||||
addTableCommentInline(apply, createTable);
|
||||
@@ -151,8 +154,9 @@ public class BaseTableDdl implements TableDdl {
|
||||
apply.end();
|
||||
writer.dropAll().end();
|
||||
|
||||
writeAddForeignKeys(writer, createTable);
|
||||
|
||||
if (!platformDdl.isInlineForeignKeys()) {
|
||||
writeAddForeignKeys(writer, createTable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -235,6 +239,43 @@ public class BaseTableDdl implements TableDdl {
|
||||
platformDdl.createWithHistory(writer, table);
|
||||
}
|
||||
|
||||
protected void writeInlineForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
|
||||
|
||||
for (Column column : createTable.getColumn()) {
|
||||
String references = column.getReferences();
|
||||
if (hasValue(references)) {
|
||||
writeInlineForeignKey(write, column);
|
||||
}
|
||||
}
|
||||
writeInlineCompoundForeignKeys(write, createTable);
|
||||
}
|
||||
|
||||
protected void writeInlineForeignKey(DdlWrite write, Column column) throws IOException {
|
||||
|
||||
String references = column.getReferences();
|
||||
int pos = references.lastIndexOf('.');
|
||||
if (pos == -1) {
|
||||
throw new IllegalStateException("Expecting period '.' character for table.column split but not found in [" + references + "]");
|
||||
}
|
||||
String refTableName = references.substring(0, pos);
|
||||
String refColumnName = references.substring(pos + 1);
|
||||
String fkConstraint = platformDdl.tableInlineForeignKey(new String[]{column.getName()}, refTableName, new String[]{refColumnName});
|
||||
write.apply().append(",").newLine().append(" ").append(fkConstraint);
|
||||
}
|
||||
|
||||
protected void writeInlineCompoundForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
|
||||
|
||||
List<ForeignKey> foreignKey = createTable.getForeignKey();
|
||||
for (ForeignKey key : foreignKey) {
|
||||
String refTableName = key.getRefTableName();
|
||||
String[] cols = toColumnNamesSplit(key.getColumnNames());
|
||||
String[] refColumns = toColumnNamesSplit(key.getRefColumnNames());
|
||||
|
||||
String fkConstraint = platformDdl.tableInlineForeignKey(cols, refTableName, refColumns);
|
||||
write.apply().append(",").newLine().append(" ").append(fkConstraint);
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeAddForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
|
||||
|
||||
String tableName = createTable.getName();
|
||||
@@ -309,7 +350,10 @@ public class BaseTableDdl implements TableDdl {
|
||||
|
||||
protected void alterTableAddForeignKey(DdlBuffer buffer, String fkName, String tableName, String[] columns, String refTable, String[] refColumns) throws IOException {
|
||||
|
||||
buffer.append(platformDdl.alterTableAddForeignKey(tableName, fkName, columns, refTable, refColumns)).endOfStatement();
|
||||
String fkConstraint = platformDdl.alterTableAddForeignKey(tableName, fkName, columns, refTable, refColumns);
|
||||
if (fkConstraint != null && !fkConstraint.isEmpty()) {
|
||||
buffer.append(fkConstraint).endOfStatement();
|
||||
}
|
||||
}
|
||||
|
||||
protected void appendColumns(String[] columns, DdlBuffer buffer) throws IOException {
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
/**
|
||||
* DB2 platform specific DDL.
|
||||
*/
|
||||
public class DB2Ddl extends PlatformDdl {
|
||||
|
||||
public DB2Ddl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
public DB2Ddl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.identitySuffix = " generated by default as identity";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
/**
|
||||
* H2 platform specific DDL.
|
||||
*/
|
||||
public class H2Ddl extends PlatformDdl {
|
||||
|
||||
public H2Ddl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
public H2Ddl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.historyDdl = new H2HistoryDdl();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
/**
|
||||
* Hsqldb platform specific DDL.
|
||||
*/
|
||||
public class HsqldbDdl extends PlatformDdl {
|
||||
|
||||
public HsqldbDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
public HsqldbDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.identitySuffix = " generated by default as identity (start with 1) ";
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import com.avaje.ebean.dbmigration.migration.AlterColumn;
|
||||
|
||||
@@ -12,8 +11,8 @@ import java.io.IOException;
|
||||
*/
|
||||
public class MsSqlServerDdl extends PlatformDdl {
|
||||
|
||||
public MsSqlServerDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
public MsSqlServerDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.identitySuffix = " identity(1,1)";
|
||||
this.foreignKeyRestrict = "";
|
||||
this.inlineUniqueOneToOne = false;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import com.avaje.ebean.dbmigration.migration.AlterColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.Column;
|
||||
@@ -14,8 +13,8 @@ import java.io.IOException;
|
||||
*/
|
||||
public class MySqlDdl extends PlatformDdl {
|
||||
|
||||
public MySqlDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
public MySqlDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.alterColumn = "modify";
|
||||
this.dropUniqueConstraint = "drop index";
|
||||
this.historyDdl = new MySqlHistoryDdl();
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
/**
|
||||
* Oracle platform specific DDL.
|
||||
*/
|
||||
public class Oracle10Ddl extends PlatformDdl {
|
||||
|
||||
public Oracle10Ddl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
public Oracle10Ddl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.dropTableIfExists = "drop table ";
|
||||
this.dropSequenceIfExists = "drop sequence ";
|
||||
this.dropTableCascade = " cascade constraints purge";
|
||||
|
||||
@@ -2,8 +2,9 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.DbConstraintNaming;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbDefaultValue;
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.IdType;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.BaseDdlHandler;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
|
||||
@@ -85,9 +86,17 @@ public class PlatformDdl {
|
||||
|
||||
protected DbConstraintNaming naming;
|
||||
|
||||
public PlatformDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
this.dbIdentity = dbIdentity;
|
||||
this.typeConverter = new PlatformTypeConverter(platformTypes);
|
||||
/**
|
||||
* Generally not desired as then they are not named (used with SQLite).
|
||||
*/
|
||||
protected boolean inlineForeignKeys;
|
||||
|
||||
protected final DbDefaultValue dbDefaultValue;
|
||||
|
||||
public PlatformDdl(DatabasePlatform platform) {
|
||||
this.dbIdentity = platform.getDbIdentity();
|
||||
this.dbDefaultValue = platform.getDbDefaultValue();
|
||||
this.typeConverter = new PlatformTypeConverter(platform.getDbTypeMap());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,6 +137,14 @@ public class PlatformDdl {
|
||||
return inlineComments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if foreign key reference constraints need to inlined with create table.
|
||||
* Ideally we don't do this as then the constraints are not named. Do this for SQLite.
|
||||
*/
|
||||
public boolean isInlineForeignKeys() {
|
||||
return inlineForeignKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write all the table columns converting to platform types as necessary.
|
||||
*/
|
||||
@@ -152,6 +169,12 @@ public class PlatformDdl {
|
||||
buffer.append(" ");
|
||||
buffer.append(lowerColumnName(column.getName()), 29);
|
||||
buffer.append(platformType);
|
||||
if (!typeContainsDefault(platformType)) {
|
||||
String defaultValue = convertDefaultValue(column.getDefaultValue());
|
||||
if (defaultValue != null) {
|
||||
buffer.append(" default ").append(defaultValue);
|
||||
}
|
||||
}
|
||||
if (isTrue(column.isNotnull()) || isTrue(column.isPrimaryKey())) {
|
||||
buffer.append(" not null");
|
||||
}
|
||||
@@ -160,6 +183,20 @@ public class PlatformDdl {
|
||||
// so that the database can potentially provide a nice SQL error
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the type definition already contains a default value.
|
||||
*/
|
||||
private boolean typeContainsDefault(String platformType) {
|
||||
return platformType.toLowerCase().contains(" default");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the DB column default literal to platform specific.
|
||||
*/
|
||||
private String convertDefaultValue(String dbDefault) {
|
||||
return dbDefaultValue.convert(dbDefault);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the drop foreign key clause.
|
||||
*/
|
||||
@@ -255,6 +292,20 @@ public class PlatformDdl {
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign key constraint when used inline with create table.
|
||||
*/
|
||||
public String tableInlineForeignKey(String[] columns, String refTable, String[] refColumns) {
|
||||
|
||||
StringBuilder buffer = new StringBuilder(90);
|
||||
buffer.append("foreign key");
|
||||
appendColumns(columns, buffer);
|
||||
buffer.append(" references ").append(lowerTableName(refTable));
|
||||
appendColumns(refColumns, buffer);
|
||||
appendWithSpace(foreignKeyRestrict, buffer);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add foreign key.
|
||||
*/
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
/**
|
||||
* Postgres specific DDL.
|
||||
*/
|
||||
public class PostgresDdl extends PlatformDdl {
|
||||
|
||||
public PostgresDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
public PostgresDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.historyDdl = new PostgresHistoryDdl();
|
||||
this.dropTableCascade = " cascade";
|
||||
this.columnSetType = "type ";
|
||||
|
||||
@@ -1,16 +1,34 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* DB2 platform specific DDL.
|
||||
*/
|
||||
public class SQLiteDdl extends PlatformDdl {
|
||||
|
||||
public SQLiteDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
this.identitySuffix = " autoincrement";
|
||||
public SQLiteDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.identitySuffix = "";
|
||||
this.inlineForeignKeys = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableComment(DdlBuffer apply, String tableName, String tableComment) throws IOException {
|
||||
// not supported
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addColumnComment(DdlBuffer apply, String table, String column, String comment) throws IOException {
|
||||
// not supported
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterTableAddForeignKey(String tableName, String fkName, String[] columns, String refTable, String[] refColumns) {
|
||||
// not supported
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@ import java.util.Arrays;
|
||||
*/
|
||||
public class MigrationVersion implements Comparable<MigrationVersion> {
|
||||
|
||||
private static final int[] REPEAT_ORDERING = {Integer.MAX_VALUE};
|
||||
|
||||
private static final boolean[] REPEAT_UNDERSCORES = {false};
|
||||
|
||||
/**
|
||||
* The raw version text.
|
||||
*/
|
||||
@@ -21,6 +25,19 @@ public class MigrationVersion implements Comparable<MigrationVersion> {
|
||||
|
||||
private final String comment;
|
||||
|
||||
/**
|
||||
* Construct for "repeatable" version.
|
||||
*/
|
||||
private MigrationVersion(String raw, String comment) {
|
||||
this.raw = raw;
|
||||
this.comment = comment;
|
||||
this.ordering = REPEAT_ORDERING;
|
||||
this.underscores = REPEAT_UNDERSCORES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for "normal" version.
|
||||
*/
|
||||
private MigrationVersion(String raw, int[] ordering, boolean[] underscores, String comment) {
|
||||
this.raw = raw;
|
||||
this.ordering = ordering;
|
||||
@@ -28,6 +45,20 @@ public class MigrationVersion implements Comparable<MigrationVersion> {
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a "repeatable" version.
|
||||
*/
|
||||
public boolean isRepeatable() {
|
||||
return ordering == REPEAT_ORDERING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full version.
|
||||
*/
|
||||
public String getFull() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return raw;
|
||||
}
|
||||
@@ -69,11 +100,15 @@ public class MigrationVersion implements Comparable<MigrationVersion> {
|
||||
|
||||
/**
|
||||
* Returns the version part of the string.
|
||||
*
|
||||
* <p>
|
||||
* Normalised means always use '.' delimiters (no underscores).
|
||||
* NextVersion means bump/increase the last version number by 1.
|
||||
*/
|
||||
private String formattedVersion(boolean normalised, boolean nextVersion) {
|
||||
|
||||
if (ordering == REPEAT_ORDERING) {
|
||||
return "R";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < ordering.length; i++) {
|
||||
if (i < ordering.length - 1) {
|
||||
@@ -103,8 +138,7 @@ public class MigrationVersion implements Comparable<MigrationVersion> {
|
||||
return (ordering[i] > other.ordering[i]) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
// considered the same
|
||||
return 0;
|
||||
return comment.compareTo(other.comment);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,6 +153,10 @@ public class MigrationVersion implements Comparable<MigrationVersion> {
|
||||
*/
|
||||
public static MigrationVersion parse(String raw) {
|
||||
|
||||
if (raw.startsWith("V") || raw.startsWith("v")) {
|
||||
raw = raw.substring(1);
|
||||
}
|
||||
|
||||
String comment = "";
|
||||
String value = raw;
|
||||
int commentStart = raw.indexOf("__");
|
||||
@@ -132,6 +170,11 @@ public class MigrationVersion implements Comparable<MigrationVersion> {
|
||||
|
||||
String[] sections = value.split("\\.");
|
||||
|
||||
if ("r".equalsIgnoreCase(sections[0])) {
|
||||
// a "repeatable" version (does not have a version number)
|
||||
return new MigrationVersion(raw, comment);
|
||||
}
|
||||
|
||||
boolean[] underscores = new boolean[sections.length];
|
||||
int[] ordering = new int[sections.length];
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public class VisitAllUsing {
|
||||
|
||||
public void visitAllBeans() {
|
||||
for (BeanDescriptor<?> desc : descriptors) {
|
||||
if (desc.getBaseTable() != null) {
|
||||
if (desc.isBaseTable()) {
|
||||
visitBean(desc, visitor);
|
||||
}
|
||||
}
|
||||
@@ -150,8 +150,8 @@ public class VisitAllUsing {
|
||||
}
|
||||
|
||||
public void visit(InheritInfo inheritInfo) {
|
||||
BeanProperty[] propertiesLocal = inheritInfo.getBeanDescriptor().propertiesLocal();
|
||||
for (int i = 0; i <propertiesLocal.length ; i++) {
|
||||
BeanProperty[] propertiesLocal = inheritInfo.desc().propertiesLocal();
|
||||
for (int i = 0; i < propertiesLocal.length; i++) {
|
||||
owner.visit(pv, propertiesLocal[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
/**
|
||||
* Calculates the checksum for the given string content.
|
||||
*/
|
||||
public class Checksum {
|
||||
|
||||
/**
|
||||
* Returns the checksum of this string.
|
||||
*/
|
||||
public static int calculate(String str) {
|
||||
|
||||
final CRC32 crc32 = new CRC32();
|
||||
|
||||
BufferedReader bufferedReader = new BufferedReader(new StringReader(str));
|
||||
try {
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
crc32.update(line.getBytes("UTF-8"));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to calculate checksum", e);
|
||||
}
|
||||
|
||||
return (int) crc32.getValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import com.avaje.ebean.dbmigration.model.MigrationVersion;
|
||||
import org.avaje.classpath.scanner.Resource;
|
||||
|
||||
/**
|
||||
* A DB migration resource (DDL script with version).
|
||||
*/
|
||||
public class LocalMigrationResource implements Comparable<LocalMigrationResource> {
|
||||
|
||||
/**
|
||||
* Code for repeatable migrations.
|
||||
*/
|
||||
private static final String REPEAT_TYPE = "R";
|
||||
|
||||
/**
|
||||
* Code for version migrations.
|
||||
*/
|
||||
private static final String VERSION_TYPE = "V";
|
||||
|
||||
private final MigrationVersion version;
|
||||
|
||||
private final String location;
|
||||
|
||||
private final Resource resource;
|
||||
|
||||
/**
|
||||
* Construct with version and resource.
|
||||
*/
|
||||
public LocalMigrationResource(MigrationVersion version, String location, Resource resource) {
|
||||
this.version = version;
|
||||
this.location = location;
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return version.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the underlying version is "repeatable".
|
||||
*/
|
||||
public boolean isRepeatable() {
|
||||
return version.isRepeatable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the "key" that identifies the migration.
|
||||
*/
|
||||
public String key() {
|
||||
if (isRepeatable()) {
|
||||
return version.getComment().toLowerCase();
|
||||
} else {
|
||||
return version.normalised();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the migration comment.
|
||||
*/
|
||||
public String getComment() {
|
||||
String comment = version.getComment();
|
||||
return (comment == null || comment.isEmpty()) ? "-" : comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default ordering by version.
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(LocalMigrationResource o) {
|
||||
return version.compareTo(o.version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying migration version.
|
||||
*/
|
||||
public MigrationVersion getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resource location.
|
||||
*/
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the content for the migration apply ddl script.
|
||||
*/
|
||||
public String getContent() {
|
||||
return resource.loadAsString("UTF-8");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type code ("R" or "V") for this migration.
|
||||
*/
|
||||
public String getType() {
|
||||
return isRepeatable() ? REPEAT_TYPE : VERSION_TYPE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import com.avaje.ebean.config.DbMigrationConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.model.MigrationVersion;
|
||||
import org.avaje.classpath.scanner.Resource;
|
||||
import org.avaje.classpath.scanner.ResourceFilter;
|
||||
import org.avaje.classpath.scanner.Scanner;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Loads the DB migration resources and sorts them into execution order.
|
||||
*/
|
||||
public class LocalMigrationResources {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LocalMigrationResources.class);
|
||||
|
||||
private final ServerConfig serverConfig;
|
||||
|
||||
private final DbMigrationConfig migrationConfig;
|
||||
|
||||
private final List<LocalMigrationResource> versions = new ArrayList<LocalMigrationResource>();
|
||||
|
||||
/**
|
||||
* Construct with configuration options.
|
||||
*/
|
||||
public LocalMigrationResources(ServerConfig serverConfig, DbMigrationConfig migrationConfig) {
|
||||
this.serverConfig = serverConfig;
|
||||
this.migrationConfig = migrationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all the migration resources (SQL scripts) returning true if there are versions.
|
||||
*/
|
||||
public boolean readResources() {
|
||||
|
||||
String migrationPath = migrationConfig.getMigrationPath();
|
||||
|
||||
ClassLoader classLoader = serverConfig.getClassLoadConfig().getClassLoader();
|
||||
|
||||
Scanner scanner = new Scanner(classLoader);
|
||||
List<Resource> resourceList = scanner.scanForResources(migrationPath, new Match(migrationConfig));
|
||||
|
||||
logger.debug("resources: {}", resourceList);
|
||||
|
||||
for (Resource resource : resourceList) {
|
||||
String filename = resource.getFilename();
|
||||
if (filename.endsWith(migrationConfig.getApplySuffix())) {
|
||||
int pos = filename.lastIndexOf(migrationConfig.getApplySuffix());
|
||||
String mainName = filename.substring(0, pos);
|
||||
|
||||
MigrationVersion migrationVersion = MigrationVersion.parse(mainName);
|
||||
LocalMigrationResource res = new LocalMigrationResource(migrationVersion, resource.getLocation(), resource);
|
||||
versions.add(res);
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(versions);
|
||||
return !versions.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of migration resources in version order.
|
||||
*/
|
||||
public List<LocalMigrationResource> getVersions() {
|
||||
return versions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Filter used to find the migration scripts.
|
||||
*/
|
||||
private static class Match implements ResourceFilter {
|
||||
|
||||
private final DbMigrationConfig migrationConfig;
|
||||
|
||||
Match(DbMigrationConfig migrationConfig) {
|
||||
this.migrationConfig = migrationConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(String name) {
|
||||
return name.endsWith(migrationConfig.getApplySuffix());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import com.avaje.ebean.SqlRow;
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* Bean holding migration execution details stored in the migration table.
|
||||
*/
|
||||
class MigrationMetaRow {
|
||||
|
||||
private int id;
|
||||
|
||||
private String type;
|
||||
|
||||
private String version;
|
||||
|
||||
private String comment;
|
||||
|
||||
private int checksum;
|
||||
|
||||
private Timestamp runOn;
|
||||
|
||||
private String runBy;
|
||||
|
||||
private long runTime;
|
||||
|
||||
/**
|
||||
* Construct for inserting into table.
|
||||
*/
|
||||
MigrationMetaRow(int id, String type, String version, String comment, int checksum, String runBy, Timestamp runOn, long runTime) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.version = version;
|
||||
this.checksum = checksum;
|
||||
this.comment = comment;
|
||||
this.runBy = runBy;
|
||||
this.runOn = runOn;
|
||||
this.runTime = runTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct from the SqlRow (read from table).
|
||||
*/
|
||||
MigrationMetaRow(SqlRow row) {
|
||||
id = row.getInteger("id");
|
||||
type = row.getString("mtype");
|
||||
version = row.getString("mversion");
|
||||
comment = row.getString("mcomment");
|
||||
checksum = row.getInteger("mchecksum");
|
||||
runOn = row.getTimestamp("run_on");
|
||||
runBy = row.getString("run_by");
|
||||
runTime = row.getLong("run_time");
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "id:" + id + " type:" + type + " runVersion:" + version + " comment:" + comment + " runOn:" + runOn + " runBy:" + runBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the id for this migration.
|
||||
*/
|
||||
int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the normalised version for this migration.
|
||||
*/
|
||||
String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the checksum for this migration.
|
||||
*/
|
||||
int getChecksum() {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind to the insert statement.
|
||||
*/
|
||||
void bindInsert(SqlUpdate insert) {
|
||||
insert.setParameter(1, id);
|
||||
insert.setParameter(2, type);
|
||||
insert.setParameter(3, "SUCCESS");
|
||||
insert.setParameter(4, version);
|
||||
insert.setParameter(5, comment);
|
||||
insert.setParameter(6, checksum);
|
||||
insert.setParameter(7, runOn);
|
||||
insert.setParameter(8, runBy);
|
||||
insert.setParameter(9, runTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL insert given the table migration meta data is stored in.
|
||||
*/
|
||||
static String insertSql(String table) {
|
||||
return "insert into " + table
|
||||
+ " (id, mtype, mstatus, mversion, mcomment, mchecksum, run_on, run_by, run_time)"
|
||||
+ " values (?,?,?,?,?,?,?,?,?)";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import com.avaje.ebean.dbmigration.DdlRunner;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Runs the DDL migration scripts.
|
||||
*/
|
||||
public class MigrationScriptRunner {
|
||||
|
||||
private final Connection connection;
|
||||
|
||||
/**
|
||||
* Construct with a given connection.
|
||||
*/
|
||||
public MigrationScriptRunner(Connection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all the DDL statements in the script.
|
||||
*/
|
||||
int runScript(boolean expectErrors, String content, String scriptName) throws SQLException {
|
||||
|
||||
DdlRunner runner = new DdlRunner(expectErrors, scriptName);
|
||||
return runner.runAll(content, connection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.SqlQuery;
|
||||
import com.avaje.ebean.SqlRow;
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebean.config.DbMigrationConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.dbmigration.MigrationRunner;
|
||||
import com.avaje.ebean.plugin.SpiServer;
|
||||
import com.avaje.ebeaninternal.server.transaction.ExternalJdbcTransaction;
|
||||
import com.avaje.ebeaninternal.util.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Manages the migration table.
|
||||
*/
|
||||
public class MigrationTable {
|
||||
|
||||
private static final Logger logger = MigrationRunner.logger;
|
||||
|
||||
private final Connection connection;
|
||||
|
||||
private final EbeanServer server;
|
||||
|
||||
private final DatabasePlatform databasePlatform;
|
||||
|
||||
private final String catalog;
|
||||
private final String schema;
|
||||
private final String table;
|
||||
private final ServerConfig serverConfig;
|
||||
private final String envUserName;
|
||||
|
||||
private final Timestamp runOn = new Timestamp(System.currentTimeMillis());
|
||||
|
||||
private final ScriptTransform scriptTransform;
|
||||
|
||||
private final String insertSql;
|
||||
|
||||
private final LinkedHashMap<String, MigrationMetaRow> migrations;
|
||||
|
||||
private MigrationMetaRow lastMigration;
|
||||
|
||||
/**
|
||||
* Construct with server, configuration and jdbc connection (DB admin user).
|
||||
*/
|
||||
public MigrationTable(EbeanServer server, DbMigrationConfig migrationConfig, Connection connection) {
|
||||
this.connection = connection;
|
||||
this.server = server;
|
||||
this.migrations = new LinkedHashMap<String, MigrationMetaRow>();
|
||||
|
||||
SpiServer pluginApi = server.getPluginApi();
|
||||
this.serverConfig = pluginApi.getServerConfig();
|
||||
this.databasePlatform = pluginApi.getDatabasePlatform();
|
||||
this.catalog = null;
|
||||
this.schema = null;
|
||||
this.table = migrationConfig.getMetaTable();
|
||||
this.insertSql = MigrationMetaRow.insertSql(table);
|
||||
this.scriptTransform = createScriptTransform(migrationConfig);
|
||||
this.envUserName = System.getProperty("user.name");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of migrations in the DB migration table.
|
||||
*/
|
||||
public int size() {
|
||||
return migrations.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the ScriptTransform for placeholder key/value replacement.
|
||||
*/
|
||||
private ScriptTransform createScriptTransform(DbMigrationConfig config) {
|
||||
|
||||
Map<String, String> map = PlaceholderBuilder.build(config.getRunPlaceholders(), config.getRunPlaceholderMap());
|
||||
return new ScriptTransform(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the table is it does not exist.
|
||||
*/
|
||||
public void createIfNeeded() throws SQLException, IOException {
|
||||
|
||||
if (!tableExists(connection)) {
|
||||
createTable(connection);
|
||||
}
|
||||
|
||||
ExternalJdbcTransaction t = new ExternalJdbcTransaction(connection);
|
||||
SqlQuery sqlQuery = server.createSqlQuery("select * from " + table + " order by id for update");
|
||||
List<SqlRow> metaRows = server.findList(sqlQuery, t);
|
||||
|
||||
for (SqlRow row : metaRows) {
|
||||
MigrationMetaRow metaRow = new MigrationMetaRow(row);
|
||||
addMigration(metaRow.getVersion(), metaRow);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void createTable(Connection connection) throws IOException, SQLException {
|
||||
|
||||
String script = ScriptTransform.table(table, getCreateTableScript());
|
||||
|
||||
MigrationScriptRunner run = new MigrationScriptRunner(connection);
|
||||
run.runScript(false, script, "create migration table");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the create table script.
|
||||
*/
|
||||
private String getCreateTableScript() throws IOException {
|
||||
// supply a script to override the default table create script
|
||||
String script = readResource("migration-support/create-table.sql");
|
||||
if (script == null) {
|
||||
// no, just use the default script
|
||||
script = readResource("migration-support/default-create-table.sql");
|
||||
}
|
||||
return script;
|
||||
}
|
||||
|
||||
private String readResource(String location) throws IOException {
|
||||
|
||||
Enumeration<URL> resources = serverConfig.getClassLoadConfig().getResources(location);
|
||||
if (resources.hasMoreElements()) {
|
||||
URL url = resources.nextElement();
|
||||
return IOUtils.readUtf8(url.openStream());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the table exists.
|
||||
*/
|
||||
private boolean tableExists(Connection connection) throws SQLException {
|
||||
return databasePlatform.tableExists(connection, catalog, schema, table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the migration ran successfully and false if the migration failed.
|
||||
*/
|
||||
public boolean shouldRun(LocalMigrationResource localVersion, LocalMigrationResource priorVersion) throws SQLException {
|
||||
|
||||
if (priorVersion != null && !localVersion.isRepeatable()) {
|
||||
if (!migrationExists(priorVersion)) {
|
||||
logger.error("Migration {} requires prior migration {} which has not been run", localVersion.getVersion(), priorVersion.getVersion());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MigrationMetaRow existing = migrations.get(localVersion.key());
|
||||
return runMigration(localVersion, existing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migration script.
|
||||
*
|
||||
* @param local The local migration resource
|
||||
* @param existing The information for this migration existing in the table
|
||||
*
|
||||
* @return True if the migrations should continue
|
||||
*/
|
||||
private boolean runMigration(LocalMigrationResource local, MigrationMetaRow existing) throws SQLException {
|
||||
|
||||
String script = convertScript(local.getContent());
|
||||
int checksum = Checksum.calculate(script);
|
||||
|
||||
if (existing != null) {
|
||||
|
||||
boolean matchChecksum = (existing.getChecksum() == checksum);
|
||||
|
||||
if (!local.isRepeatable()) {
|
||||
if (!matchChecksum) {
|
||||
logger.error("Checksum mismatch on migration {}", local.getLocation());
|
||||
}
|
||||
return true;
|
||||
|
||||
} else if (matchChecksum) {
|
||||
logger.trace("... skip unchanged repeatable migration {}", local.getLocation());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
runMigration(local, script, checksum);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a migration script as new migration or update on existing repeatable migration.
|
||||
*/
|
||||
private void runMigration(LocalMigrationResource local, String script, int checksum) throws SQLException {
|
||||
|
||||
logger.debug("run migration {}", local.getLocation());
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
MigrationScriptRunner run = new MigrationScriptRunner(connection);
|
||||
run.runScript(false, script, "run migration version: " + local.getVersion());
|
||||
|
||||
long exeMillis = System.currentTimeMillis() - start;
|
||||
// insert new migration row
|
||||
SqlUpdate insert = server.createSqlUpdate(insertSql);
|
||||
MigrationMetaRow metaRow = createMetaRow(local, checksum, exeMillis);
|
||||
metaRow.bindInsert(insert);
|
||||
server.execute(insert, new ExternalJdbcTransaction(connection));
|
||||
|
||||
addMigration(local.key(), metaRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the MigrationMetaRow for this migration.
|
||||
*/
|
||||
private MigrationMetaRow createMetaRow(LocalMigrationResource migration, int checksum, long exeMillis) {
|
||||
|
||||
int nextId = 1;
|
||||
if (lastMigration != null) {
|
||||
nextId = lastMigration.getId() + 1;
|
||||
}
|
||||
|
||||
String type = migration.getType();
|
||||
String runVersion = migration.key();
|
||||
String comment = migration.getComment();
|
||||
|
||||
return new MigrationMetaRow(nextId, type, runVersion, comment, checksum, envUserName, runOn, exeMillis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the migration exists.
|
||||
*/
|
||||
private boolean migrationExists(LocalMigrationResource priorVersion) {
|
||||
return migrations.containsKey(priorVersion.key());
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the placeholder key/value replacement on the script.
|
||||
*/
|
||||
private String convertScript(String script) {
|
||||
return scriptTransform.transform(script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the successfully executed migration (to allow dependant scripts to run).
|
||||
*/
|
||||
private void addMigration(String key, MigrationMetaRow metaRow) {
|
||||
lastMigration = metaRow;
|
||||
if (metaRow.getVersion() == null) {
|
||||
throw new IllegalStateException("No runVersion in db migration table row? " + metaRow);
|
||||
}
|
||||
migrations.put(key, metaRow);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Joins placeholder map and comma/equals delimited string.
|
||||
*/
|
||||
class PlaceholderBuilder {
|
||||
|
||||
private final Map<String,String> map = new HashMap<String,String>();
|
||||
|
||||
/**
|
||||
* Create with raw comma and equals delimited pairs plus map of key value pairs.
|
||||
*/
|
||||
public static Map<String,String> build(String commaDelimited, Map<String,String> placeholders) {
|
||||
|
||||
PlaceholderBuilder builder = new PlaceholderBuilder();
|
||||
builder.add(commaDelimited);
|
||||
builder.add(placeholders);
|
||||
|
||||
return builder.map;
|
||||
}
|
||||
|
||||
private PlaceholderBuilder() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a comma and equals delimited string to parse for key value pairs.
|
||||
*/
|
||||
public void add(String commaDelimited) {
|
||||
|
||||
if (commaDelimited != null) {
|
||||
String[] split = commaDelimited.split("[,;]");
|
||||
for (String keyValue : split) {
|
||||
String[] pair = keyValue.split("=");
|
||||
if (pair.length == 2) {
|
||||
map.put(pair[0].trim(), pair[1].trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a map of key value placeholder pairs.
|
||||
*/
|
||||
public void add(Map<String,String> placeholders) {
|
||||
if (placeholders != null) {
|
||||
map.putAll(placeholders);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Transforms a SQL script given a map of key/value substitutions.
|
||||
*/
|
||||
class ScriptTransform {
|
||||
|
||||
/**
|
||||
* Transform just ${table} with the table name.
|
||||
*/
|
||||
public static String table(String tableName, String script) {
|
||||
return script.replace("${table}", tableName);
|
||||
}
|
||||
|
||||
private final Map<String,String> placeholders = new HashMap<String, String>();
|
||||
|
||||
ScriptTransform(Map<String,String> map) {
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
placeholders.put(wrapKey(entry.getKey()), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private String wrapKey(String key) {
|
||||
return "${"+key+"}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this contains no placeholders.
|
||||
*/
|
||||
boolean isEmpty() {
|
||||
return placeholders.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the script replacing placeholders in the form <code>${key}</code> with <code>value</code>.
|
||||
*/
|
||||
String transform(String source) {
|
||||
|
||||
for (Map.Entry<String, String> entry : placeholders.entrySet()) {
|
||||
source = source.replace(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return source;
|
||||
}
|
||||
}
|
||||
@@ -46,33 +46,4 @@ public abstract class AbstractBeanPersistListener implements BeanPersistListener
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that a bean was inserted on another node of the cluster.
|
||||
*
|
||||
* @param id the id value of the inserted bean
|
||||
*/
|
||||
@Override
|
||||
public void remoteInsert(Object id) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that a bean was updated on another node of the cluster.
|
||||
*
|
||||
* @param id the id value of the updated bean.
|
||||
*/
|
||||
@Override
|
||||
public void remoteUpdate(Object id) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that a bean was deleted on another node of the cluster.
|
||||
*
|
||||
* @param id the id value of the deleted bean.
|
||||
*/
|
||||
@Override
|
||||
public void remoteDelete(Object id) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,28 +74,4 @@ public interface BeanPersistListener {
|
||||
*/
|
||||
boolean deleted(Object bean);
|
||||
|
||||
/**
|
||||
* Notify that a bean was inserted on another node of the cluster.
|
||||
*
|
||||
* @param id
|
||||
* the id value of the inserted bean
|
||||
*/
|
||||
void remoteInsert(Object id);
|
||||
|
||||
/**
|
||||
* Notify that a bean was updated on another node of the cluster.
|
||||
*
|
||||
* @param id
|
||||
* the id value of the updated bean.
|
||||
*/
|
||||
void remoteUpdate(Object id);
|
||||
|
||||
/**
|
||||
* Notify that a bean was deleted on another node of the cluster.
|
||||
*
|
||||
* @param id
|
||||
* the id value of the deleted bean.
|
||||
*/
|
||||
void remoteDelete(Object id);
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -5,11 +5,9 @@ import com.avaje.ebean.event.BeanFindController;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.text.json.JsonReadOptions;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocumentMapping;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
@@ -17,6 +15,11 @@ import java.util.Collection;
|
||||
*/
|
||||
public interface BeanType<T> {
|
||||
|
||||
/**
|
||||
* Return the short name of the bean type.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the full name of the bean type.
|
||||
*/
|
||||
@@ -53,12 +56,12 @@ public interface BeanType<T> {
|
||||
Property getWhenCreatedProperty();
|
||||
|
||||
/**
|
||||
* Return the SpiProperty for a property to read values from a bean.
|
||||
* Return the Property to read values from a bean.
|
||||
*/
|
||||
Property getProperty(String propertyName);
|
||||
|
||||
/**
|
||||
* Return the SpiExpressionPath for a given property path.
|
||||
* Return the ExpressionPath for a given property path.
|
||||
* <p>
|
||||
* This can return a property or nested property path.
|
||||
* </p>
|
||||
@@ -150,8 +153,27 @@ public interface BeanType<T> {
|
||||
BeanDocType<T> docStore();
|
||||
|
||||
/**
|
||||
* Read the JSON content returning the bean.
|
||||
* Add the discriminator value to the query if needed.
|
||||
*/
|
||||
T jsonRead(JsonParser parser, JsonReadOptions readOptions, Object objectMapper) throws IOException;
|
||||
void addInheritanceWhere(SpiQuery<?> query);
|
||||
|
||||
/**
|
||||
* Return the root bean type for an inheritance hierarchy.
|
||||
*/
|
||||
BeanType<?> root();
|
||||
|
||||
/**
|
||||
* Return true if this bean type has an inheritance hierarchy.
|
||||
*/
|
||||
boolean hasInheritance();
|
||||
|
||||
/**
|
||||
* Return the discriminator column.
|
||||
*/
|
||||
String getDiscColumn();
|
||||
|
||||
/**
|
||||
* Create a bean given the discriminator value.
|
||||
*/
|
||||
T createBeanUsingDisc(Object discValue);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.avaje.ebean.plugin;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.text.StringParser;
|
||||
|
||||
/**
|
||||
* A dot notation expression path.
|
||||
*/
|
||||
@@ -10,11 +13,64 @@ public interface ExpressionPath {
|
||||
*/
|
||||
boolean containsMany();
|
||||
|
||||
/**
|
||||
* Return the value from a given entity bean.
|
||||
*/
|
||||
Object pathGet(Object bean);
|
||||
|
||||
/**
|
||||
* Set a value to the bean for this expression path.
|
||||
*
|
||||
* @param bean the bean to set the value on
|
||||
* @param value the value to set
|
||||
*/
|
||||
void set(Object bean, Object value);
|
||||
void pathSet(Object bean, Object value);
|
||||
|
||||
/**
|
||||
* Convert the value to the expected type.
|
||||
* <p>
|
||||
* Typically useful for converting strings to the appropriate number type etc.
|
||||
* </p>
|
||||
*/
|
||||
Object convert(Object value);
|
||||
|
||||
/**
|
||||
* Return the default StringParser for the scalar property.
|
||||
*/
|
||||
StringParser getStringParser();
|
||||
|
||||
/**
|
||||
* For DateTime capable scalar types convert the long systemTimeMillis into
|
||||
* an appropriate java time (Date,Timestamp,Time,Calendar, JODA type etc).
|
||||
*/
|
||||
Object parseDateTime(long systemTimeMillis);
|
||||
|
||||
/**
|
||||
* Return true if the last type is "DateTime capable" - can support
|
||||
* {@link #parseDateTime(long)}.
|
||||
*/
|
||||
boolean isDateTimeCapable();
|
||||
|
||||
/**
|
||||
* Return the underlying JDBC type or 0 if this is not a scalar type.
|
||||
*/
|
||||
int getJdbcType();
|
||||
|
||||
/**
|
||||
* Return true if this is an ManyToOne or OneToOne associated bean property.
|
||||
*/
|
||||
boolean isAssocId();
|
||||
|
||||
/**
|
||||
* Return the Id expression string.
|
||||
* <p>
|
||||
* Typically used to produce id = ? expression strings.
|
||||
* </p>
|
||||
*/
|
||||
String getAssocIdExpression(String propName, String bindOperator);
|
||||
|
||||
/**
|
||||
* Return the Id values for the given bean value.
|
||||
*/
|
||||
Object[] getAssocIdValues(EntityBean bean);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -40,4 +41,10 @@ public interface SpiServer extends EbeanServer {
|
||||
* Return the bean type for a given doc store queueId.
|
||||
*/
|
||||
BeanType<?> getBeanTypeForQueueId(String queueId);
|
||||
|
||||
/**
|
||||
* Return the associated DataSource for this EbeanServer instance.
|
||||
*/
|
||||
DataSource getDataSource();
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user