mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
356
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03ff53c7af | ||
|
|
c20d111ea2 | ||
|
|
920fa73d11 | ||
|
|
cd62686337 | ||
|
|
e9ad459fa5 | ||
|
|
ea5e9fa75a | ||
|
|
d44460e180 | ||
|
|
0e5ebf3fea | ||
|
|
42d35f8ec6 | ||
|
|
7f52e466e0 | ||
|
|
861a8a4ee5 | ||
|
|
abe2f76d5c | ||
|
|
d0f75a940c | ||
|
|
44ad78b5e0 | ||
|
|
967b4de784 | ||
|
|
ea45201905 | ||
|
|
938f4ec9c2 | ||
|
|
99bd2972d0 | ||
|
|
deac291951 | ||
|
|
3161e24677 | ||
|
|
37804bd083 | ||
|
|
0a2a987695 | ||
|
|
4a085cb819 | ||
|
|
67469ef4d3 | ||
|
|
c3f43d503f | ||
|
|
9158f46bb3 | ||
|
|
b3bfa88eb5 | ||
|
|
185dec9c02 | ||
|
|
20634233ca | ||
|
|
7c9dda586e | ||
|
|
3ca0f7b776 | ||
|
|
85caca48de | ||
|
|
ff85a51994 | ||
|
|
6dc3038d0d | ||
|
|
c0fcb77f3d | ||
|
|
da5d5296b6 | ||
|
|
f04ab28c3f | ||
|
|
d6cd41f8d2 | ||
|
|
504a209a78 | ||
|
|
9f98b5333d | ||
|
|
2a600adbcf | ||
|
|
9ce6007330 | ||
|
|
7780dd6272 | ||
|
|
b01ddea781 | ||
|
|
b848587cd3 | ||
|
|
fe7e929a99 | ||
|
|
3ee0b0224e | ||
|
|
169eba4296 | ||
|
|
91d3279061 | ||
|
|
b4b7c631da | ||
|
|
4f98ca5d91 | ||
|
|
014a9aef6f | ||
|
|
f21c33df7b | ||
|
|
f1eb494e0d | ||
|
|
d26203db1f | ||
|
|
abfe58fb06 | ||
|
|
d0ad5f6c48 | ||
|
|
bc4a246f33 | ||
|
|
61f590944b | ||
|
|
223e53416d | ||
|
|
a3143b1cf6 | ||
|
|
bd3e7c8035 | ||
|
|
b753ce3a73 | ||
|
|
a0f2ebe448 | ||
|
|
7e7810602e | ||
|
|
d218fff374 | ||
|
|
a0e927d353 | ||
|
|
51a58d4993 | ||
|
|
b9f0ee7ac0 | ||
|
|
4f3b461f8e | ||
|
|
adfe5f0305 | ||
|
|
1796c8b9bc | ||
|
|
4bad4358f0 | ||
|
|
92665ebc3b | ||
|
|
59670d0303 | ||
|
|
244275fd72 | ||
|
|
d1e2176a5a | ||
|
|
43968e70b8 | ||
|
|
0aa3bd3c97 | ||
|
|
2d85a9a20c | ||
|
|
157dfcfeb6 | ||
|
|
2b7c204072 | ||
|
|
be731feb6b | ||
|
|
da15d0b2c6 | ||
|
|
9c5fd496c1 | ||
|
|
5075ea32b4 | ||
|
|
f5c8d8896f | ||
|
|
32fdff9f11 | ||
|
|
87f6964995 | ||
|
|
b45226dd41 | ||
|
|
992c40d362 | ||
|
|
9144d60948 | ||
|
|
6396143d49 | ||
|
|
ce045ca0fe | ||
|
|
d722d34072 | ||
|
|
2cc4c2c265 | ||
|
|
0a830841c4 | ||
|
|
c427009b93 | ||
|
|
7f42d045ac | ||
|
|
43afaf1344 | ||
|
|
6c182ecaa5 | ||
|
|
fdb839f90e | ||
|
|
16be213faf | ||
|
|
3344f0ddb0 | ||
|
|
479ac38537 | ||
|
|
e30ad80f5f | ||
|
|
08e46d6bf3 | ||
|
|
876476fdc1 | ||
|
|
81de83a6e7 | ||
|
|
b5b221ffb1 | ||
|
|
3c6eab6c85 | ||
|
|
1be30f1671 | ||
|
|
9a5cb242ce | ||
|
|
ea69cae4a3 | ||
|
|
629fb7a433 | ||
|
|
4ff10da739 | ||
|
|
9472592a50 | ||
|
|
f42682ca90 | ||
|
|
5dc296e644 | ||
|
|
380660913f | ||
|
|
d08ac6973e | ||
|
|
9d23c1d56e | ||
|
|
b5d6c5f70b | ||
|
|
3657d05774 | ||
|
|
2de8ae777d | ||
|
|
16950a5641 | ||
|
|
ad992d07ce | ||
|
|
cbcec8f5ea | ||
|
|
6e2148d20b | ||
|
|
ca1c0a08f3 | ||
|
|
baa6fc355e | ||
|
|
dacdc26902 | ||
|
|
48edf64013 | ||
|
|
e2ee6e8e98 | ||
|
|
e6e6a28245 | ||
|
|
82a695a98a | ||
|
|
cdad31bd8a | ||
|
|
4d16cf9caa | ||
|
|
84a86cad0e | ||
|
|
dfdf87fa2d | ||
|
|
ee0615caec | ||
|
|
79b8395f8f | ||
|
|
87c479cd95 | ||
|
|
abbdda810a | ||
|
|
e621900de9 | ||
|
|
76b33511e1 | ||
|
|
77deab5cf0 | ||
|
|
4a9f8cef0e | ||
|
|
4d1340c16c | ||
|
|
74c6c71301 | ||
|
|
0f0028eb1f | ||
|
|
b4a1d52067 | ||
|
|
d82148248c | ||
|
|
dc7c854432 | ||
|
|
7c83010df1 | ||
|
|
ed41e58073 | ||
|
|
5bab9eb648 | ||
|
|
5ce8eb6046 | ||
|
|
56fee2ea9b | ||
|
|
84f32c2ace | ||
|
|
85288a0652 | ||
|
|
3183287833 | ||
|
|
780ee7c7c0 | ||
|
|
2bac7bf84d | ||
|
|
499862438d | ||
|
|
4ad0b7cf66 | ||
|
|
6108ef484b | ||
|
|
b763f4c875 | ||
|
|
ca7285b2ad | ||
|
|
75b639bc15 | ||
|
|
1a7c4dac3f | ||
|
|
6828fa1786 | ||
|
|
ba7e729ae1 | ||
|
|
c3fba72a24 | ||
|
|
ff401cfc72 | ||
|
|
7902276296 | ||
|
|
95f7a85aa1 | ||
|
|
cf9eb4ed97 | ||
|
|
b5cb04a6ed | ||
|
|
5a9193f732 | ||
|
|
55584f09d5 | ||
|
|
05eb0bfc55 | ||
|
|
cf13119b49 | ||
|
|
e0eff149b5 | ||
|
|
474c2d5595 | ||
|
|
e58cec8bdd | ||
|
|
9dd82c0dd7 | ||
|
|
49d3cc91e4 | ||
|
|
a8c2fc2ed5 | ||
|
|
45d7e3cafd | ||
|
|
be6754bd06 | ||
|
|
83c16ad1c6 | ||
|
|
3f8b389999 | ||
|
|
b4b6a13e75 | ||
|
|
3fad4aae2f | ||
|
|
ceab95e6c2 | ||
|
|
84b37fb014 | ||
|
|
1a1c432c2a | ||
|
|
86faa947af | ||
|
|
6b54b6ef46 | ||
|
|
d8dfd66af3 | ||
|
|
675c51b8c1 | ||
|
|
3cd7ecaa4a | ||
|
|
1b322955ee | ||
|
|
8115c5e230 | ||
|
|
ad180c5531 | ||
|
|
b454f46dd4 | ||
|
|
8a853b28f3 | ||
|
|
a1be7ba5dd | ||
|
|
3914516793 | ||
|
|
8c5854f77c | ||
|
|
0bc5b94eae | ||
|
|
12fa287f35 | ||
|
|
2991cb9ad1 | ||
|
|
3b7f5496a8 | ||
|
|
4be703ff6e | ||
|
|
d2c5765ac1 | ||
|
|
aaf256b9be | ||
|
|
c7c6410cd9 | ||
|
|
2c3c23725a | ||
|
|
92069c0319 | ||
|
|
630ad66ff1 | ||
|
|
b732b390c7 | ||
|
|
8c62fcdcb2 | ||
|
|
e458f577fe | ||
|
|
23434bab8c | ||
|
|
c47b5a1595 | ||
|
|
411846347b | ||
|
|
3722d19424 | ||
|
|
04a7310e5d | ||
|
|
3490e90f03 | ||
|
|
d89817a5c5 | ||
|
|
db1ba5f20e | ||
|
|
4f9a9a5094 | ||
|
|
1c6ac1289d | ||
|
|
b96be84106 | ||
|
|
3c40293183 | ||
|
|
a9a6031986 | ||
|
|
b82085da42 | ||
|
|
9a17a7752c | ||
|
|
92474c2b24 | ||
|
|
9a00b9df0e | ||
|
|
697f67c14a | ||
|
|
2c34bc1636 | ||
|
|
1f9ccf1c8b | ||
|
|
a1f10b8704 | ||
|
|
3c21950b91 | ||
|
|
3b45308ac7 | ||
|
|
00e69e1b5d | ||
|
|
11b3f7a813 | ||
|
|
2185c8a886 | ||
|
|
f8bda05b37 | ||
|
|
0a3b819991 | ||
|
|
5c8b1eb3bb | ||
|
|
824f6dcc7e | ||
|
|
06e23b85ad | ||
|
|
09219c759b | ||
|
|
b861038568 | ||
|
|
bfd8445bcd | ||
|
|
c30e3bf78c | ||
|
|
c793d6652f | ||
|
|
d12e55c20b | ||
|
|
3477f590dd | ||
|
|
6bbf93aba8 | ||
|
|
42d02cc521 | ||
|
|
9ea58572de | ||
|
|
35d82c9104 | ||
|
|
31aae38616 | ||
|
|
f144b53651 | ||
|
|
f47cd7e7c2 | ||
|
|
8765cb8356 | ||
|
|
30abe75a96 | ||
|
|
164e6c71c1 | ||
|
|
dfa6353850 | ||
|
|
d88ff2a3b2 | ||
|
|
713ae75464 | ||
|
|
710fb0e947 | ||
|
|
cb0cf97f3f | ||
|
|
07edb2c81f | ||
|
|
066effa5bf | ||
|
|
bb5ca6c56e | ||
|
|
a64a020e36 | ||
|
|
c24ee53462 | ||
|
|
06e4bdca0e | ||
|
|
3dbf35aca4 | ||
|
|
cd56b3ca3c | ||
|
|
353175626d | ||
|
|
1a3acb86df | ||
|
|
1304646cce | ||
|
|
b3828572fd | ||
|
|
eddd48f8ad | ||
|
|
9797502ef2 | ||
|
|
daba7a11b4 | ||
|
|
92caf69cb3 | ||
|
|
a954f8e9e1 | ||
|
|
71f70c01ae | ||
|
|
74d7652044 | ||
|
|
d7ee748f31 | ||
|
|
2442eb017a | ||
|
|
37ea56ad11 | ||
|
|
067a8b784c | ||
|
|
b18922df79 | ||
|
|
70cce1094e | ||
|
|
44c69dec72 | ||
|
|
6c7074e288 | ||
|
|
1c162b9b18 | ||
|
|
676f0d7a24 | ||
|
|
46e674db57 | ||
|
|
0e1aacdeee | ||
|
|
7268890332 | ||
|
|
b2a3f0c99b | ||
|
|
662be92a16 | ||
|
|
11d623cb69 | ||
|
|
a20822a9e1 | ||
|
|
0510304c0f | ||
|
|
fb2488e3b8 | ||
|
|
5959dcc7db | ||
|
|
3656091d1f | ||
|
|
5122ea4b4d | ||
|
|
db8dd48e53 | ||
|
|
4606c7c99f | ||
|
|
e3a7c3040b | ||
|
|
cb51ea4238 | ||
|
|
a1a48dac2c | ||
|
|
b8d9273152 | ||
|
|
026f0e161f | ||
|
|
75a2633590 | ||
|
|
362ceea79b | ||
|
|
1c9b974427 | ||
|
|
f181e3946f | ||
|
|
6df145b4fa | ||
|
|
a4cb116d4f | ||
|
|
3161664d58 | ||
|
|
4b3f63f6e0 | ||
|
|
d89b1b0367 | ||
|
|
17433bb70b | ||
|
|
fb6ea92ae9 | ||
|
|
08b0a6350d | ||
|
|
bd330b4c0e | ||
|
|
ec234f1f39 | ||
|
|
dd28b28095 | ||
|
|
2a5be6db3d | ||
|
|
545f40703e | ||
|
|
35d0481644 | ||
|
|
2282ff3c6e | ||
|
|
d1d4bf1da8 | ||
|
|
8c6653605d | ||
|
|
e344b5c0a1 | ||
|
|
0e5859716b | ||
|
|
90a794fca5 | ||
|
|
1d6e480402 | ||
|
|
54706302df | ||
|
|
4a59cf4c3d | ||
|
|
8cb8f9eabf | ||
|
|
58a36e6b67 | ||
|
|
064d282f7b |
@@ -6,12 +6,12 @@ Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Web
|
||||
|
||||
|
||||
## 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 - ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebean%22%20AND%20a%3A%22ebean%22 "maven central ebean")
|
||||
|
||||
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cavaje-ebeanorm "maven central ebeanorm")
|
||||
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
|
||||
|
||||
## 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
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean) - ebean
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent) - ebean-agent
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin) - ebean-maven-plugin
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
<version>1.1</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>7.11.2</version>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>8.7.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
<name>ebean</name>
|
||||
<url>http://ebean-orm.github.io/</url>
|
||||
|
||||
<properties>
|
||||
@@ -36,8 +36,8 @@
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git</developerConnection>
|
||||
<tag>avaje-ebeanorm-7.11.2</tag>
|
||||
<developerConnection>scm:git:https://github.com/ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-8.7.1</tag>
|
||||
</scm>
|
||||
|
||||
<dependencies>
|
||||
@@ -69,13 +69,19 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-classpath-scanner-api</artifactId>
|
||||
<version>2.1</version>
|
||||
<version>2.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-classpath-scanner</artifactId>
|
||||
<version>2.1.1</version>
|
||||
<version>2.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-dbmigration</artifactId>
|
||||
<version>1.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -84,6 +90,12 @@
|
||||
<version>[1.7.1,1.7.99)</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-runtime</artifactId>
|
||||
<version>4.5.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
@@ -160,9 +172,9 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-agent</artifactId>
|
||||
<version>4.9.2</version>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<artifactId>ebean-agent</artifactId>
|
||||
<version>8.1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -171,7 +183,7 @@
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.189</version>
|
||||
<version>1.4.192</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -235,16 +247,15 @@
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
|
||||
<version>4.9.2</version>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>8.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
<phase>process-test-classes</phase>
|
||||
<configuration>
|
||||
<classSource>target/test-classes</classSource>
|
||||
<packages>com.avaje.tests.**</packages>
|
||||
<transformArgs>debug=1</transformArgs>
|
||||
</configuration>
|
||||
<goals>
|
||||
@@ -292,7 +303,7 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<doctitle>Ebean 7</doctitle>
|
||||
<doctitle>Ebean 8</doctitle>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
|
||||
@@ -38,6 +38,11 @@ public interface BeanState {
|
||||
*/
|
||||
void setDisableLazyLoad(boolean disableLazyLoading);
|
||||
|
||||
/**
|
||||
* Return true if the bean has lazy loading disabled.
|
||||
*/
|
||||
boolean isDisableLazyLoad();
|
||||
|
||||
/**
|
||||
* Set the loaded state of the property given it's name.
|
||||
*
|
||||
@@ -115,4 +120,9 @@ public interface BeanState {
|
||||
* for a fully loaded entity bean.
|
||||
*/
|
||||
void setLoaded();
|
||||
|
||||
/**
|
||||
* Reset the bean putting it into NEW state such that a save() results in an insert.
|
||||
*/
|
||||
void resetForInsert();
|
||||
}
|
||||
@@ -49,7 +49,7 @@ final class DRawSqlColumnsParser {
|
||||
if (split.length > 1) {
|
||||
ArrayList<String> tmp = new ArrayList<String>(split.length);
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
if (split[i].trim().length() > 0) {
|
||||
if (!split[i].trim().isEmpty()) {
|
||||
tmp.add(split[i].trim());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Document storage operations.
|
||||
@@ -205,6 +206,39 @@ public interface DocumentStore {
|
||||
*/
|
||||
void createIndex(String indexName, String alias);
|
||||
|
||||
/**
|
||||
* Modify the settings on an index.
|
||||
* <p>
|
||||
* For example, this can be used be used to set elasticSearch refresh_interval
|
||||
* on an index before a bulk update.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // refresh_interval -1 ... disable refresh while bulk loading
|
||||
*
|
||||
* Map<String,Object> settings = new LinkedHashMap<>();
|
||||
* settings.put("refresh_interval", "-1");
|
||||
*
|
||||
* documentStore.indexSettings("product", settings);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // refresh_interval 1s ... restore after bulk loading
|
||||
*
|
||||
* Map<String,Object> settings = new LinkedHashMap<>();
|
||||
* settings.put("refresh_interval", "1s");
|
||||
*
|
||||
* documentStore.indexSettings("product", settings);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param indexName the name of the index to update settings on
|
||||
* @param settings the settings to set on the index
|
||||
*/
|
||||
void indexSettings(String indexName, Map<String, Object> settings);
|
||||
|
||||
/**
|
||||
* Copy the index to a new index.
|
||||
* <p>
|
||||
|
||||
@@ -161,7 +161,7 @@ public final class Ebean {
|
||||
// look to see if there is a default server defined
|
||||
String defaultName = PrimaryServer.getDefaultServerName();
|
||||
logger.debug("defaultName:" + defaultName);
|
||||
if (defaultName != null && defaultName.trim().length() > 0) {
|
||||
if (defaultName != null && !defaultName.trim().isEmpty()) {
|
||||
defaultServer = getWithCreate(defaultName.trim());
|
||||
}
|
||||
}
|
||||
@@ -182,7 +182,7 @@ public final class Ebean {
|
||||
}
|
||||
|
||||
private EbeanServer get(String name) {
|
||||
if (name == null || name.length() == 0) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
return defaultServer;
|
||||
}
|
||||
// non-synchronized read
|
||||
@@ -499,6 +499,13 @@ public final class Ebean {
|
||||
serverMgr.getDefaultServer().endTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the current transaction as rollback only.
|
||||
*/
|
||||
public static void setRollbackOnly() {
|
||||
serverMgr.getDefaultServer().currentTransaction().setRollbackOnly();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of the differences between two objects of the same type.
|
||||
* <p>
|
||||
@@ -639,58 +646,6 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().saveAll(beans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the associations (from the intersection table) of a ManyToMany given
|
||||
* the owner bean and the propertyName of the ManyToMany collection.
|
||||
* <p>
|
||||
* Typically these deletions occur automatically when persisting a ManyToMany
|
||||
* collection and this provides a way to invoke those deletions directly.
|
||||
* </p>
|
||||
*
|
||||
* @return the number of associations deleted (from the intersection table).
|
||||
*/
|
||||
public static int deleteManyToManyAssociations(Object ownerBean, String propertyName) {
|
||||
return serverMgr.getDefaultServer().deleteManyToManyAssociations(ownerBean, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the associations of a ManyToMany given the owner bean and the
|
||||
* propertyName of the ManyToMany collection.
|
||||
* <p>
|
||||
* Typically the saving of these associations (inserting into the intersection
|
||||
* table) occurs automatically when persisting a ManyToMany. This provides a
|
||||
* way to invoke those insertions directly.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can use this when the collection is new and in this case all the
|
||||
* entries in the collection are treated as additions are result in inserts
|
||||
* into the intersection table.
|
||||
* </p>
|
||||
*/
|
||||
public static void saveManyToManyAssociations(Object ownerBean, String propertyName) {
|
||||
serverMgr.getDefaultServer().saveManyToManyAssociations(ownerBean, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the associated collection or bean given the property name.
|
||||
* <p>
|
||||
* This is similar to performing a save cascade on a specific property
|
||||
* manually/programmatically.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that you can turn on/off cascading for a transaction via
|
||||
* {@link Transaction#setPersistCascade(boolean)}
|
||||
* </p>
|
||||
*
|
||||
* @param ownerBean
|
||||
* the bean instance holding the property we want to save
|
||||
* @param propertyName
|
||||
* the property we want to save
|
||||
*/
|
||||
public static void saveAssociation(Object ownerBean, String propertyName) {
|
||||
serverMgr.getDefaultServer().saveAssociation(ownerBean, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the bean.
|
||||
* <p>
|
||||
@@ -932,19 +887,6 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().createSqlQuery(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a named sql query.
|
||||
* <p>
|
||||
* The query statement will be defined in a deployment orm xml file.
|
||||
* </p>
|
||||
*
|
||||
* @param namedQuery
|
||||
* the name of the query
|
||||
*/
|
||||
public static SqlQuery createNamedSqlQuery(String namedQuery) {
|
||||
return serverMgr.getDefaultServer().createNamedSqlQuery(namedQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sql update for executing native dml statements.
|
||||
* <p>
|
||||
@@ -954,10 +896,6 @@ public final class Ebean {
|
||||
* <p>
|
||||
* See {@link SqlUpdate} for example usage.
|
||||
* </p>
|
||||
* <p>
|
||||
* Where possible it would be expected practice to put the statement in a orm
|
||||
* xml file (named update) and use {@link #createNamedSqlUpdate(String)} .
|
||||
* </p>
|
||||
*/
|
||||
public static SqlUpdate createSqlUpdate(String sql) {
|
||||
return serverMgr.getDefaultServer().createSqlUpdate(sql);
|
||||
@@ -972,144 +910,6 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().createCallableSql(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a named sql update.
|
||||
* <p>
|
||||
* The statement (an Insert Update or Delete statement) will be defined in a
|
||||
* deployment orm xml file.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Use a namedQuery
|
||||
* UpdateSql update = Ebean.createNamedSqlUpdate("update.topic.count");
|
||||
*
|
||||
* update.setParameter("count", 1);
|
||||
* update.setParameter("topicId", 50);
|
||||
*
|
||||
* int modifiedCount = update.execute();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static SqlUpdate createNamedSqlUpdate(String namedQuery) {
|
||||
return serverMgr.getDefaultServer().createNamedSqlUpdate(namedQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a named Query that will have defined fetch paths, predicates etc.
|
||||
* <p>
|
||||
* The query is created from a statement that will be defined in a deployment
|
||||
* orm xml file or NamedQuery annotations. The query will typically already
|
||||
* define fetch paths, predicates, order by clauses etc so often you will just
|
||||
* need to bind required parameters and then execute the query.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // example
|
||||
* Query<Order> query = Ebean.createNamedQuery(Order.class, "new.for.customer");
|
||||
* query.setParameter("customerId", 23);
|
||||
* List<Order> newOrders = query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType
|
||||
* the class of entity to be fetched
|
||||
* @param namedQuery
|
||||
* the name of the query
|
||||
*/
|
||||
public static <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery) {
|
||||
|
||||
return serverMgr.getDefaultServer().createNamedQuery(beanType, namedQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query using the query language.
|
||||
* <p>
|
||||
* Note that you are allowed to add additional clauses using where() as well
|
||||
* as use fetch() and setOrderBy() after the query has been created.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that this method signature used to map to named queries and that has
|
||||
* moved to {@link #createNamedQuery(Class, String)}.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String q = "find order fetch details where status = :st";
|
||||
*
|
||||
* List<Order> newOrders = Ebean.>findOrder.class, q)
|
||||
* .setParameter("st", Order.Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param query
|
||||
* the object query
|
||||
*/
|
||||
public static <T> Query<T> createQuery(Class<T> beanType, String query) {
|
||||
return serverMgr.getDefaultServer().createQuery(beanType, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a named orm update. The update statement is specified via the
|
||||
* NamedUpdate annotation.
|
||||
* <p>
|
||||
* The orm update differs from the SqlUpdate in that it uses the bean name and
|
||||
* bean property names rather than table and column names.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that named update statements can be specified in raw sql (with column
|
||||
* and table names) or using bean name and bean property names. This can be
|
||||
* specified with the isSql flag.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example named updates:
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* package app.data;
|
||||
*
|
||||
* import ...
|
||||
*
|
||||
* @NamedUpdates(value = {
|
||||
* @NamedUpdate( name = "setTitle",
|
||||
* isSql = false,
|
||||
* notifyCache = false,
|
||||
* update = "update topic set title = :title, postCount = :postCount where id = :id"),
|
||||
* @NamedUpdate( name = "setPostCount",
|
||||
* notifyCache = false,
|
||||
* update = "update f_topic set post_count = :postCount where id = :id"),
|
||||
* @NamedUpdate( name = "incrementPostCount",
|
||||
* notifyCache = false,
|
||||
* isSql = false,
|
||||
* update = "update Topic set postCount = postCount + 1 where id = :id") })
|
||||
* @Entity
|
||||
* @Table(name = "f_topic")
|
||||
* public class Topic { ...
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Example using a named update:
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Update<Topic> update = Ebean.createNamedUpdate(Topic.class, "setPostCount");
|
||||
* update.setParameter("postCount", 10);
|
||||
* update.setParameter("id", 3);
|
||||
*
|
||||
* int rows = update.execute();
|
||||
* System.out.println("rows updated: " + rows);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static <T> Update<T> createNamedUpdate(Class<T> beanType, String namedUpdate) {
|
||||
|
||||
return serverMgr.getDefaultServer().createNamedUpdate(beanType, namedUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a orm update where you will supply the insert/update or delete
|
||||
* statement (rather than using a named one that is already defined using the
|
||||
@@ -1152,6 +952,21 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().createCsvReader(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a named query.
|
||||
* <p>
|
||||
* For RawSql the named query is expected to be in ebean.xml.
|
||||
* </p>
|
||||
*
|
||||
* @param beanType The type of entity bean
|
||||
* @param namedQuery The name of the query
|
||||
* @param <T> The type of entity bean
|
||||
* @return The query
|
||||
*/
|
||||
public static <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery) {
|
||||
return serverMgr.getDefaultServer().createNamedQuery(beanType, namedQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query for a type of entity bean.
|
||||
* <p>
|
||||
@@ -1167,39 +982,7 @@ public final class Ebean {
|
||||
* {@link Query#findSet()} etc will execute against the same EbeanServer from
|
||||
* which is was created.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* // Find order 2 additionally fetching the customer, details and details.product
|
||||
* // name.
|
||||
*
|
||||
* Order order = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .fetch("details")
|
||||
* .fetch("detail.product", "name")
|
||||
* .setId(2)
|
||||
* .findUnique();
|
||||
*
|
||||
* // Find order 2 additionally fetching the customer, details and details.product
|
||||
* // name.
|
||||
* // Note: same query as above but using the query language
|
||||
* // Note: using a named query would be preferred practice
|
||||
*
|
||||
* String oql = "find order fetch customer fetch details fetch details.product (name) where id = :orderId ";
|
||||
*
|
||||
* Query<Order> query = Ebean.find(Order.class);
|
||||
* query.setQuery(oql);
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* // Using a named query
|
||||
* Query<Order> query = Ebean.find(Order.class, "with.details");
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* @param beanType
|
||||
* the class of entity to be fetched
|
||||
* @return A ORM Query object for this beanType
|
||||
@@ -1209,6 +992,47 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().createQuery(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the Ebean query language statement returning the query which can then
|
||||
* be modified (add expressions, change order by clause, change maxRows, change
|
||||
* fetch and select paths etc).
|
||||
*
|
||||
* <h3>Example</h3>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
*
|
||||
* // Find order additionally fetching the customer, details and details.product name.
|
||||
*
|
||||
* String eql = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class, eql);
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* // This is the same as:
|
||||
*
|
||||
* Order order = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .fetch("details")
|
||||
* .fetch("detail.product", "name")
|
||||
* .setId(2)
|
||||
* .findUnique();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The type of bean to fetch
|
||||
* @param eql The Ebean query
|
||||
* @param <T> The type of the entity bean
|
||||
*
|
||||
* @return The query with expressions defined as per the parsed query statement
|
||||
*/
|
||||
public static <T> Query<T> createQuery(Class<T> beanType, String eql) {
|
||||
|
||||
return serverMgr.getDefaultServer().createQuery(beanType, eql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query for a type of entity bean.
|
||||
* <p>
|
||||
@@ -1226,6 +1050,28 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().find(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Update query to perform a bulk update.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = Ebean.update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The type of entity bean to update
|
||||
* @param <T> The type of entity bean
|
||||
* @return The update query to use
|
||||
*/
|
||||
public static <T> UpdateQuery<T> update(Class<T> beanType) {
|
||||
return serverMgr.getDefaultServer().update(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a filter for sorting and filtering lists of entities locally without
|
||||
* going back to the database.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -135,6 +135,11 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression ieq(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case Insensitive Equal To that allows for named parameter use.
|
||||
*/
|
||||
Expression ieqObject(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
@@ -192,6 +197,11 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType);
|
||||
|
||||
/**
|
||||
* Like with support for named parameters.
|
||||
*/
|
||||
Expression like(String propertyName, Object value, boolean caseInsensitive, LikeType likeType);
|
||||
|
||||
/**
|
||||
* Like - property like value where the value contains the SQL wild card
|
||||
* characters % (percentage) and _ (underscore).
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.util.Set;
|
||||
* more methods than you would initially expect (the ones duplicated from
|
||||
* Query).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @see Query#where()
|
||||
*/
|
||||
public interface ExpressionList<T> {
|
||||
@@ -83,14 +83,14 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Add an orderBy clause to the query.
|
||||
*
|
||||
*
|
||||
* @see Query#orderBy(String)
|
||||
*/
|
||||
Query<T> orderBy(String orderBy);
|
||||
|
||||
/**
|
||||
* Add an orderBy clause to the query.
|
||||
*
|
||||
*
|
||||
* @see Query#orderBy(String)
|
||||
*/
|
||||
Query<T> setOrderBy(String orderBy);
|
||||
@@ -116,12 +116,6 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Query<T> asDraft();
|
||||
|
||||
/**
|
||||
* Deprecated in favour of setIncludeSoftDeletes().
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> includeSoftDeletes();
|
||||
|
||||
/**
|
||||
* Execute the query including soft deleted rows.
|
||||
*/
|
||||
@@ -135,13 +129,21 @@ public interface ExpressionList<T> {
|
||||
* optimal depending on the database platform.
|
||||
* </p>
|
||||
*
|
||||
* @return the number of beans/rows that were deleted.
|
||||
* @return the number of rows that were deleted.
|
||||
*/
|
||||
int delete();
|
||||
|
||||
/**
|
||||
* Execute as a update query.
|
||||
*
|
||||
* @return the number of rows that were updated.
|
||||
* @see UpdateQuery
|
||||
*/
|
||||
int update();
|
||||
|
||||
/**
|
||||
* Execute the query iterating over the results.
|
||||
*
|
||||
*
|
||||
* @see Query#findIterate()
|
||||
*/
|
||||
QueryIterator<T> findIterate();
|
||||
@@ -163,17 +165,17 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Execute the query returning a list.
|
||||
*
|
||||
*
|
||||
* @see Query#findList()
|
||||
*/
|
||||
List<T> findList();
|
||||
|
||||
/**
|
||||
* Execute the query returning the list of Id's.
|
||||
*
|
||||
*
|
||||
* @see Query#findIds()
|
||||
*/
|
||||
List<Object> findIds();
|
||||
<A> List<A> findIds();
|
||||
|
||||
/**
|
||||
* Return the count of entities this query should return.
|
||||
@@ -181,26 +183,53 @@ public interface ExpressionList<T> {
|
||||
* This is the number of 'top level' or 'root level' entities.
|
||||
* </p>
|
||||
*/
|
||||
int findRowCount();
|
||||
int findCount();
|
||||
|
||||
/**
|
||||
* Execute the query returning a set.
|
||||
*
|
||||
*
|
||||
* @see Query#findSet()
|
||||
*/
|
||||
Set<T> findSet();
|
||||
|
||||
/**
|
||||
* Execute the query returning a map.
|
||||
*
|
||||
*
|
||||
* @see Query#findMap()
|
||||
*/
|
||||
Map<?, T> findMap();
|
||||
<K> Map<K, T> findMap();
|
||||
|
||||
/**
|
||||
* Return a typed map specifying the key property and type.
|
||||
* Execute the query returning a list of values for a single property.
|
||||
*
|
||||
* <h3>Example 1:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* .select("name")
|
||||
* .orderBy().asc("name")
|
||||
* .findSingleAttributeList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Example 2:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .where().eq("status", Customer.Status.NEW)
|
||||
* .orderBy().asc("name")
|
||||
* .setMaxRows(100)
|
||||
* .findSingleAttributeList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @return the list of values for the selected property
|
||||
*/
|
||||
<K> Map<K, T> findMap(String keyProperty, Class<K> keyType);
|
||||
<A> List<A> findSingleAttributeList();
|
||||
|
||||
/**
|
||||
* Execute the query returning a single bean or null (if no matching
|
||||
@@ -224,10 +253,10 @@ public interface ExpressionList<T> {
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return a Future object for the row count query
|
||||
*/
|
||||
FutureRowCount<T> findFutureRowCount();
|
||||
FutureRowCount<T> findFutureCount();
|
||||
|
||||
/**
|
||||
* Execute find Id's query in a background thread.
|
||||
@@ -236,7 +265,7 @@ public interface ExpressionList<T> {
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return a Future object for the list of Id's
|
||||
*/
|
||||
FutureIds<T> findFutureIds();
|
||||
@@ -248,32 +277,11 @@ public interface ExpressionList<T> {
|
||||
* 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
|
||||
*/
|
||||
FutureList<T> findFutureList();
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query using pageIndex and pageSize.
|
||||
* <p>
|
||||
* The benefit of using this over just using the normal {@link Query#setFirstRow(int)} and
|
||||
* {@link Query#setMaxRows(int)} is that it additionally wraps an optional call to
|
||||
* {@link Query#findFutureRowCount()} to determine total row count, total page count etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* Internally this works using {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} on
|
||||
* the query. This translates into SQL that uses limit offset, rownum or row_number
|
||||
* function to limit the result set.
|
||||
* </p>
|
||||
*
|
||||
* @param pageIndex
|
||||
* The zero based index of the page.
|
||||
* @param pageSize
|
||||
* The number of beans to return per page.
|
||||
* @return The PagedList
|
||||
*/
|
||||
PagedList<T> findPagedList(int pageIndex, int pageSize);
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query using firstRow and maxRows.
|
||||
* <p>
|
||||
@@ -332,7 +340,7 @@ public interface ExpressionList<T> {
|
||||
/**
|
||||
* Specify specific properties to fetch on the main/root bean (aka partial
|
||||
* object).
|
||||
*
|
||||
*
|
||||
* @see Query#select(String)
|
||||
*/
|
||||
Query<T> select(String properties);
|
||||
@@ -357,28 +365,28 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Set the first row to fetch.
|
||||
*
|
||||
*
|
||||
* @see Query#setFirstRow(int)
|
||||
*/
|
||||
Query<T> setFirstRow(int firstRow);
|
||||
|
||||
/**
|
||||
* Set the maximum number of rows to fetch.
|
||||
*
|
||||
*
|
||||
* @see Query#setMaxRows(int)
|
||||
*/
|
||||
Query<T> setMaxRows(int maxRows);
|
||||
|
||||
/**
|
||||
* Set the name of the property which values become the key of a map.
|
||||
*
|
||||
*
|
||||
* @see Query#setMapKey(String)
|
||||
*/
|
||||
Query<T> setMapKey(String mapKey);
|
||||
|
||||
/**
|
||||
* Set to true to use the query for executing this query.
|
||||
*
|
||||
*
|
||||
* @see Query#setUseCache(boolean)
|
||||
*/
|
||||
Query<T> setUseCache(boolean useCache);
|
||||
@@ -639,7 +647,7 @@ public interface ExpressionList<T> {
|
||||
* To get control over the options you can create an ExampleExpression and set
|
||||
* those options such as case insensitive etc.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // create an example bean and set the properties
|
||||
@@ -647,26 +655,26 @@ public interface ExpressionList<T> {
|
||||
* Customer example = new Customer();
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
*
|
||||
* List<Customer> list = Ebean.find(Customer.class).where()
|
||||
* // pass the bean into the where() clause
|
||||
* .exampleLike(example)
|
||||
* // you can add other expressions to the same query
|
||||
* .gt("id", 2).findList();
|
||||
*
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* Similarly you can create an ExampleExpression
|
||||
*
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer example = new Customer();
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
*
|
||||
* // create a ExampleExpression with more control
|
||||
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO).includeZeros();
|
||||
*
|
||||
*
|
||||
* List<Customer> list = Ebean.find(Customer.class).where().add(qbe).findList();
|
||||
*
|
||||
* }</pre>
|
||||
@@ -768,7 +776,7 @@ public interface ExpressionList<T> {
|
||||
* Exists expression
|
||||
*/
|
||||
ExpressionList<T> exists(Query<?> subQuery);
|
||||
|
||||
|
||||
/**
|
||||
* Not exists expression
|
||||
*/
|
||||
@@ -795,7 +803,7 @@ public interface ExpressionList<T> {
|
||||
* Expression where all the property names in the map are equal to the
|
||||
* corresponding value.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param propertyMap
|
||||
* a map keyed by property names.
|
||||
*/
|
||||
@@ -945,7 +953,7 @@ public interface ExpressionList<T> {
|
||||
* This is exactly the same as conjunction();
|
||||
* </p>
|
||||
* <p>
|
||||
* Use endJunction() to end the AND junction.
|
||||
* Use endAnd() or endJunction() to end the AND junction.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that a where() clause defaults to an AND junction so
|
||||
@@ -963,11 +971,11 @@ public interface ExpressionList<T> {
|
||||
* .and() // nested and
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end AND junction
|
||||
* .endAnd()
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction() // end AND junction
|
||||
* .endAnd()
|
||||
* .orderBy().asc("name")
|
||||
* .findList();
|
||||
* }</pre>
|
||||
@@ -979,7 +987,7 @@ public interface ExpressionList<T> {
|
||||
* This is exactly the same as disjunction();
|
||||
*
|
||||
* <p>
|
||||
* Use endJunction() to end the OR junction.
|
||||
* Use endOr() or endJunction() to end the OR junction.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
@@ -993,11 +1001,11 @@ public interface ExpressionList<T> {
|
||||
* .and()
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end AND junction
|
||||
* .endAnd()
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction() // end AND junction
|
||||
* .endAnd()
|
||||
* .orderBy().asc("name")
|
||||
* .findList();
|
||||
*
|
||||
@@ -1008,7 +1016,7 @@ public interface ExpressionList<T> {
|
||||
/**
|
||||
* Return a list of expressions that will be wrapped by NOT.
|
||||
* <p>
|
||||
* Use endJunction() to end expressions being added to the
|
||||
* Use endNot() or endJunction() to end expressions being added to the
|
||||
* NOT expression list.
|
||||
* </p>
|
||||
*
|
||||
@@ -1018,7 +1026,7 @@ public interface ExpressionList<T> {
|
||||
* .not()
|
||||
* .gt("id", 1)
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end the not expressions
|
||||
* .endNot()
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
@@ -1032,7 +1040,7 @@ public interface ExpressionList<T> {
|
||||
* .not()
|
||||
* .gt("id", 1)
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end the not expressions
|
||||
* .endNot()
|
||||
* .orderBy()
|
||||
* .asc("name")
|
||||
* .findList();
|
||||
@@ -1105,4 +1113,19 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> endJunction();
|
||||
|
||||
/**
|
||||
* End a AND junction - synonym for endJunction().
|
||||
*/
|
||||
ExpressionList<T> endAnd();
|
||||
|
||||
/**
|
||||
* End a AND junction - synonym for endJunction().
|
||||
*/
|
||||
ExpressionList<T> endOr();
|
||||
|
||||
/**
|
||||
* End a NOT junction - synonym for endJunction().
|
||||
*/
|
||||
ExpressionList<T> endNot();
|
||||
|
||||
}
|
||||
|
||||
@@ -29,8 +29,7 @@ import java.io.Serializable;
|
||||
* // Find Orders join details using a single SQL query
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL
|
||||
* queries
|
||||
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL queries
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
@@ -117,7 +116,7 @@ import java.io.Serializable;
|
||||
* <pre>{@code
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer","name", new FetchConfig().lazy(5))
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .where().eq("status",Order.Status.NEW)
|
||||
* .findList();
|
||||
@@ -125,12 +124,7 @@ import java.io.Serializable;
|
||||
* // query 1) find order where status = Order.Status.NEW
|
||||
* //
|
||||
* // .. if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* find customer (name)
|
||||
* fetch customer.contacts (contactName, phone, email)
|
||||
* fetch customer.shippingAddress (*)
|
||||
* where id in (?,?,?,?,?)
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
|
||||
@@ -9,8 +9,6 @@ import java.util.concurrent.Future;
|
||||
* It extends the java.util.concurrent.Future with the ability to get the Id's
|
||||
* while the query is still executing in the background.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface FutureIds<T> extends Future<List<Object>> {
|
||||
|
||||
@@ -19,16 +17,4 @@ public interface FutureIds<T> extends Future<List<Object>> {
|
||||
*/
|
||||
Query<T> getQuery();
|
||||
|
||||
/**
|
||||
* Return the list of Id's which could be partially populated.
|
||||
* <p>
|
||||
* That is the query getting the id's could still be running and adding id's
|
||||
* to this list.
|
||||
* </p>
|
||||
* <p>
|
||||
* To get the list of Id's ensuring the query has finished use the
|
||||
* {@link Future#get()} method instead of this one.
|
||||
* </p>
|
||||
*/
|
||||
List<Object> getPartialIds();
|
||||
}
|
||||
|
||||
@@ -59,11 +59,11 @@ package com.avaje.ebean;
|
||||
* .and()
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction()
|
||||
* .endAnd()
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction()
|
||||
* .endAnd()
|
||||
* .order().asc("name");
|
||||
*
|
||||
* q.findList();
|
||||
@@ -84,39 +84,41 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
|
||||
/**
|
||||
* AND group.
|
||||
*/
|
||||
AND(" and ", ""),
|
||||
AND(" and ", "", false),
|
||||
|
||||
/**
|
||||
* OR group.
|
||||
*/
|
||||
OR(" or ", ""),
|
||||
OR(" or ", "", false),
|
||||
|
||||
/**
|
||||
* NOT group.
|
||||
*/
|
||||
NOT(" and ", "not "),
|
||||
NOT(" and ", "not ", false),
|
||||
|
||||
/**
|
||||
* Text search AND group.
|
||||
*/
|
||||
MUST("must", ""),
|
||||
MUST("must", "", true),
|
||||
|
||||
/**
|
||||
* Text search NOT group.
|
||||
*/
|
||||
MUST_NOT("must_not", ""),
|
||||
MUST_NOT("must_not", "", true),
|
||||
|
||||
/**
|
||||
* Text search OR group.
|
||||
*/
|
||||
SHOULD("should", "");
|
||||
SHOULD("should", "", true);
|
||||
|
||||
String prefix;
|
||||
String literal;
|
||||
private String prefix;
|
||||
private String literal;
|
||||
private boolean text;
|
||||
|
||||
Type(String literal, String prefix) {
|
||||
Type(String literal, String prefix, boolean text) {
|
||||
this.literal = literal;
|
||||
this.prefix = prefix;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,6 +134,14 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
|
||||
public String prefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a text type.
|
||||
*/
|
||||
public boolean isText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -495,7 +495,7 @@ public abstract class Model {
|
||||
/**
|
||||
* Return typically a different EbeanServer to the default.
|
||||
* <p>
|
||||
* This is equivilent to {@link Ebean#getServer(String)}
|
||||
* This is equivalent to {@link Ebean#getServer(String)}
|
||||
*
|
||||
* @param server
|
||||
* The name of the EbeanServer. If this is null then the default EbeanServer is
|
||||
@@ -598,7 +598,7 @@ public abstract class Model {
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findIds()}
|
||||
*/
|
||||
public List<Object> findIds() {
|
||||
public <A> List<A> findIds() {
|
||||
return query().findIds();
|
||||
}
|
||||
|
||||
@@ -660,46 +660,43 @@ public abstract class Model {
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findMap()}
|
||||
*/
|
||||
public Map<?, T> findMap() {
|
||||
public <K> Map<K, T> findMap() {
|
||||
return query().findMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the query and returns the results as a map of the objects specifying the map key
|
||||
* property.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findMap(String, Class)}
|
||||
*/
|
||||
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
|
||||
return query().findMap(keyProperty, keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a PagedList of all entities of the given type (use where() to specify predicates as
|
||||
* needed).
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findPagedList(int, int)}
|
||||
*/
|
||||
public PagedList<T> findPagedList(int pageIndex, int pageSize) {
|
||||
return query().findPagedList(pageIndex, pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a find row count query in a background thread.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findFutureRowCount()}
|
||||
* Equivalent to {@link Query#findFutureCount()}
|
||||
*/
|
||||
public FutureRowCount<T> findFutureCount() {
|
||||
return query().findFutureCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated in favor of findFutureCount().
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findFutureCount()}
|
||||
*/
|
||||
public FutureRowCount<T> findFutureRowCount() {
|
||||
return query().findFutureRowCount();
|
||||
return query().findFutureCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of entities for this type. *
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findRowCount()}
|
||||
* Equivalent to {@link Query#findCount()}
|
||||
*/
|
||||
public int findCount() {
|
||||
return query().findCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated in favor of findCount().
|
||||
* @deprecated
|
||||
*/
|
||||
public int findRowCount() {
|
||||
return query().findRowCount();
|
||||
return query().findCount();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -843,15 +840,6 @@ public abstract class Model {
|
||||
return query().setId(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new query using the OQL.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#createQuery(Class, String)}
|
||||
*/
|
||||
public Query<T> setQuery(String oql) {
|
||||
return db().createQuery(type, oql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new query based on the <code>RawSql</code>.
|
||||
* <p>
|
||||
|
||||
@@ -148,6 +148,13 @@ public final class OrderBy<T> implements Serializable {
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the order by by parsing a raw expression.
|
||||
*/
|
||||
public void add(String rawExpression) {
|
||||
parse(rawExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property to the order by.
|
||||
*/
|
||||
@@ -206,8 +213,9 @@ public final class OrderBy<T> implements Serializable {
|
||||
* order by clause and replace.
|
||||
* </p>
|
||||
*/
|
||||
public void clear() {
|
||||
public OrderBy<T> clear() {
|
||||
list.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,6 +408,6 @@ public final class OrderBy<T> implements Serializable {
|
||||
}
|
||||
|
||||
private boolean isEmptyString(String s) {
|
||||
return s == null || s.length() == 0;
|
||||
return s == null || s.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,30 +44,6 @@ import java.util.concurrent.Future;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h4>Example: typical use including total row count</h4>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // We want to find the first 100 new orders
|
||||
* // ... 0 means first page
|
||||
* // ... page size is 100
|
||||
*
|
||||
* PagedList<Order> pagedList
|
||||
* = ebeanServer.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .findPagedList(0, 100);
|
||||
*
|
||||
* // Optional: initiate the loading of the total
|
||||
* // row count in a background thread
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // get the total row count (from the future)
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h4>Example: No total row count required</h4>
|
||||
* <pre>{@code
|
||||
@@ -84,7 +60,7 @@ import java.util.concurrent.Future;
|
||||
* @param <T>
|
||||
* the entity bean type
|
||||
*
|
||||
* @see Query#findPagedList(int, int)
|
||||
* @see Query#findPagedList()
|
||||
*/
|
||||
public interface PagedList<T> {
|
||||
|
||||
@@ -110,7 +86,7 @@ public interface PagedList<T> {
|
||||
* wrapped in the unchecked PersistenceException (which might be preferrable).
|
||||
* </p>
|
||||
*/
|
||||
void loadRowCount();
|
||||
void loadCount();
|
||||
|
||||
/**
|
||||
* Return the Future row count. You might get this if you wish to cancel the total row count query
|
||||
@@ -138,7 +114,7 @@ public interface PagedList<T> {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Future<Integer> getFutureRowCount();
|
||||
Future<Integer> getFutureCount();
|
||||
|
||||
/**
|
||||
* Return the list of entities for this page.
|
||||
@@ -170,7 +146,7 @@ public interface PagedList<T> {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
int getTotalRowCount();
|
||||
int getTotalCount();
|
||||
|
||||
/**
|
||||
* Return the total number of pages based on the page size and total row count.
|
||||
@@ -181,20 +157,19 @@ public interface PagedList<T> {
|
||||
*/
|
||||
int getTotalPageCount();
|
||||
|
||||
/**
|
||||
* Return the index position of this page. Zero based.
|
||||
* <p>
|
||||
* Note that if firstRows/maxRows is used rather than pageIndex/pageSize then
|
||||
* this always returns 0.
|
||||
* </p>
|
||||
*/
|
||||
int getPageIndex();
|
||||
|
||||
/**
|
||||
* Return the page size used for this query. This is the same value as maxRows used by the query.
|
||||
*/
|
||||
int getPageSize();
|
||||
|
||||
/**
|
||||
* Return the index position of this page (Zero based).
|
||||
* <p>
|
||||
* This is a calculated value based on firstRow/maxRows.
|
||||
* </p>
|
||||
*/
|
||||
int getPageIndex();
|
||||
|
||||
/**
|
||||
* Return true if there is a next page.
|
||||
* <p>
|
||||
|
||||
@@ -78,6 +78,6 @@ class PrimaryServer {
|
||||
* Return true if the string is null or empty.
|
||||
*/
|
||||
private static boolean isEmpty(String value) {
|
||||
return value == null || value.trim().length() == 0;
|
||||
return value == null || value.trim().isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,28 +10,35 @@ import java.util.Iterator;
|
||||
* findList(), findSet() etc where all the beans are held in the List or Set
|
||||
* etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that findIterate (and findEach and findEachWhile) uses a "per graph"
|
||||
* persistence context scope and adjusts jdbc fetch buffer size for large
|
||||
* queries. As such it is better to use findList for small queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
|
||||
* when you have finished iterating the results (typically in a finally block).
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* QueryIterator<Customer> it = query.findIterate();
|
||||
* try {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer...
|
||||
* }
|
||||
* } finally {
|
||||
* // close the associated resources
|
||||
* it.close();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* QueryIterator<Customer> it = query.findIterate();
|
||||
* try {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer ...
|
||||
* }
|
||||
* } finally {
|
||||
* // close the underlying resources
|
||||
* it.close();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean in the iteration
|
||||
|
||||
@@ -404,7 +404,7 @@ public final class RawSql implements Serializable {
|
||||
this.dbColumnMap = new LinkedHashMap<String, Column>();
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
Column c = columns.get(i);
|
||||
dbColumnMap.put(c.getDbColumn(), c);
|
||||
dbColumnMap.put(c.getDbColumnKey(), c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,8 +500,7 @@ public final class RawSql implements Serializable {
|
||||
} else {
|
||||
Column column = dbColumnMap.get(dbColumn);
|
||||
if (column == null) {
|
||||
String msg = "DB Column [" + dbColumn + "] not found in mapping. Expecting one of ["
|
||||
+ dbColumnMap.keySet() + "]";
|
||||
String msg = "DB Column [" + dbColumn + "] not found in mapping. Expecting one of [" + dbColumnMap.keySet() + "]";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
column.setPropertyName(propertyName);
|
||||
@@ -607,9 +606,9 @@ public final class RawSql implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
private static String derivePropertyName(String dbAlias, String dbColumn) {
|
||||
protected static String derivePropertyName(String dbAlias, String dbColumn) {
|
||||
if (dbAlias != null) {
|
||||
return dbAlias;
|
||||
return CamelCaseHelper.toCamelFromUnderscore(dbAlias);
|
||||
}
|
||||
int dotPos = dbColumn.indexOf('.');
|
||||
if (dotPos > -1) {
|
||||
@@ -657,6 +656,14 @@ public final class RawSql implements Serializable {
|
||||
return indexPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB column alias if specified otherwise DB column.
|
||||
* This is used as the key for mapping a column to a logical property.
|
||||
*/
|
||||
public String getDbColumnKey() {
|
||||
return (dbAlias != null) ? dbAlias : dbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB column name including table alias (if it has one).
|
||||
*/
|
||||
@@ -664,13 +671,6 @@ public final class RawSql implements Serializable {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB column alias (if it has one).
|
||||
*/
|
||||
public String getDbAlias() {
|
||||
return dbAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean property this column is mapped to.
|
||||
*/
|
||||
|
||||
@@ -2,8 +2,6 @@ package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Query object for performing native SQL queries that return SqlRow's.
|
||||
|
||||
@@ -26,7 +26,7 @@ package com.avaje.ebean;
|
||||
*
|
||||
* int modifiedCount = Ebean.execute(update);
|
||||
*
|
||||
* String msg = "There where " + modifiedCount + "rows updated"
|
||||
* String msg = "There were " + modifiedCount + " rows updated"
|
||||
* </pre>
|
||||
*
|
||||
* @see Update
|
||||
@@ -117,8 +117,7 @@ public interface SqlUpdate {
|
||||
SqlUpdate setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set a null parameter via its index position. Exactly the same as
|
||||
* {@link #setNull(int, int)}.
|
||||
* Set a null parameter via its index position.
|
||||
*/
|
||||
SqlUpdate setNull(int position, int jdbcType);
|
||||
|
||||
@@ -143,4 +142,4 @@ public interface SqlUpdate {
|
||||
*/
|
||||
SqlUpdate setNullParameter(String name, int jdbcType);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.ebean;
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
import com.avaje.ebean.config.DocStoreConfig;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.RollbackException;
|
||||
@@ -53,13 +54,52 @@ public interface Transaction extends Closeable {
|
||||
*/
|
||||
void setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Commits the transaction at this point with the expectation that another
|
||||
* commit (or rollback or end) will occur later to complete the transaction.
|
||||
* <p>
|
||||
* This is similar to commit() but leaves the transaction "Active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <ul>
|
||||
* <li>Flush the JDBC batch buffer</li>
|
||||
* <li>Call commit on the underlying JDBC connection</li>
|
||||
* <li>Trigger any registered TransactionCallbacks</li>
|
||||
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
|
||||
* </ul>
|
||||
*/
|
||||
void commitAndContinue() throws RollbackException;
|
||||
|
||||
/**
|
||||
* Commit the transaction.
|
||||
* <p>
|
||||
* This performs commit and completes the transaction closing underlying resources and
|
||||
* marking the transaction as "In active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <ul>
|
||||
* <li>Flush the JDBC batch buffer</li>
|
||||
* <li>Call commit on the underlying JDBC connection</li>
|
||||
* <li>Trigger any registered TransactionCallbacks</li>
|
||||
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
|
||||
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
|
||||
* <li>Mark the transaction as "Inactive"</li>
|
||||
* </ul>
|
||||
*/
|
||||
void commit() throws RollbackException;
|
||||
|
||||
/**
|
||||
* Rollback the transaction.
|
||||
* <p>
|
||||
* This performs rollback, closes underlying resources and marks the transaction as "In active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <ul>
|
||||
* <li>Call rollback on the underlying JDBC connection</li>
|
||||
* <li>Trigger any registered TransactionCallbacks</li>
|
||||
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
|
||||
* <li>Mark the transaction as "Inactive"</li>
|
||||
* </ul>
|
||||
*/
|
||||
void rollback() throws PersistenceException;
|
||||
|
||||
@@ -73,6 +113,16 @@ public interface Transaction extends Closeable {
|
||||
*/
|
||||
void rollback(Throwable e) throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Mark the transaction for rollback only.
|
||||
*/
|
||||
void setRollbackOnly();
|
||||
|
||||
/**
|
||||
* Return true if the transaction is marked as rollback only.
|
||||
*/
|
||||
boolean isRollbackOnly();
|
||||
|
||||
/**
|
||||
* If the transaction is active then perform rollback. Otherwise do nothing.
|
||||
*/
|
||||
@@ -125,13 +175,78 @@ public interface Transaction extends Closeable {
|
||||
* Set to true when you want all loaded properties to be included in the update
|
||||
* (rather than just the changed properties).
|
||||
* <p>
|
||||
* You might set this when using JDBC batch in order to get multiple updates
|
||||
* with slightly different sets of changed properties into the same statement
|
||||
* and hence better JDBC batch performance.
|
||||
* You might set this when using JDBC batch in order to get multiple updates
|
||||
* with slightly different sets of changed properties into the same statement
|
||||
* and hence better JDBC batch performance.
|
||||
* </p>
|
||||
*/
|
||||
void setUpdateAllLoadedProperties(boolean updateAllLoadedProperties);
|
||||
|
||||
/**
|
||||
* Set if the L2 cache should be skipped for "find by id" and "find by natural key" queries.
|
||||
* <p>
|
||||
* By default {@link ServerConfig#isSkipCacheAfterWrite()} is true and that means that for
|
||||
* "find by id" and "find by natural key" queries which normally hit L2 bean cache automatically
|
||||
* - will not do so after a persist/write on the transaction.
|
||||
* </p>
|
||||
* <p>
|
||||
* This method provides explicit control over whether "find by id" and "find by natural key"
|
||||
* will skip the L2 bean cache or not (regardless of whether the transaction is considered "read only").
|
||||
* </p>
|
||||
* <p>
|
||||
* Refer to {@link ServerConfig#setSkipCacheAfterWrite(boolean)} for configuring the default behavior
|
||||
* for using the L2 bean cache in transactions spanning multiple query/persist requests.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // assume Customer has L2 bean caching enabled ...
|
||||
*
|
||||
* Transaction transaction = Ebean.beginTransaction();
|
||||
* try {
|
||||
*
|
||||
* // this uses L2 bean cache as the transaction
|
||||
* // ... is considered "query only" at this point
|
||||
* Customer.find.byId(42);
|
||||
*
|
||||
* // transaction no longer "query only" once
|
||||
* // ... a bean has been saved etc
|
||||
* Ebean.save(someBean);
|
||||
*
|
||||
* // will NOT use L2 bean cache as the transaction
|
||||
* // ... is no longer considered "query only"
|
||||
* Customer.find.byId(55);
|
||||
*
|
||||
*
|
||||
*
|
||||
* // explicit control - please use L2 bean cache
|
||||
*
|
||||
* transaction.setSkipCache(false);
|
||||
* Customer.find.byId(77); // hit the l2 bean cache
|
||||
*
|
||||
*
|
||||
* // explicit control - please don't use L2 bean cache
|
||||
*
|
||||
* transaction.setSkipCache(true);
|
||||
* Customer.find.byId(99); // skips l2 bean cache
|
||||
*
|
||||
*
|
||||
* } finally {
|
||||
* transaction.end();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see ServerConfig#isSkipCacheAfterWrite()
|
||||
*/
|
||||
void setSkipCache(boolean skipCache);
|
||||
|
||||
/**
|
||||
* Return true if the L2 cache should be skipped. More accurately if true then find by id
|
||||
* and find by natural key queries should NOT automatically use the L2 bean cache.
|
||||
*/
|
||||
boolean isSkipCache();
|
||||
|
||||
/**
|
||||
* Turn on or off statement batching. Statement batching can be transparent
|
||||
* for drivers and databases that support getGeneratedKeys. Otherwise you may
|
||||
@@ -351,9 +466,8 @@ public interface Transaction extends Closeable {
|
||||
|
||||
/**
|
||||
* Add an arbitrary user object to the transaction. The objects added have no
|
||||
* impact on any internals of ebena and are solely meant as a convenient
|
||||
* method push user information to e.g. the
|
||||
* {@link com.avaje.ebean.event.TransactionEventListener}.
|
||||
* impact on any internals of ebean and are solely meant as a convenient
|
||||
* method push user information (although somewhat replaced by TransactionCallback).
|
||||
*/
|
||||
void putUserObject(String name, Object value);
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import java.util.ArrayList;
|
||||
* This object is used internally with the enhancement of a method with
|
||||
* Transactional annotation.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @see TxCallable
|
||||
* @see TxRunnable
|
||||
* @see Ebean#execute(TxScope, TxCallable)
|
||||
@@ -36,33 +36,14 @@ public final class TxScope {
|
||||
|
||||
int batchSize;
|
||||
|
||||
boolean skipGeneratedKeys;
|
||||
|
||||
boolean readOnly;
|
||||
|
||||
ArrayList<Class<? extends Throwable>> rollbackFor;
|
||||
|
||||
ArrayList<Class<? extends Throwable>> noRollbackFor;
|
||||
|
||||
/**
|
||||
* Return true if PersistBatch has been set.
|
||||
*/
|
||||
public boolean isBatchSet() {
|
||||
return batch != null && batch != PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if batch on cascade has been set.
|
||||
*/
|
||||
public boolean isBatchOnCascadeSet() {
|
||||
return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if batch size has been set.
|
||||
*/
|
||||
public boolean isBatchSizeSet() {
|
||||
return batchSize > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with REQUIRES.
|
||||
*/
|
||||
@@ -128,6 +109,44 @@ public final class TxScope {
|
||||
+ "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if PersistBatch has been set.
|
||||
*/
|
||||
public boolean isBatchSet() {
|
||||
return batch != null && batch != PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if batch on cascade has been set.
|
||||
*/
|
||||
public boolean isBatchOnCascadeSet() {
|
||||
return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if batch size has been set.
|
||||
*/
|
||||
public boolean isBatchSizeSet() {
|
||||
return batchSize > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for batchSize being set without batch mode and use this to imply PersistBatch.ALL.
|
||||
*/
|
||||
public void checkBatchMode() {
|
||||
if (batchSize > 0 && notSet(batch) && notSet(batchOnCascade)) {
|
||||
// Use setting the batchSize as implying PersistBatch.ALL for @Transactional
|
||||
batch = PersistBatch.ALL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the mode is considered not set.
|
||||
*/
|
||||
private boolean notSet(PersistBatch batchMode) {
|
||||
return batchMode == null || batchMode == PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction type.
|
||||
*/
|
||||
@@ -188,6 +207,21 @@ public final class TxScope {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the transaction should skip reading generated keys for inserts.
|
||||
*/
|
||||
public TxScope setSkipGeneratedKeys() {
|
||||
this.skipGeneratedKeys = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if getGeneratedKeys should be skipped for this transaction.
|
||||
*/
|
||||
public boolean isSkipGeneratedKeys() {
|
||||
return skipGeneratedKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the transaction should be treated as read only.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* An update query typically intended to perform a bulk update of many rows that match the query.
|
||||
* <p>
|
||||
* Also note that you can also just use a raw SQL update via {@link SqlUpdate} which is pretty light and simple.
|
||||
* This UpdateQuery is more for the cases where we want to build the where expression of the update using the
|
||||
* {@link ExpressionList} "Criteria API" that is used with a normal ORM query.
|
||||
* </p>
|
||||
*
|
||||
* <h4>Example: Simple update</h4>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
* <pre>{@code sql
|
||||
*
|
||||
* update o_customer set status=?, updtime=? where id > ?
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Note that if the where() clause contains a join then the SQL update changes to use a
|
||||
* <code> WHERE ID IN () </code> form.
|
||||
* </p>
|
||||
*
|
||||
* <h4>Example: Update with a JOIN</h4>
|
||||
* <p>
|
||||
* In this example the expression <code>.eq("billingAddress.country", nz)</code> requires a join
|
||||
* to the address table.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
* .eq("status", Customer.Status.NEW)
|
||||
* .eq("billingAddress.country", nz)
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
* }</pre>
|
||||
*
|
||||
* <pre>{@code sql
|
||||
*
|
||||
* update o_customer set status=?, updtime=?
|
||||
* where id in (
|
||||
* select t0.id c0
|
||||
* from o_customer t0
|
||||
* left join o_address t1 on t1.id = t0.billing_address_id
|
||||
* where t0.status = ?
|
||||
* and t1.country_code = ?
|
||||
* and t0.id > ? )
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T> The type of entity bean being updated
|
||||
*
|
||||
* @see SqlUpdate
|
||||
*/
|
||||
public interface UpdateQuery<T> {
|
||||
|
||||
/**
|
||||
* Set the value of a property.
|
||||
*
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param property The bean property to be set
|
||||
* @param value The value to set the property to
|
||||
*/
|
||||
UpdateQuery<T> set(String property, Object value);
|
||||
|
||||
/**
|
||||
* Set the property to be null.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .setNull("notes")
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param property The property to be set to null.
|
||||
*/
|
||||
UpdateQuery<T> setNull(String property);
|
||||
|
||||
/**
|
||||
*
|
||||
* Set using a property expression that does not need any bind values.
|
||||
* <p>
|
||||
* The property expression typically contains database functions.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .setRaw("status = coalesce(status, 'A')")
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyExpression A property expression
|
||||
*/
|
||||
UpdateQuery<T> setRaw(String propertyExpression);
|
||||
|
||||
/**
|
||||
* Set using a property expression that can contain <code>?</code> bind value placeholders.
|
||||
* <p>
|
||||
* For each <code>?</code> in the property expression there should be a matching bind value supplied.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .setRaw("status = coalesce(status, ?)", Customer.Status.ACTIVE)
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyExpression A raw property expression
|
||||
* @param values The values to bind with the property expression
|
||||
*/
|
||||
UpdateQuery<T> setRaw(String propertyExpression, Object... values);
|
||||
|
||||
/**
|
||||
* Return the query expression list to add predicates to.
|
||||
*/
|
||||
ExpressionList<T> where();
|
||||
|
||||
}
|
||||
@@ -28,6 +28,11 @@ public @interface Cache {
|
||||
* 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>
|
||||
* <p>
|
||||
* When bean caching is enabled by default "find by id" and "find by unique natural key"
|
||||
* queries will try to use the bean cache. We use {@link com.avaje.ebean.Query#setUseCache(boolean)}
|
||||
* with <code>false</code> for the case when we do NOT want to use the bean cache.
|
||||
* </p>
|
||||
*/
|
||||
boolean enableBeanCache() default true;
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ public @interface Formula {
|
||||
* as count, sum etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* The join string should start with either "left outer join" or "join".
|
||||
* The join string should start with either "left join" or "join".
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation for declaring an index on a single column.
|
||||
* An annotation for declaring an index.
|
||||
*
|
||||
* @author rvbiljouw
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(Indices.class)
|
||||
public @interface Index {
|
||||
|
||||
/**
|
||||
@@ -27,6 +29,9 @@ public @interface Index {
|
||||
/**
|
||||
* When placed on the class (rather than field) you can specify the columns
|
||||
* to include in the index in order.
|
||||
*
|
||||
* Wnen placed on a field, and columnNames are specified, the field-column has to be included.
|
||||
* You can use "${fa}" for alias
|
||||
*/
|
||||
String[] columnNames() default {};
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
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;
|
||||
/**
|
||||
* An annotation for declaring multiple indices at class or field level.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Indices {
|
||||
|
||||
/**
|
||||
* Array with {@link Index} definitions.
|
||||
*/
|
||||
Index[] value() default {};
|
||||
}
|
||||
@@ -1,37 +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;
|
||||
|
||||
/**
|
||||
* An Update statement for a particular entity bean type.
|
||||
* <p>
|
||||
* The update can either be a sql insert,update or delete statement with tables
|
||||
* and columns etc or the equivalent statement but with table names and columns
|
||||
* expressed as bean types and bean properties.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NamedUpdate {
|
||||
|
||||
/**
|
||||
* The name of the update.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* The insert, update or delete statement.
|
||||
*/
|
||||
String update();
|
||||
|
||||
/**
|
||||
* Set this to false if you do not want the cache to be notified. If true the
|
||||
* cache will invalidate appropriate objects from the cache (after a
|
||||
* successful transaction commit).
|
||||
*/
|
||||
boolean notifyCache() default true;
|
||||
|
||||
}
|
||||
@@ -1,20 +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;
|
||||
|
||||
/**
|
||||
* Holds an array of named Update statements for a particular entity bean type.
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NamedUpdates {
|
||||
|
||||
/**
|
||||
* An array of named updates.
|
||||
*/
|
||||
NamedUpdate[] value();
|
||||
|
||||
}
|
||||
@@ -90,6 +90,16 @@ public @interface Transactional {
|
||||
*/
|
||||
int batchSize() default 0;
|
||||
|
||||
/**
|
||||
* Set to false when we want to skip getting generatedKeys.
|
||||
* <p>
|
||||
* This is typically used in the case of large batch inserts where we get a
|
||||
* performance benefit from not calling getGeneratedKeys (as we are going to
|
||||
* insert a lot of rows and have no need for the Id values after the insert).
|
||||
* </p>
|
||||
*/
|
||||
boolean getGeneratedKeys() default true;
|
||||
|
||||
/**
|
||||
* The transaction isolation level this transaction should have.
|
||||
* <p>
|
||||
|
||||
@@ -31,6 +31,11 @@ public interface BeanCollection<E> extends Serializable {
|
||||
ALL
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the disableLazyLoad state.
|
||||
*/
|
||||
void setDisableLazyLoad(boolean disableLazyLoad);
|
||||
|
||||
/**
|
||||
* Load bean from another collection.
|
||||
*/
|
||||
@@ -54,10 +59,12 @@ public interface BeanCollection<E> extends Serializable {
|
||||
void reset(EntityBean ownerBean, String propertyName);
|
||||
|
||||
/**
|
||||
* Return true if the collection is empty and untouched. Used to detect if a
|
||||
* collection was 'cleared' deliberately or just un-initialised.
|
||||
* Return true if the collection is uninitialised or is empty without any held modifications.
|
||||
* <p>
|
||||
* Returning true means can safely skip cascade save for this bean collection.
|
||||
* </p>
|
||||
*/
|
||||
boolean isEmptyAndUntouched();
|
||||
boolean isSkipSave();
|
||||
|
||||
/**
|
||||
* Return the bean that owns this collection.
|
||||
@@ -92,11 +99,6 @@ public interface BeanCollection<E> extends Serializable {
|
||||
*/
|
||||
void setFilterMany(ExpressionList<?> filterMany);
|
||||
|
||||
/**
|
||||
* Set a listener to be notified when the BeanCollection is first touched.
|
||||
*/
|
||||
void setBeanCollectionTouched(BeanCollectionTouched notify);
|
||||
|
||||
/**
|
||||
* Return true if the collection has been registered with the batch loading context.
|
||||
*/
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Used to specify a listener to be notified when a BeanCollection is first
|
||||
* used.
|
||||
* <p>
|
||||
* To use this you can set a BeanCollectionTouched onto a BeanCollection before
|
||||
* it has been used. When the BeanCollection is first used by the client code
|
||||
* then the BeanCollectionTouched is notified. It can only be notified once.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface BeanCollectionTouched {
|
||||
|
||||
/**
|
||||
* Notify the listener that the bean collection has been used.
|
||||
*/
|
||||
void notifyTouched(BeanCollection<?> c);
|
||||
}
|
||||
@@ -39,6 +39,8 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
|
||||
private transient BeanLoader beanLoader;
|
||||
|
||||
private transient PreGetterCallback preGetterCallback;
|
||||
|
||||
private String ebeanServerName;
|
||||
|
||||
/**
|
||||
@@ -186,6 +188,21 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
return embeddedOwnerIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the getter callback.
|
||||
*/
|
||||
public void clearGetterCallback() {
|
||||
this.preGetterCallback = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the callback to be triggered when getter is called.
|
||||
* This is used primarily to automatically flush the JDBC batch.
|
||||
*/
|
||||
public void registerGetterCallback(PreGetterCallback getterCallback) {
|
||||
this.preGetterCallback = getterCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the embedded beans owning bean.
|
||||
*/
|
||||
@@ -325,6 +342,13 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
return state == STATE_LOADED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean into NEW state.
|
||||
*/
|
||||
public void setNew() {
|
||||
this.state = STATE_NEW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the loaded state to true.
|
||||
* <p>
|
||||
@@ -832,19 +856,31 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public void initialisedMany(int propertyIndex) {
|
||||
loadedProps[propertyIndex] = true;
|
||||
}
|
||||
|
||||
|
||||
private final void preGetterCallback() {
|
||||
if (preGetterCallback != null) {
|
||||
preGetterCallback.preGetterTrigger();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called prior to Id property getter.
|
||||
*/
|
||||
public void preGetId() {
|
||||
preGetterCallback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called prior to a getter method on the actual entity.
|
||||
*/
|
||||
public void preGetter(int propertyIndex) {
|
||||
preGetterCallback();
|
||||
if (state == STATE_NEW || disableLazyLoad) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isLoadedProperty(propertyIndex)) {
|
||||
loadBean(propertyIndex);
|
||||
}
|
||||
|
||||
if (nodeUsageCollector != null) {
|
||||
nodeUsageCollector.addUsed(getProperty(propertyIndex));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* A callback that can be registered to fire on getter method calls.
|
||||
* It's primary purpose is to automatically flush JDBC batch buffer.
|
||||
*/
|
||||
public interface PreGetterCallback {
|
||||
|
||||
/**
|
||||
* Trigger the callback.
|
||||
*/
|
||||
void preGetterTrigger();
|
||||
}
|
||||
@@ -5,6 +5,15 @@ package com.avaje.ebean.cache;
|
||||
*/
|
||||
public interface ServerCacheManager {
|
||||
|
||||
/**
|
||||
* Return true if the L2 caching is local.
|
||||
* <p>
|
||||
* Local L2 caching means that the cache updates should occur in foreground
|
||||
* rather than background processing.
|
||||
* </p>
|
||||
*/
|
||||
boolean isLocalL2Caching();
|
||||
|
||||
/**
|
||||
* Return true if there is an active bean cache for this type of bean.
|
||||
*/
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.ExpressionList;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.BeanCollectionTouched;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Base class for List Set and Map implementations of BeanCollection.
|
||||
*
|
||||
@@ -22,6 +20,8 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
protected boolean readOnly;
|
||||
|
||||
protected boolean disableLazyLoad;
|
||||
|
||||
/**
|
||||
* The EbeanServer this is associated with. (used for lazy fetch).
|
||||
*/
|
||||
@@ -36,8 +36,6 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
protected String ebeanServerName;
|
||||
|
||||
protected transient BeanCollectionTouched beanCollectionTouched;
|
||||
|
||||
/**
|
||||
* The owning bean (used for lazy fetch).
|
||||
*/
|
||||
@@ -55,12 +53,6 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
protected boolean modifyRemoveListening;
|
||||
protected boolean modifyListening;
|
||||
|
||||
/**
|
||||
* Flag used to tell if empty collections have been cleared etc or just
|
||||
* uninitialised.
|
||||
*/
|
||||
protected boolean touched;
|
||||
|
||||
/**
|
||||
* Constructor not non-lazy loading collection.
|
||||
*/
|
||||
@@ -94,6 +86,11 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
this.filterMany = filterMany;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisableLazyLoad(boolean disableLazyLoad) {
|
||||
this.disableLazyLoad = disableLazyLoad;
|
||||
}
|
||||
|
||||
protected void lazyLoadCollection(boolean onlyIds) {
|
||||
if (loader == null) {
|
||||
loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
|
||||
@@ -109,25 +106,6 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
checkEmptyLazyLoad();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touched. If setFlag is false then typically an isEmpty() call and still
|
||||
* considering that to be untouched.
|
||||
*/
|
||||
protected void touched(boolean setFlag) {
|
||||
if (setFlag) {
|
||||
touched = true;
|
||||
}
|
||||
if (beanCollectionTouched != null) {
|
||||
// only call this once
|
||||
beanCollectionTouched.notifyTouched(this);
|
||||
beanCollectionTouched = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setBeanCollectionTouched(BeanCollectionTouched notify) {
|
||||
this.beanCollectionTouched = notify;
|
||||
}
|
||||
|
||||
public boolean isRegisteredWithLoadContext() {
|
||||
return registeredWithLoadContext;
|
||||
}
|
||||
@@ -219,4 +197,11 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
return modifyHolder.getModifyRemovals();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are underlying additions or removals.
|
||||
*/
|
||||
public boolean holdsModifications() {
|
||||
return modifyHolder != null && modifyHolder.hasModifications();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,12 +52,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.list = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (list == null || list.isEmpty());
|
||||
public boolean isSkipSave() {
|
||||
return list == null || (list.isEmpty() && !holdsModifications());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -103,30 +102,24 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
private void initClear() {
|
||||
synchronized (this) {
|
||||
if (list == null) {
|
||||
if (modifyListening) {
|
||||
if (!disableLazyLoad && modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
} else {
|
||||
list = new ArrayList<E>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (list == null) {
|
||||
lazyLoadCollection(false);
|
||||
if (disableLazyLoad) {
|
||||
list = new ArrayList<E>();
|
||||
} else {
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +289,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
init();
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@@ -45,11 +45,10 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.map = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (map == null || map.isEmpty());
|
||||
public boolean isSkipSave() {
|
||||
return map == null || (map.isEmpty() && !holdsModifications());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,24 +124,14 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
map = new LinkedHashMap<K, E>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (map == null) {
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +238,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
init();
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@@ -46,11 +46,10 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.set = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (set == null || set.isEmpty());
|
||||
public boolean isSkipSave() {
|
||||
return set == null || (set.isEmpty() && !holdsModifications());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -117,24 +116,14 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
set = new LinkedHashSet<E>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (set == null) {
|
||||
lazyLoadCollection(true);
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,7 +249,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
init();
|
||||
return set.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@@ -71,4 +71,11 @@ class ModifyHolder<E> implements Serializable {
|
||||
Set<E> getModifyRemovals() {
|
||||
return modifyDeletions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there additions or removals.
|
||||
*/
|
||||
boolean hasModifications() {
|
||||
return !modifyDeletions.isEmpty() || !modifyAdditions.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
* Checks string is null or empty .
|
||||
*/
|
||||
protected boolean isEmpty(String s) {
|
||||
return s == null || s.trim().length() == 0;
|
||||
return s == null || s.trim().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -91,7 +91,7 @@ public class ClassLoadConfig {
|
||||
/**
|
||||
* Return true if the given class is present.
|
||||
*/
|
||||
protected boolean isPresent(String className) {
|
||||
public boolean isPresent(String className) {
|
||||
try {
|
||||
forName(className);
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
|
||||
/**
|
||||
* Custom mappings for DB types that override the default.
|
||||
*
|
||||
* @see ServerConfig#addCustomMapping(DbType, String)
|
||||
*/
|
||||
public class CustomDbTypeMapping {
|
||||
|
||||
protected final DbType type;
|
||||
|
||||
protected final String columnDefinition;
|
||||
|
||||
protected final Platform platform;
|
||||
|
||||
/**
|
||||
* Create a mapping.
|
||||
*/
|
||||
public CustomDbTypeMapping(DbType type, String columnDefinition, Platform platform) {
|
||||
this.type = type;
|
||||
this.columnDefinition = columnDefinition;
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mapping that should apply to all the database platforms.
|
||||
*/
|
||||
public CustomDbTypeMapping(DbType type, String columnDefinition) {
|
||||
this(type, columnDefinition, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB type the mapping applies to.
|
||||
*/
|
||||
public DbType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB column definition to use.
|
||||
*/
|
||||
public String getColumnDefinition() {
|
||||
return columnDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the platform this mapping should apply to. Null means it applied to all platforms.
|
||||
*/
|
||||
public Platform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformName;
|
||||
import com.avaje.ebean.dbmigration.DbMigration;
|
||||
import org.avaje.dbmigration.MigrationConfig;
|
||||
import org.avaje.dbmigration.MigrationRunner;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -18,7 +19,7 @@ public class DbMigrationConfig {
|
||||
/**
|
||||
* The database platform to generate migration DDL for.
|
||||
*/
|
||||
protected DbPlatformName platform;
|
||||
protected Platform platform;
|
||||
|
||||
/**
|
||||
* Set to true if the DB migration should be generated on server start.
|
||||
@@ -97,7 +98,7 @@ public class DbMigrationConfig {
|
||||
/**
|
||||
* DB user used to run the DB migration.
|
||||
*/
|
||||
protected String dbUser;
|
||||
protected String dbUsername;
|
||||
|
||||
/**
|
||||
* DB password used to run the DB migration.
|
||||
@@ -110,14 +111,14 @@ public class DbMigrationConfig {
|
||||
* We typically need to explicitly specify this as migration can often be generated
|
||||
* when running against H2.
|
||||
*/
|
||||
public DbPlatformName getPlatform() {
|
||||
public Platform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB platform to generate migration DDL for.
|
||||
*/
|
||||
public void setPlatform(DbPlatformName platform) {
|
||||
public void setPlatform(Platform platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
@@ -242,14 +243,6 @@ public class DbMigrationConfig {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the model, rollback and drop paths to be empty such that all the migration files are generated
|
||||
* into a single directory.
|
||||
*/
|
||||
public void singleDirectory() {
|
||||
this.modelPath = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the table name that holds the migration run details
|
||||
* (used by DB Migration runner only).
|
||||
@@ -323,22 +316,22 @@ public class DbMigrationConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB user to use for running DB migrations.
|
||||
* Return the DB username to use for running DB migrations.
|
||||
*/
|
||||
public String getDbUser() {
|
||||
public String getDbUsername() {
|
||||
// environment properties take precedence
|
||||
String user = readEnvironment("ddl.migration.user");
|
||||
if (user != null) {
|
||||
return user;
|
||||
}
|
||||
return dbUser;
|
||||
return dbUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB user to use for running DB migrations.
|
||||
* Set the DB username to use for running DB migrations.
|
||||
*/
|
||||
public void setDbUser(String dbUser) {
|
||||
this.dbUser = dbUser;
|
||||
public void setDbUsername(String dbUsername) {
|
||||
this.dbUsername = dbUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -365,18 +358,14 @@ public class DbMigrationConfig {
|
||||
public void loadSettings(PropertiesWrapper properties, String serverName) {
|
||||
|
||||
migrationPath = properties.get("migration.migrationPath", migrationPath);
|
||||
if (properties.getBoolean("migration.singleDirectory", false)) {
|
||||
singleDirectory();
|
||||
} else {
|
||||
modelPath = properties.get("migration.modelPath", modelPath);
|
||||
}
|
||||
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);
|
||||
generatePendingDrop = properties.get("migration.generatePendingDrop", generatePendingDrop);
|
||||
|
||||
platform = properties.getEnum(DbPlatformName.class, "migration.platform", platform);
|
||||
platform = properties.getEnum(Platform.class, "migration.platform", platform);
|
||||
|
||||
generate = properties.getBoolean("migration.generate", generate);
|
||||
version = properties.get("migration.version", version);
|
||||
@@ -386,9 +375,9 @@ public class DbMigrationConfig {
|
||||
metaTable = properties.get("migration.metaTable", metaTable);
|
||||
runPlaceholders = properties.get("migration.placeholders", runPlaceholders);
|
||||
|
||||
String adminUser = properties.get("datasource."+serverName+".username", dbUser);
|
||||
String adminUser = properties.get("datasource."+serverName+".username", dbUsername);
|
||||
adminUser = properties.get("datasource."+serverName+".adminusername", adminUser);
|
||||
dbUser = properties.get("migration.dbuser", adminUser);
|
||||
dbUsername = properties.get("migration.dbusername", adminUser);
|
||||
|
||||
String adminPwd = properties.get("datasource."+serverName+".password", dbPassword);
|
||||
adminPwd = properties.get("datasource."+serverName+".adminpassword", adminPwd);
|
||||
@@ -494,4 +483,20 @@ public class DbMigrationConfig {
|
||||
return val == null || val.trim().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the MigrationRunner to run migrations if necessary.
|
||||
*/
|
||||
public MigrationRunner createRunner(ClassLoader classLoader) {
|
||||
|
||||
MigrationConfig runnerConfig = new MigrationConfig();
|
||||
runnerConfig.setMetaTable(metaTable);
|
||||
runnerConfig.setApplySuffix(applySuffix);
|
||||
runnerConfig.setMigrationPath(migrationPath);
|
||||
runnerConfig.setRunPlaceholderMap(runPlaceholderMap);
|
||||
runnerConfig.setRunPlaceholders(runPlaceholders);
|
||||
runnerConfig.setDbUsername(getDbUsername());
|
||||
runnerConfig.setDbPassword(getDbPassword());
|
||||
runnerConfig.setClassLoader(classLoader);
|
||||
return new MigrationRunner(runnerConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,6 @@ public class DocStoreConfig {
|
||||
if (systemValue != null) {
|
||||
return systemValue;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
@@ -100,6 +99,10 @@ public class DocStoreConfig {
|
||||
* Return true if Ebean should generate mapping files on server startup.
|
||||
*/
|
||||
public boolean isGenerateMapping() {
|
||||
String systemValue = System.getProperty("ebean.docstore.generateMapping");
|
||||
if (systemValue != null) {
|
||||
return Boolean.parseBoolean(systemValue);
|
||||
}
|
||||
return generateMapping;
|
||||
}
|
||||
|
||||
@@ -114,6 +117,10 @@ public class DocStoreConfig {
|
||||
* Return true if the document store should recreate mapped indexes.
|
||||
*/
|
||||
public boolean isDropCreate() {
|
||||
String systemValue = System.getProperty("ebean.docstore.dropCreate");
|
||||
if (systemValue != null) {
|
||||
return Boolean.parseBoolean(systemValue);
|
||||
}
|
||||
return dropCreate;
|
||||
}
|
||||
|
||||
@@ -129,6 +136,10 @@ public class DocStoreConfig {
|
||||
* This is only used if dropCreate is false.
|
||||
*/
|
||||
public boolean isCreate() {
|
||||
String systemValue = System.getProperty("ebean.docstore.create");
|
||||
if (systemValue != null) {
|
||||
return Boolean.parseBoolean(systemValue);
|
||||
}
|
||||
return create;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Built in supported platforms.
|
||||
*/
|
||||
public enum DbPlatformName {
|
||||
public enum Platform {
|
||||
|
||||
/**
|
||||
* Generic base platform configured via properties or code.
|
||||
@@ -7,14 +7,15 @@ 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.config.dbplatform.DbType;
|
||||
import com.avaje.ebean.event.BeanFindController;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebean.event.BeanPostConstructListener;
|
||||
import com.avaje.ebean.event.BeanPostLoad;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.event.BulkTableEventListener;
|
||||
import com.avaje.ebean.event.ServerConfigStartup;
|
||||
import com.avaje.ebean.event.TransactionEventListener;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogListener;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogPrepare;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogRegister;
|
||||
@@ -47,23 +48,16 @@ import java.util.ServiceLoader;
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* ServerConfig c = new ServerConfig();
|
||||
* c.setName("ordh2");
|
||||
* c.setName("db");
|
||||
*
|
||||
* // read the ebean.properties and load
|
||||
* // those settings into this serverConfig object
|
||||
* c.loadFromProperties();
|
||||
*
|
||||
* // generate DDL and run it
|
||||
* c.setDdlGenerate(true);
|
||||
* c.setDdlRun(true);
|
||||
*
|
||||
* // add any classes found in the app.data package
|
||||
* c.addPackage("app.data");
|
||||
*
|
||||
* // add the names of Jars that contain entities
|
||||
* c.addJar("myJarContainingEntities.jar");
|
||||
* c.addJar("someOtherJarContainingEntities.jar");
|
||||
* c.addPackage("com.myapp.domain");
|
||||
*
|
||||
* // register as the 'Default' server
|
||||
* c.setDefaultServer(true);
|
||||
@@ -81,7 +75,7 @@ public class ServerConfig {
|
||||
/**
|
||||
* The EbeanServer name.
|
||||
*/
|
||||
private String name;
|
||||
private String name = "db";
|
||||
|
||||
/**
|
||||
* Typically configuration type objects that are passed by this ServerConfig
|
||||
@@ -91,6 +85,8 @@ public class ServerConfig {
|
||||
|
||||
private ContainerConfig containerConfig;
|
||||
|
||||
private List<CustomDbTypeMapping> customDbTypeMappings = new ArrayList<CustomDbTypeMapping>();
|
||||
|
||||
/**
|
||||
* The underlying properties that were used during configuration.
|
||||
*/
|
||||
@@ -109,13 +105,18 @@ public class ServerConfig {
|
||||
/**
|
||||
* Set to true if this is the default/primary server.
|
||||
*/
|
||||
private boolean defaultServer;
|
||||
private boolean defaultServer = true;
|
||||
|
||||
/**
|
||||
* Set this to true to disable class path search.
|
||||
*/
|
||||
private boolean disableClasspathSearch;
|
||||
|
||||
/**
|
||||
* The Geometry SRID value (default 4326).
|
||||
*/
|
||||
private int geometrySRID = 4326;
|
||||
|
||||
/**
|
||||
* List of interesting classes such as entities, embedded, ScalarTypes,
|
||||
* Listeners, Finders, Controllers etc.
|
||||
@@ -128,17 +129,6 @@ public class ServerConfig {
|
||||
*/
|
||||
private List<String> packages = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* The names of Jar files that are searched for entities and other interesting
|
||||
* classes. Only used when classes is empty/not explicitly specified.
|
||||
*/
|
||||
private List<String> searchJars = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Class name of a classPathReader implementation.
|
||||
*/
|
||||
private String classPathReaderClassName;
|
||||
|
||||
/**
|
||||
* Configuration for the ElasticSearch integration.
|
||||
*/
|
||||
@@ -181,6 +171,17 @@ public class ServerConfig {
|
||||
*/
|
||||
private int databaseSequenceBatchSize = 20;
|
||||
|
||||
/**
|
||||
* JDBC fetchSize hint when using findList. Defaults to 0 leaving it up to the JDBC driver.
|
||||
*/
|
||||
private int jdbcFetchSizeFindList;
|
||||
|
||||
/**
|
||||
* JDBC fetchSize hint when using findEach/findEachWhile. Defaults to 100. Note that this does
|
||||
* not apply to MySql as that gets special treatment (forward only etc).
|
||||
*/
|
||||
private int jdbcFetchSizeFindEach = 100;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -205,9 +206,11 @@ public class ServerConfig {
|
||||
private PersistBatch persistBatch = PersistBatch.NONE;
|
||||
|
||||
/**
|
||||
* Use for per request batch mode.
|
||||
* Use for cascade persist JDBC batch mode. INHERIT means use the platform default
|
||||
* which is ALL except for SQL Server where it is NONE (as getGeneratedKeys isn't
|
||||
* supported on SQL Server with JDBC batch).
|
||||
*/
|
||||
private PersistBatch persistBatchOnCascade = PersistBatch.NONE;
|
||||
private PersistBatch persistBatchOnCascade = PersistBatch.INHERIT;
|
||||
|
||||
private int persistBatchSize = 20;
|
||||
|
||||
@@ -238,6 +241,11 @@ public class ServerConfig {
|
||||
|
||||
private String ddlSeedSql;
|
||||
|
||||
/**
|
||||
* When true L2 bean cache use is skipped after a write has occurred on a transaction.
|
||||
*/
|
||||
private boolean skipCacheAfterWrite = true;
|
||||
|
||||
private boolean useJtaTransactionManager;
|
||||
|
||||
/**
|
||||
@@ -320,18 +328,18 @@ public class ServerConfig {
|
||||
/**
|
||||
* Setting to indicate if UUID should be stored as binary(16) or varchar(40) or native DB type (for H2 and Postgres).
|
||||
*/
|
||||
private DbUuid dbUuid = DbUuid.AUTO;
|
||||
private DbUuid dbUuid = DbUuid.AUTO_VARCHAR;
|
||||
|
||||
|
||||
private List<IdGenerator> idGenerators = new ArrayList<IdGenerator>();
|
||||
private List<BeanFindController> findControllers = new ArrayList<BeanFindController>();
|
||||
private List<BeanPersistController> persistControllers = new ArrayList<BeanPersistController>();
|
||||
private List<BeanPostLoad> postLoaders = new ArrayList<BeanPostLoad>();
|
||||
private List<BeanPostConstructListener> postConstructListeners = new ArrayList<BeanPostConstructListener>();
|
||||
private List<BeanPersistListener> persistListeners = new ArrayList<BeanPersistListener>();
|
||||
private List<BeanQueryAdapter> queryAdapters = new ArrayList<BeanQueryAdapter>();
|
||||
private List<BulkTableEventListener> bulkTableEventListeners = new ArrayList<BulkTableEventListener>();
|
||||
private List<ServerConfigStartup> configStartupListeners = new ArrayList<ServerConfigStartup>();
|
||||
private List<TransactionEventListener> transactionEventListeners = new ArrayList<TransactionEventListener>();
|
||||
|
||||
/**
|
||||
* By default inserts are included in the change log.
|
||||
@@ -379,19 +387,13 @@ public class ServerConfig {
|
||||
|
||||
private boolean transactionRollbackOnChecked = true;
|
||||
|
||||
private boolean registerJmxMBeans = true;
|
||||
|
||||
// configuration for the background executor service (thread pool)
|
||||
|
||||
private int backgroundExecutorSchedulePoolSize = 1;
|
||||
private int backgroundExecutorCorePoolSize = 1;
|
||||
private int backgroundExecutorMaxPoolSize = 8;
|
||||
private int backgroundExecutorIdleSecs = 60;
|
||||
private int backgroundExecutorShutdownSecs = 30;
|
||||
|
||||
// defaults for the L2 bean caching
|
||||
|
||||
private int cacheWarmingDelay = 30;
|
||||
private int cacheMaxSize = 10000;
|
||||
private int cacheMaxIdleTime = 600;
|
||||
private int cacheMaxTimeToLive = 60 * 60 * 6;
|
||||
@@ -409,7 +411,7 @@ public class ServerConfig {
|
||||
private boolean expressionEqualsWithNullAsNoop;
|
||||
|
||||
/**
|
||||
* Set to true to use native ILIKE expression (if support by datasbase platform / like Postgres).
|
||||
* Set to true to use native ILIKE expression (if support by database platform / like Postgres).
|
||||
*/
|
||||
private boolean expressionNativeIlike;
|
||||
|
||||
@@ -561,7 +563,7 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set true if this EbeanServer should be registered as the "default" server
|
||||
* Set false if you do not want this EbeanServer to be registered as the "default" server
|
||||
* with the Ebean singleton.
|
||||
* <p>
|
||||
* This is only used when {@link #setRegister(boolean)} is also true.
|
||||
@@ -732,6 +734,34 @@ public class ServerConfig {
|
||||
this.databaseSequenceBatchSize = databaseSequenceBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default JDBC fetchSize hint for findList queries.
|
||||
*/
|
||||
public int getJdbcFetchSizeFindList() {
|
||||
return jdbcFetchSizeFindList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default JDBC fetchSize hint for findList queries.
|
||||
*/
|
||||
public void setJdbcFetchSizeFindList(int jdbcFetchSizeFindList) {
|
||||
this.jdbcFetchSizeFindList = jdbcFetchSizeFindList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default JDBC fetchSize hint for findEach/findEachWhile queries.
|
||||
*/
|
||||
public int getJdbcFetchSizeFindEach() {
|
||||
return jdbcFetchSizeFindEach;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default JDBC fetchSize hint for findEach/findEachWhile queries.
|
||||
*/
|
||||
public void setJdbcFetchSizeFindEach(int jdbcFetchSizeFindEach) {
|
||||
this.jdbcFetchSizeFindEach = jdbcFetchSizeFindEach;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ChangeLogPrepare.
|
||||
* <p>
|
||||
@@ -851,6 +881,20 @@ public class ServerConfig {
|
||||
this.migrationConfig = migrationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Geometry SRID.
|
||||
*/
|
||||
public int getGeometrySRID() {
|
||||
return geometrySRID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Geometry SRID.
|
||||
*/
|
||||
public void setGeometrySRID(int geometrySRID) {
|
||||
this.geometrySRID = geometrySRID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time zone to use when reading/writing Timestamps via JDBC.
|
||||
* <p>
|
||||
@@ -1014,20 +1058,6 @@ public class ServerConfig {
|
||||
this.transactionRollbackOnChecked = transactionRollbackOnChecked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the server should register JMX MBeans.
|
||||
*/
|
||||
public boolean isRegisterJmxMBeans() {
|
||||
return registerJmxMBeans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the server should register JMX MBeans.
|
||||
*/
|
||||
public void setRegisterJmxMBeans(boolean registerJmxMBeans) {
|
||||
this.registerJmxMBeans = registerJmxMBeans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor schedule pool size. Defaults to 1.
|
||||
*/
|
||||
@@ -1042,48 +1072,6 @@ public class ServerConfig {
|
||||
this.backgroundExecutorSchedulePoolSize = backgroundExecutorSchedulePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor core pool size.
|
||||
*/
|
||||
public int getBackgroundExecutorCorePoolSize() {
|
||||
return backgroundExecutorCorePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor core pool size.
|
||||
*/
|
||||
public void setBackgroundExecutorCorePoolSize(int backgroundExecutorCorePoolSize) {
|
||||
this.backgroundExecutorCorePoolSize = backgroundExecutorCorePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor max pool size.
|
||||
*/
|
||||
public int getBackgroundExecutorMaxPoolSize() {
|
||||
return backgroundExecutorMaxPoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor max pool size.
|
||||
*/
|
||||
public void setBackgroundExecutorMaxPoolSize(int backgroundExecutorMaxPoolSize) {
|
||||
this.backgroundExecutorMaxPoolSize = backgroundExecutorMaxPoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor idle seconds.
|
||||
*/
|
||||
public int getBackgroundExecutorIdleSecs() {
|
||||
return backgroundExecutorIdleSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor idle seconds.
|
||||
*/
|
||||
public void setBackgroundExecutorIdleSecs(int backgroundExecutorIdleSecs) {
|
||||
this.backgroundExecutorIdleSecs = backgroundExecutorIdleSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor shutdown seconds. This is the time allowed for the pool to shutdown nicely
|
||||
* before it is forced shutdown.
|
||||
@@ -1100,20 +1088,6 @@ public class ServerConfig {
|
||||
this.backgroundExecutorShutdownSecs = backgroundExecutorShutdownSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache warming delay in seconds.
|
||||
*/
|
||||
public int getCacheWarmingDelay() {
|
||||
return cacheWarmingDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cache warming delay in seconds.
|
||||
*/
|
||||
public void setCacheWarmingDelay(int cacheWarmingDelay) {
|
||||
this.cacheWarmingDelay = cacheWarmingDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 cache default max size.
|
||||
*/
|
||||
@@ -1487,7 +1461,7 @@ public class ServerConfig {
|
||||
* <p>
|
||||
* You can also set this in ebean.proprerties:
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
* # set via ebean.properties
|
||||
* ebean.encryptKeyManager=com.avaje.tests.basic.encrypt.BasicEncyptKeyManager
|
||||
@@ -1790,67 +1764,6 @@ public class ServerConfig {
|
||||
this.packages = packages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the name of a Jar to search for entities via class path search.
|
||||
* <p>
|
||||
* This is only used if classes have not been explicitly specified.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you are using ebean.properties you can specify jars to search by setting
|
||||
* a ebean.search.jars property.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* # EBean will search through classes for entities, but will not search jar files
|
||||
* # unless you tell it to do so, for performance reasons. Set this value to a
|
||||
* # comma-delimited list of jar files you want ebean to search.
|
||||
* ebean.search.jars=example.jar
|
||||
* }</pre>
|
||||
*/
|
||||
public void addJar(String jarName) {
|
||||
if (searchJars == null) {
|
||||
searchJars = new ArrayList<String>();
|
||||
}
|
||||
searchJars.add(jarName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return packages to search for entities via class path search.
|
||||
* <p>
|
||||
* This is only used if classes have not been explicitly specified.
|
||||
* </p>
|
||||
*/
|
||||
public List<String> getJars() {
|
||||
return searchJars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the names of Jars to search for entities via class path search.
|
||||
* <p>
|
||||
* This is only used if classes have not been explicitly specified.
|
||||
* </p>
|
||||
*/
|
||||
public void setJars(List<String> searchJars) {
|
||||
this.searchJars = searchJars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class name of a classPathReader implementation.
|
||||
*/
|
||||
public String getClassPathReaderClassName() {
|
||||
return classPathReaderClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class name of a classPathReader implementation.
|
||||
* <p>
|
||||
* Refer to server.util.ClassPathReader, this should really by a plugin but doing this for now
|
||||
* to be relatively compatible with current implementation.
|
||||
*/
|
||||
public void setClassPathReaderClassName(String classPathReaderClassName) {
|
||||
this.classPathReaderClassName = classPathReaderClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of classes (entities, listeners, scalarTypes etc) that should
|
||||
* be used for this server.
|
||||
@@ -1874,6 +1787,66 @@ public class ServerConfig {
|
||||
return classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if L2 bean cache should be skipped once writes have occurred on a transaction.
|
||||
* <p>
|
||||
* This defaults to true and means that for "find by id" and "find by natural key"
|
||||
* queries that normally hit L2 bean cache automatically will not do so after a write/persist
|
||||
* on the transaction.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // assume Customer has L2 bean caching enabled ...
|
||||
*
|
||||
* Transaction transaction = Ebean.beginTransaction();
|
||||
* try {
|
||||
*
|
||||
* // this uses L2 bean cache as the transaction
|
||||
* // ... is considered "query only" at this point
|
||||
* Customer.find.byId(42);
|
||||
*
|
||||
* // transaction no longer "query only" once
|
||||
* // ... a bean has been saved etc
|
||||
* Ebean.save(someBean);
|
||||
*
|
||||
* // will NOT use L2 bean cache as the transaction
|
||||
* // ... is no longer considered "query only"
|
||||
* Customer.find.byId(55);
|
||||
*
|
||||
*
|
||||
*
|
||||
* // explicit control - please use L2 bean cache
|
||||
*
|
||||
* transaction.setSkipCache(false);
|
||||
* Customer.find.byId(77); // hit the l2 bean cache
|
||||
*
|
||||
*
|
||||
* // explicit control - please don't use L2 bean cache
|
||||
*
|
||||
* transaction.setSkipCache(true);
|
||||
* Customer.find.byId(99); // skips l2 bean cache
|
||||
*
|
||||
*
|
||||
* } finally {
|
||||
* transaction.end();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see com.avaje.ebean.Transaction#setSkipCache(boolean)
|
||||
*/
|
||||
public boolean isSkipCacheAfterWrite() {
|
||||
return skipCacheAfterWrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to false when we still want to hit the cache after a write has occurred on a transaction.
|
||||
*/
|
||||
public void setSkipCacheAfterWrite(boolean skipCacheAfterWrite) {
|
||||
this.skipCacheAfterWrite = skipCacheAfterWrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true to only update changed properties.
|
||||
*/
|
||||
@@ -1983,6 +1956,54 @@ public class ServerConfig {
|
||||
this.resourceDirectory = resourceDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom type mapping.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set the default mapping for BigDecimal.class/decimal
|
||||
* serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
|
||||
*
|
||||
* // set the default mapping for String.class/varchar but only for Postgres
|
||||
* serverConfig.addCustomMapping(DbType.VARCHAR, "text", Platform.POSTGRES);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param type The DB type this mapping should apply to
|
||||
* @param columnDefinition The column definition that should be used
|
||||
* @param platform Optionally specify the platform this mapping should apply to.
|
||||
*/
|
||||
public void addCustomMapping(DbType type, String columnDefinition, Platform platform) {
|
||||
customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition, platform));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom type mapping that applies to all platforms.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set the default mapping for BigDecimal/decimal
|
||||
* serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
|
||||
*
|
||||
* // set the default mapping for String/varchar
|
||||
* serverConfig.addCustomMapping(DbType.VARCHAR, "text");
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param type The DB type this mapping should apply to
|
||||
* @param columnDefinition The column definition that should be used
|
||||
*/
|
||||
public void addCustomMapping(DbType type, String columnDefinition) {
|
||||
customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of custom type mappings.
|
||||
*/
|
||||
public List<CustomDbTypeMapping> getCustomTypeMappings() {
|
||||
return customDbTypeMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a BeanQueryAdapter instance.
|
||||
* <p>
|
||||
@@ -2055,6 +2076,16 @@ public class ServerConfig {
|
||||
postLoaders.add(postLoad);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a BeanPostConstructListener instance.
|
||||
* <p>
|
||||
* Note alternatively you can use {@link #setPostConstructListeners(List)} to set
|
||||
* all the BeanPostConstructListener instances.
|
||||
* </p>
|
||||
*/
|
||||
public void add(BeanPostConstructListener listener) {
|
||||
postConstructListeners.add(listener);
|
||||
}
|
||||
/**
|
||||
* Return the list of BeanFindController instances.
|
||||
*/
|
||||
@@ -2083,6 +2114,19 @@ public class ServerConfig {
|
||||
this.postLoaders = postLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanPostLoader instances.
|
||||
*/
|
||||
public List<BeanPostConstructListener> getPostConstructListeners() {
|
||||
return postConstructListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of BeanPostLoader instances.
|
||||
*/
|
||||
public void setPostConstructListeners(List<BeanPostConstructListener> listeners) {
|
||||
this.postConstructListeners = listeners;
|
||||
}
|
||||
/**
|
||||
* Return the BeanPersistController instances.
|
||||
*/
|
||||
@@ -2101,35 +2145,6 @@ public class ServerConfig {
|
||||
this.persistControllers = persistControllers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a TransactionEventListener instance
|
||||
* <p>
|
||||
* Note alternatively you can use {@link #setTransactionEventListeners(List)}
|
||||
* to set all the TransactionEventListener instances.
|
||||
* </p>
|
||||
*/
|
||||
public void add(TransactionEventListener listener) {
|
||||
transactionEventListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TransactionEventListener instances.
|
||||
*/
|
||||
public List<TransactionEventListener> getTransactionEventListeners() {
|
||||
return transactionEventListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all the TransactionEventListener instances.
|
||||
* <p>
|
||||
* Note alternatively you can use {@link #add(TransactionEventListener)} to
|
||||
* add TransactionEventListener instances one at a time.
|
||||
* </p>
|
||||
*/
|
||||
public void setTransactionEventListeners(List<TransactionEventListener> transactionEventListeners) {
|
||||
this.transactionEventListeners = transactionEventListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a BeanPersistListener instance.
|
||||
* <p>
|
||||
@@ -2367,11 +2382,14 @@ public class ServerConfig {
|
||||
}
|
||||
loadDocStoreSettings(p);
|
||||
|
||||
geometrySRID = p.getInt("geometrySRID", geometrySRID);
|
||||
disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache);
|
||||
explicitTransactionBeginMode = p.getBoolean("explicitTransactionBeginMode", explicitTransactionBeginMode);
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
|
||||
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager);
|
||||
|
||||
backgroundExecutorSchedulePoolSize = p.getInt("backgroundExecutorSchedulePoolSize", backgroundExecutorSchedulePoolSize);
|
||||
backgroundExecutorShutdownSecs = p.getInt("backgroundExecutorShutdownSecs", backgroundExecutorShutdownSecs);
|
||||
disableClasspathSearch = p.getBoolean("disableClasspathSearch", disableClasspathSearch);
|
||||
currentUserProvider = createInstance(p, CurrentUserProvider.class, "currentUserProvider", currentUserProvider);
|
||||
databasePlatform = createInstance(p, DatabasePlatform.class, "databasePlatform", databasePlatform);
|
||||
@@ -2381,13 +2399,6 @@ public class ServerConfig {
|
||||
dbEncrypt = createInstance(p, DbEncrypt.class, "dbEncrypt", dbEncrypt);
|
||||
serverCachePlugin = createInstance(p, ServerCachePlugin.class, "serverCachePlugin", serverCachePlugin);
|
||||
serverCacheManager = createInstance(p, ServerCacheManager.class, "serverCacheManager", serverCacheManager);
|
||||
cacheWarmingDelay = p.getInt("cacheWarmingDelay", cacheWarmingDelay);
|
||||
classPathReaderClassName = p.get("classpathreader");
|
||||
|
||||
String jarsProp = p.get("search.jars", p.get("jars", null));
|
||||
if (jarsProp != null) {
|
||||
searchJars = getSearchJarsPackages(jarsProp);
|
||||
}
|
||||
|
||||
if (packages != null) {
|
||||
String packagesProp = p.get("search.packages", p.get("packages", null));
|
||||
@@ -2397,6 +2408,7 @@ public class ServerConfig {
|
||||
collectQueryStatsByNode = p.getBoolean("collectQueryStatsByNode", collectQueryStatsByNode);
|
||||
collectQueryOrigins = p.getBoolean("collectQueryOrigins", collectQueryOrigins);
|
||||
|
||||
skipCacheAfterWrite = p.getBoolean("skipCacheAfterWrite", skipCacheAfterWrite);
|
||||
updateAllPropertiesInBatch = p.getBoolean("updateAllPropertiesInBatch", updateAllPropertiesInBatch);
|
||||
updateChangesOnly = p.getBoolean("updateChangesOnly", updateChangesOnly);
|
||||
|
||||
@@ -2424,6 +2436,8 @@ public class ServerConfig {
|
||||
asOfSysPeriod = p.get("asOfSysPeriod", asOfSysPeriod);
|
||||
historyTableSuffix = p.get("historyTableSuffix", historyTableSuffix);
|
||||
dataSourceJndiName = p.get("dataSourceJndiName", dataSourceJndiName);
|
||||
jdbcFetchSizeFindEach = p.getInt("jdbcFetchSizeFindEach", jdbcFetchSizeFindEach);
|
||||
jdbcFetchSizeFindList = p.getInt("jdbcFetchSizeFindList", jdbcFetchSizeFindList);
|
||||
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
|
||||
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
|
||||
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
|
||||
@@ -2479,7 +2493,7 @@ public class ServerConfig {
|
||||
String[] split = classNames.split("[ ,;]");
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
String cn = split[i].trim();
|
||||
if (cn.length() > 0 && !"class".equalsIgnoreCase(cn)) {
|
||||
if (!cn.isEmpty() && !"class".equalsIgnoreCase(cn)) {
|
||||
try {
|
||||
classes.add(Class.forName(cn));
|
||||
} catch (ClassNotFoundException e) {
|
||||
@@ -2508,13 +2522,14 @@ public class ServerConfig {
|
||||
/**
|
||||
* Return the PersistBatch mode to use for 'batchOnCascade' taking into account if the database
|
||||
* platform supports getGeneratedKeys in batch mode.
|
||||
* <p>
|
||||
* Used to effectively turn off batchOnCascade for SQL Server - still allows explicit batch mode.
|
||||
* </p>
|
||||
*/
|
||||
public PersistBatch appliedPersistBatchOnCascade() {
|
||||
|
||||
return databasePlatform.isDisallowBatchOnCascade() ? PersistBatch.NONE : persistBatchOnCascade;
|
||||
if (persistBatchOnCascade == PersistBatch.INHERIT) {
|
||||
// use the platform default (ALL except SQL Server which has NONE)
|
||||
return databasePlatform.getPersistBatchOnCascade();
|
||||
}
|
||||
return persistBatchOnCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2590,18 +2605,45 @@ public class ServerConfig {
|
||||
public enum DbUuid {
|
||||
|
||||
/**
|
||||
* Store using native UUID in H2 and Postgres.
|
||||
* Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40).
|
||||
*/
|
||||
AUTO,
|
||||
AUTO_VARCHAR(true, false),
|
||||
|
||||
/**
|
||||
* Store using DB VARCHAR.
|
||||
* Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16).
|
||||
*/
|
||||
VARCHAR,
|
||||
AUTO_BINARY(true, true),
|
||||
|
||||
/**
|
||||
* Store using DB BINARY.
|
||||
* Store using DB VARCHAR(40).
|
||||
*/
|
||||
BINARY
|
||||
VARCHAR(false, false),
|
||||
|
||||
/**
|
||||
* Store using DB BINARY(16).
|
||||
*/
|
||||
BINARY(false, true);
|
||||
|
||||
boolean nativeType;
|
||||
boolean binary;
|
||||
|
||||
DbUuid(boolean nativeType, boolean binary) {
|
||||
this.nativeType = nativeType;
|
||||
this.binary = binary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if native UUID type is preferred.
|
||||
*/
|
||||
public boolean useNativeType() {
|
||||
return nativeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if BINARY(16) storage is preferred over VARCHAR(40).
|
||||
*/
|
||||
public boolean useBinary() {
|
||||
return binary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +146,6 @@ public final class TableName {
|
||||
* @return true, if is valid
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return name != null && name.length() > 0;
|
||||
return name != null && !name.isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Adds ANSI based OFFSET FETCH NEXT clauses to a SQL query.
|
||||
*/
|
||||
public class BasicSqlAnsiLimiter implements BasicSqlLimiter {
|
||||
|
||||
@Override
|
||||
public String limit(String dbSql, int firstRow, int maxRows) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(50 + dbSql.length());
|
||||
|
||||
sb.append(dbSql);
|
||||
if (firstRow > 0) {
|
||||
sb.append(" ").append("offset");
|
||||
sb.append(" ").append(firstRow).append(" rows");
|
||||
}
|
||||
if (maxRows > 0) {
|
||||
sb.append(" fetch next ").append(maxRows).append(" rows only");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Adds LIMIT OFFSET clauses to a SQL query.
|
||||
*/
|
||||
public class BasicSqlLimitOffset implements BasicSqlLimiter {
|
||||
|
||||
/**
|
||||
* LIMIT keyword.
|
||||
*/
|
||||
private static final String LIMIT = "limit";
|
||||
|
||||
/**
|
||||
* OFFSET keyword.
|
||||
*/
|
||||
private static final String OFFSET = "offset";
|
||||
|
||||
@Override
|
||||
public String limit(String dbSql, int firstRow, int maxRows) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(50 + dbSql.length());
|
||||
|
||||
sb.append(dbSql);
|
||||
|
||||
if (maxRows > 0) {
|
||||
sb.append(" ").append(LIMIT);
|
||||
sb.append(" ").append(maxRows);
|
||||
}
|
||||
if (firstRow > 0) {
|
||||
sb.append(" ").append(OFFSET).append(" ");
|
||||
sb.append(firstRow);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Simple SQL limiter for use with SqlQuery.
|
||||
*/
|
||||
public interface BasicSqlLimiter {
|
||||
|
||||
/**
|
||||
* Add basic offset/limit clause to SqlQuery query.
|
||||
*/
|
||||
String limit(String dbSql, int firstRow, int maxRows);
|
||||
}
|
||||
@@ -24,9 +24,9 @@ public class DB2Platform extends DatabasePlatform {
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
booleanDbType = Types.BOOLEAN;
|
||||
dbTypeMap.put(Types.REAL, new DbType("real"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 15));
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("real"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 15));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,9 @@ package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.config.CustomDbTypeMapping;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
import com.avaje.ebean.config.Platform;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
|
||||
@@ -14,7 +17,6 @@ import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Database platform specific settings.
|
||||
@@ -33,12 +35,6 @@ public class DatabasePlatform {
|
||||
*/
|
||||
ROLLBACK,
|
||||
|
||||
/**
|
||||
* Just close the transaction. Valid at READ_COMMITTED isolation and preferred on some Databases
|
||||
* as a performance optimisation.
|
||||
*/
|
||||
CLOSE,
|
||||
|
||||
/**
|
||||
* Commit the transaction
|
||||
*/
|
||||
@@ -71,10 +67,15 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected SqlLimiter sqlLimiter = new LimitOffsetSqlLimiter();
|
||||
|
||||
/**
|
||||
* Limit/offset support for SqlQuery only.
|
||||
*/
|
||||
protected BasicSqlLimiter basicSqlLimiter = new BasicSqlLimitOffset();
|
||||
|
||||
/**
|
||||
* Mapping of JDBC to Database types.
|
||||
*/
|
||||
protected DbTypeMap dbTypeMap = new DbTypeMap();
|
||||
protected DbPlatformTypeMapping dbTypeMap = new DbPlatformTypeMapping();
|
||||
|
||||
/**
|
||||
* Default values for DB columns.
|
||||
@@ -150,11 +151,9 @@ public class DatabasePlatform {
|
||||
protected boolean forwardOnlyHintOnFindIterate;
|
||||
|
||||
/**
|
||||
* Flag set for SQL Server due to lack of support of getGeneratedKeys in
|
||||
* batch mode (meaning for batch inserts you should explicitly turn off
|
||||
* getGeneratedKeys - joy).
|
||||
* By default we use JDBC batch when cascading (except for SQL Server).
|
||||
*/
|
||||
protected boolean disallowBatchOnCascade;
|
||||
protected PersistBatch persistBatchOnCascade = PersistBatch.ALL;
|
||||
|
||||
protected PlatformDdl platformDdl;
|
||||
|
||||
@@ -178,8 +177,24 @@ public class DatabasePlatform {
|
||||
public DatabasePlatform() {
|
||||
}
|
||||
|
||||
public void configure(Properties properties) {
|
||||
// by default do nothing
|
||||
/**
|
||||
* Configure UUID Storage etc based on ServerConfig settings.
|
||||
*/
|
||||
public void configure(ServerConfig serverConfig) {
|
||||
dbTypeMap.config(nativeUuidType, serverConfig.getDbUuid());
|
||||
for (CustomDbTypeMapping mapping : serverConfig.getCustomTypeMappings()) {
|
||||
if (platformMatch(mapping.getPlatform())) {
|
||||
dbTypeMap.put(mapping.getType(), parse(mapping.getColumnDefinition()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DbPlatformType parse(String columnDefinition) {
|
||||
return DbPlatformType.parse(columnDefinition);
|
||||
}
|
||||
|
||||
private boolean platformMatch(Platform platform) {
|
||||
return platform == null || platform.name().equalsIgnoreCase(name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,7 +324,7 @@ public class DatabasePlatform {
|
||||
*
|
||||
* @return the db type map
|
||||
*/
|
||||
public DbTypeMap getDbTypeMap() {
|
||||
public DbPlatformTypeMapping getDbTypeMap() {
|
||||
return dbTypeMap;
|
||||
}
|
||||
|
||||
@@ -454,6 +469,13 @@ public class DatabasePlatform {
|
||||
return sqlLimiter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BasicSqlLimiter for limit/offset of SqlQuery queries.
|
||||
*/
|
||||
public BasicSqlLimiter getBasicSqlLimiter() {
|
||||
return basicSqlLimiter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB TRUE literal (from the registered boolean ScalarType)
|
||||
*/
|
||||
@@ -480,7 +502,7 @@ public class DatabasePlatform {
|
||||
*/
|
||||
public String convertQuotedIdentifiers(String dbName) {
|
||||
// Ignore null values e.g. schema name or catalog
|
||||
if (dbName != null && dbName.length() > 0) {
|
||||
if (dbName != null && !dbName.isEmpty()) {
|
||||
if (dbName.charAt(0) == BACK_TICK) {
|
||||
if (dbName.charAt(dbName.length() - 1) == BACK_TICK) {
|
||||
|
||||
@@ -530,14 +552,10 @@ public class DatabasePlatform {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the persistBatchOnCascade setting should be ignored.
|
||||
* <p>
|
||||
* This is primarily for SQL Server which does not support getGeneratedKeys with jdbc batch mode
|
||||
* so can't really be transparently used.
|
||||
* </p>
|
||||
* Return the platform default JDBC batch mode for persist cascade.
|
||||
*/
|
||||
public boolean isDisallowBatchOnCascade() {
|
||||
return disallowBatchOnCascade;
|
||||
public PersistBatch getPersistBatchOnCascade() {
|
||||
return persistBatchOnCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,11 +6,13 @@ package com.avaje.ebean.config.dbplatform;
|
||||
public interface DbHistorySupport {
|
||||
|
||||
/**
|
||||
* Return true if the 'As of' predicate is part of the from clause
|
||||
* (more standard sql2011). So true for Oracle total recall and false
|
||||
* for Postgres and MySql (where we use views and history tables).
|
||||
* Return true if the implementation is SQL2011 standards based.
|
||||
* <p>
|
||||
* Non standards based means we need to add additional predicates into the
|
||||
* JOIN ON clause and add an additional predicate for the base table.
|
||||
* </p>
|
||||
*/
|
||||
boolean isBindWithFromClause();
|
||||
boolean isStandardsBased();
|
||||
|
||||
/**
|
||||
* Return the number of columns bound in a 'As Of' predicate.
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Represents a DB type with name, length, precision, and scale.
|
||||
* <p>
|
||||
* The length is for VARCHAR types and precision/scale for DECIMAL types.
|
||||
* </p>
|
||||
*/
|
||||
public class DbPlatformType implements ExtraDbTypes {
|
||||
|
||||
/**
|
||||
* The data type name (VARCHAR, INTEGER ...)
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The default length or precision.
|
||||
*/
|
||||
private final int defaultLength;
|
||||
|
||||
/**
|
||||
* The default scale (decimal).
|
||||
*/
|
||||
private final int defaultScale;
|
||||
|
||||
/**
|
||||
* Set to true if the type should never have a length or scale.
|
||||
*/
|
||||
private final boolean canHaveLength;
|
||||
|
||||
/**
|
||||
* Parse a type definition into a DbPlatformType.
|
||||
* <p>
|
||||
* e.g. "decimal(18,6)"
|
||||
* e.g. "text"
|
||||
* </p>
|
||||
*/
|
||||
public static DbPlatformType parse(String columnDefinition) {
|
||||
return DbPlatformTypeParser.parse(columnDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with no length or scale.
|
||||
*/
|
||||
public DbPlatformType(String name) {
|
||||
this(name, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a given length.
|
||||
*/
|
||||
public DbPlatformType(String name, int defaultLength) {
|
||||
this(name, defaultLength, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for Decimal with precision and scale.
|
||||
*/
|
||||
public DbPlatformType(String name, int defaultPrecision, int defaultScale) {
|
||||
this.name = name;
|
||||
this.defaultLength = defaultPrecision;
|
||||
this.defaultScale = defaultScale;
|
||||
this.canHaveLength = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use with canHaveLength=false for types that should never have a length.
|
||||
*
|
||||
* @param name
|
||||
* the type name
|
||||
* @param canHaveLength
|
||||
* set this to false for type that should never have a length
|
||||
*/
|
||||
public DbPlatformType(String name, boolean canHaveLength) {
|
||||
this.name = name;
|
||||
this.defaultLength = 0;
|
||||
this.defaultScale = 0;
|
||||
this.canHaveLength = canHaveLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default length/precision.
|
||||
*/
|
||||
public int getDefaultLength() {
|
||||
return defaultLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default scale.
|
||||
*/
|
||||
public int getDefaultScale() {
|
||||
return defaultScale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for a specific property that incorporates the name, length,
|
||||
* precision and scale.
|
||||
* <p>
|
||||
* The deployLength and deployScale are for the property we are rendering the
|
||||
* DB type for.
|
||||
* </p>
|
||||
*
|
||||
* @param deployLength
|
||||
* the length or precision defined by deployment on a specific
|
||||
* property.
|
||||
* @param deployScale
|
||||
* the scale defined by deployment on a specific property.
|
||||
*/
|
||||
public String renderType(int deployLength, int deployScale) {
|
||||
return renderType(deployLength, deployScale, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the type defining strict mode.
|
||||
* <p>
|
||||
* If strict mode if OFF then this will render with a scale value even if
|
||||
* that is not strictly supported. The reason for supporting this is to enable
|
||||
* use to use types like jsonb(200) as a "logical" type that maps to JSONB for
|
||||
* Postgres and VARCHAR(200) for other databases.
|
||||
* </p>
|
||||
*/
|
||||
public String renderType(int deployLength, int deployScale, boolean strict) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(name);
|
||||
|
||||
if (canHaveLength || !strict) {
|
||||
// see if there is a precision/scale to add (or not)
|
||||
int len = deployLength != 0 ? deployLength : defaultLength;
|
||||
if (len > 0) {
|
||||
sb.append("(");
|
||||
sb.append(len);
|
||||
int scale = deployScale != 0 ? deployScale : defaultScale;
|
||||
if (scale > 0) {
|
||||
sb.append(",");
|
||||
sb.append(scale);
|
||||
}
|
||||
sb.append(")");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of the type with a new default length.
|
||||
*/
|
||||
public DbPlatformType withLength(int defaultLength) {
|
||||
return new DbPlatformType(name, defaultLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Helper to reverse lookup a DbType given the name or JDBC int value.
|
||||
*/
|
||||
class DbPlatformTypeLookup {
|
||||
|
||||
/**
|
||||
* A map to lookup the type by name.
|
||||
*/
|
||||
private Map<String, DbType> nameLookup = new HashMap<String, DbType>();
|
||||
|
||||
/**
|
||||
* A map to lookup the type by JDBC int value.
|
||||
*/
|
||||
private Map<Integer, DbType> idLookup = new HashMap<Integer, DbType>();
|
||||
|
||||
DbPlatformTypeLookup() {
|
||||
addAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DbType for the given name.
|
||||
*/
|
||||
DbType byName(String name) {
|
||||
return nameLookup.get(name.trim().toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DbType for the given name.
|
||||
*/
|
||||
DbType byId(int jdbcId) {
|
||||
return idLookup.get(jdbcId);
|
||||
}
|
||||
|
||||
private void addAll() {
|
||||
// Extra mapping for Float and Varchar2
|
||||
add("FLOAT", DbType.REAL);
|
||||
add("VARCHAR2", DbType.VARCHAR);
|
||||
for (DbType type : DbType.values()) {
|
||||
add(type.name(), type);
|
||||
}
|
||||
}
|
||||
|
||||
private void add(String name, DbType dbType) {
|
||||
nameLookup.put(name, dbType);
|
||||
idLookup.put(dbType.id(), dbType);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Used to map bean property types to DB specific types for DDL generation.
|
||||
*/
|
||||
public class DbPlatformTypeMapping {
|
||||
|
||||
private static DbPlatformTypeLookup lookup = new DbPlatformTypeLookup();
|
||||
|
||||
private static final DbPlatformType UUID_NATIVE = new DbPlatformType("uuid", false);
|
||||
private static final DbPlatformType UUID_PLACEHOLDER = new DbPlatformType("uuidPlaceholder");
|
||||
private static final DbPlatformType JSON_CLOB_PLACEHOLDER = new DbPlatformType("jsonClobPlaceholder");
|
||||
private static final DbPlatformType JSON_BLOB_PLACEHOLDER = new DbPlatformType("jsonBlobPlaceholder");
|
||||
private static final DbPlatformType JSON_VARCHAR_PLACEHOLDER = new DbPlatformType("jsonVarcharPlaceholder");
|
||||
|
||||
private static final DbPlatformType POINT = new DbPlatformType("point");
|
||||
private static final DbPlatformType POLYGON = new DbPlatformType("polygon");
|
||||
private static final DbPlatformType LINESTRING = new DbPlatformType("linestring");
|
||||
private static final DbPlatformType MULTIPOINT = new DbPlatformType("multipoint");
|
||||
private static final DbPlatformType MULTILINESTRING = new DbPlatformType("multilinestring");
|
||||
private static final DbPlatformType MULTIPOLYGON = new DbPlatformType("multipolygon");
|
||||
|
||||
private final Map<DbType, DbPlatformType> typeMap = new HashMap<DbType, DbPlatformType>();
|
||||
|
||||
/**
|
||||
* Return the DbTypeMap with standard (not platform specific) types.
|
||||
* <p>
|
||||
* This has some extended JSON types (JSON, JSONB, JSONVarchar, JSONClob, JSONBlob).
|
||||
* These types get translated to specific database platform types during DDL generation.
|
||||
*/
|
||||
public static DbPlatformTypeMapping logicalTypes() {
|
||||
return new DbPlatformTypeMapping(true);
|
||||
}
|
||||
|
||||
public DbPlatformTypeMapping() {
|
||||
loadDefaults(false);
|
||||
}
|
||||
|
||||
private DbPlatformTypeMapping(boolean logicalTypes) {
|
||||
loadDefaults(logicalTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the standard types. These can be overridden by DB specific platform.
|
||||
*/
|
||||
private void loadDefaults(boolean logicalTypes) {
|
||||
|
||||
put(DbType.BOOLEAN);
|
||||
put(DbType.BIT);
|
||||
put(DbType.INTEGER);
|
||||
put(DbType.BIGINT);
|
||||
put(DbType.DOUBLE);
|
||||
put(DbType.SMALLINT);
|
||||
put(DbType.TINYINT);
|
||||
put(DbType.BLOB);
|
||||
put(DbType.CLOB);
|
||||
put(DbType.ARRAY);
|
||||
put(DbType.DATE);
|
||||
put(DbType.TIME);
|
||||
put(DbType.TIMESTAMP);
|
||||
put(DbType.LONGVARBINARY);
|
||||
put(DbType.LONGVARCHAR);
|
||||
// most commonly real maps to db float
|
||||
put(DbType.REAL, new DbPlatformType("float"));
|
||||
|
||||
put(DbType.POINT, POINT);
|
||||
put(DbType.POLYGON, POLYGON);
|
||||
put(DbType.LINESTRING, LINESTRING);
|
||||
put(DbType.MULTIPOINT, MULTIPOINT);
|
||||
put(DbType.MULTILINESTRING, MULTILINESTRING);
|
||||
put(DbType.MULTIPOLYGON, MULTIPOLYGON);
|
||||
|
||||
if (logicalTypes) {
|
||||
// keep it logical for 2 layer DDL generation
|
||||
put(DbType.VARCHAR, new DbPlatformType("varchar"));
|
||||
put(DbType.DECIMAL, new DbPlatformType("decimal"));
|
||||
put(DbType.VARBINARY, new DbPlatformType("varbinary"));
|
||||
put(DbType.BINARY, new DbPlatformType("binary"));
|
||||
put(DbType.CHAR, new DbPlatformType("char"));
|
||||
|
||||
put(DbType.HSTORE, new DbPlatformType("hstore", false));
|
||||
put(DbType.JSON, new DbPlatformType("json", false));
|
||||
put(DbType.JSONB, new DbPlatformType("jsonb", false));
|
||||
put(DbType.JSONCLOB, new DbPlatformType("jsonclob"));
|
||||
put(DbType.JSONBLOB, new DbPlatformType("jsonblob"));
|
||||
put(DbType.JSONVARCHAR, new DbPlatformType("jsonvarchar", 1000));
|
||||
put(DbType.UUID, UUID_NATIVE);
|
||||
|
||||
} else {
|
||||
put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
|
||||
put(DbType.DECIMAL, new DbPlatformType("decimal", 38));
|
||||
put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
|
||||
put(DbType.BINARY, new DbPlatformType("binary", 255));
|
||||
put(DbType.CHAR, new DbPlatformType("char", 1));
|
||||
|
||||
put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON
|
||||
put(DbType.JSONB, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSONB
|
||||
put(DbType.JSONCLOB, JSON_CLOB_PLACEHOLDER);
|
||||
put(DbType.JSONBLOB, JSON_BLOB_PLACEHOLDER);
|
||||
put(DbType.JSONVARCHAR, JSON_VARCHAR_PLACEHOLDER);
|
||||
put(DbType.UUID, UUID_PLACEHOLDER);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the platform specific DbType given the standard sql type name.
|
||||
*/
|
||||
public DbPlatformType lookup(String name, boolean withScale) {
|
||||
|
||||
DbType type = lookup.byName(name);
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Unknown type [" + name + "] - not standard sql type");
|
||||
}
|
||||
// handle JSON types mapped to clob, blob and varchar
|
||||
switch (type) {
|
||||
case JSONBLOB:
|
||||
return get(DbType.BLOB);
|
||||
case JSONCLOB:
|
||||
return get(DbType.CLOB);
|
||||
case JSONVARCHAR:
|
||||
return get(DbType.VARCHAR);
|
||||
case JSON:
|
||||
return getJsonType(DbType.JSON, withScale);
|
||||
case JSONB:
|
||||
return getJsonType(DbType.JSONB, withScale);
|
||||
default:
|
||||
return get(type);
|
||||
}
|
||||
}
|
||||
|
||||
private DbPlatformType getJsonType(DbType type, boolean withScale) {
|
||||
|
||||
DbPlatformType dbType = get(type);
|
||||
if (dbType == JSON_CLOB_PLACEHOLDER) {
|
||||
// if we have scale that implies this maps to varchar
|
||||
return withScale ? get(DbType.VARCHAR) : get(DbType.CLOB);
|
||||
}
|
||||
if (dbType == JSON_BLOB_PLACEHOLDER) {
|
||||
return get(DbType.BLOB);
|
||||
}
|
||||
if (dbType == JSON_VARCHAR_PLACEHOLDER) {
|
||||
return get(DbType.VARCHAR);
|
||||
}
|
||||
// Postgres has specific type
|
||||
return get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the type for a given JDBC type.
|
||||
*/
|
||||
private void put(DbType type) {
|
||||
typeMap.put(type, type.createPlatformType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the type for a given JDBC type.
|
||||
*/
|
||||
public void put(DbType type, DbPlatformType platformType) {
|
||||
typeMap.put(type, platformType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for a given jdbc type.
|
||||
*/
|
||||
public DbPlatformType get(int jdbcType) {
|
||||
return get(lookup.byId(jdbcType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for a given jdbc type.
|
||||
*/
|
||||
public DbPlatformType get(DbType dbType) {
|
||||
return typeMap.get(dbType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the UUID appropriately based on native DB support and ServerConfig.DbUuid.
|
||||
*/
|
||||
public void config(boolean nativeUuidType, ServerConfig.DbUuid dbUuid) {
|
||||
if (nativeUuidType && dbUuid.useNativeType()) {
|
||||
put(DbType.UUID, UUID_NATIVE);
|
||||
} else if (dbUuid.useBinary()) {
|
||||
put(DbType.UUID, get(DbType.BINARY).withLength(16));
|
||||
} else {
|
||||
put(DbType.UUID, get(DbType.VARCHAR).withLength(40));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Parse raw column definitions into DbPlatformType like "decimal(18,6)" and "varchar(20) and "json".
|
||||
*/
|
||||
class DbPlatformTypeParser {
|
||||
|
||||
/**
|
||||
* Parse the column definition and return the DbPlatformType.
|
||||
*/
|
||||
static DbPlatformType parse(String columnDefinition) {
|
||||
|
||||
columnDefinition = columnDefinition.trim();
|
||||
|
||||
int openPos = columnDefinition.indexOf('(');
|
||||
if (openPos == -1) {
|
||||
return new DbPlatformType(columnDefinition, false);
|
||||
}
|
||||
int closePos = columnDefinition.indexOf(')', openPos);
|
||||
if (closePos == -1) {
|
||||
return new DbPlatformType(columnDefinition, false);
|
||||
}
|
||||
try {
|
||||
int commaPos = columnDefinition.indexOf(',', openPos);
|
||||
if (commaPos > -1) {
|
||||
String type = columnDefinition.substring(0, openPos);
|
||||
int scale = Integer.parseInt(columnDefinition.substring(openPos + 1, commaPos));
|
||||
int precision = Integer.parseInt(columnDefinition.substring(commaPos + 1, closePos));
|
||||
return new DbPlatformType(type, scale, precision);
|
||||
|
||||
} else {
|
||||
String type = columnDefinition.substring(0, openPos);
|
||||
int scale = Integer.parseInt(columnDefinition.substring(openPos + 1, closePos));
|
||||
return new DbPlatformType(type, scale);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
return new DbPlatformType(columnDefinition, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,8 @@ package com.avaje.ebean.config.dbplatform;
|
||||
*/
|
||||
public abstract class DbStandardHistorySupport implements DbHistorySupport {
|
||||
|
||||
/**
|
||||
* Return true as with sql2011 the 'as of timestamp' clause included in from or join clause.
|
||||
*/
|
||||
@Override
|
||||
public boolean isBindWithFromClause() {
|
||||
public boolean isStandardsBased() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,155 +1,72 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Represents a DB type with name, length, precision, and scale.
|
||||
* The known DB types that are mapped.
|
||||
* <p>
|
||||
* The length is for VARCHAR types and precision/scale for DECIMAL types.
|
||||
* This includes extra types such as UUID, JSON, JSONB and HSTORE.
|
||||
* </p>
|
||||
*/
|
||||
public class DbType {
|
||||
public enum DbType {
|
||||
|
||||
/**
|
||||
* DB native UUID type (H2 and Postgres).
|
||||
*/
|
||||
public static final int UUID = 5010;
|
||||
BOOLEAN(Types.BOOLEAN),
|
||||
BIT(Types.BIT),
|
||||
INTEGER(Types.INTEGER),
|
||||
BIGINT(Types.BIGINT),
|
||||
SMALLINT(Types.SMALLINT),
|
||||
TINYINT(Types.TINYINT),
|
||||
REAL(Types.REAL),
|
||||
//FLOAT(Types.FLOAT),
|
||||
DOUBLE(Types.DOUBLE),
|
||||
DECIMAL(Types.DECIMAL),
|
||||
VARCHAR(Types.VARCHAR),
|
||||
CHAR(Types.CHAR),
|
||||
BLOB(Types.BLOB),
|
||||
CLOB(Types.CLOB),
|
||||
LONGVARBINARY(Types.LONGVARBINARY),
|
||||
LONGVARCHAR(Types.LONGVARCHAR),
|
||||
VARBINARY(Types.VARBINARY),
|
||||
BINARY(Types.BINARY),
|
||||
DATE(Types.DATE),
|
||||
TIME(Types.TIME),
|
||||
TIMESTAMP(Types.TIMESTAMP),
|
||||
|
||||
/**
|
||||
* Type to map Map content to Postgres HSTORE.
|
||||
*/
|
||||
public static final int HSTORE = 5000;
|
||||
ARRAY(Types.ARRAY),
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Clob or Postgres JSON type.
|
||||
*/
|
||||
public static final int JSON = 5001;
|
||||
UUID(ExtraDbTypes.UUID),
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Clob or Postgres JSONB type.
|
||||
*/
|
||||
public static final int JSONB = 5002;
|
||||
POINT(ExtraDbTypes.POINT),
|
||||
POLYGON(ExtraDbTypes.POLYGON),
|
||||
LINESTRING(ExtraDbTypes.LINESTRING),
|
||||
MULTIPOINT(ExtraDbTypes.MULTIPOINT),
|
||||
MULTILINESTRING(ExtraDbTypes.MULTILINESTRING),
|
||||
MULTIPOLYGON(ExtraDbTypes.MULTIPOLYGON),
|
||||
|
||||
/**
|
||||
* Type to map JSON content to VARCHAR.
|
||||
*/
|
||||
public static final int JSONVarchar = 5003;
|
||||
HSTORE(ExtraDbTypes.HSTORE),
|
||||
JSON(ExtraDbTypes.JSON),
|
||||
JSONB(ExtraDbTypes.JSONB),
|
||||
JSONCLOB(ExtraDbTypes.JSONClob),
|
||||
JSONBLOB(ExtraDbTypes.JSONBlob),
|
||||
JSONVARCHAR(ExtraDbTypes.JSONVarchar);
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Clob.
|
||||
*/
|
||||
public static final int JSONClob = 5004;
|
||||
private final int id;
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Blob.
|
||||
*/
|
||||
public static final int JSONBlob = 5005;
|
||||
|
||||
/**
|
||||
* The data type name (VARCHAR, INTEGER ...)
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The default length or precision.
|
||||
*/
|
||||
private final int defaultLength;
|
||||
|
||||
/**
|
||||
* The default scale (decimal).
|
||||
*/
|
||||
private final int defaultScale;
|
||||
|
||||
/**
|
||||
* Set to true if the type should never have a length or scale.
|
||||
*/
|
||||
private final boolean canHaveLength;
|
||||
|
||||
/**
|
||||
* Construct with no length or scale.
|
||||
*/
|
||||
public DbType(String name) {
|
||||
this(name, 0, 0);
|
||||
DbType(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a given length.
|
||||
* Return the JDBC java.sql.Types value.
|
||||
*/
|
||||
public DbType(String name, int defaultLength) {
|
||||
this(name, defaultLength, 0);
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for Decimal with precision and scale.
|
||||
* Create a platform type without scale or precision.
|
||||
*/
|
||||
public DbType(String name, int defaultPrecision, int defaultScale) {
|
||||
this.name = name;
|
||||
this.defaultLength = defaultPrecision;
|
||||
this.defaultScale = defaultScale;
|
||||
this.canHaveLength = true;
|
||||
public DbPlatformType createPlatformType() {
|
||||
return new DbPlatformType(name().toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Use with canHaveLength=false for types that should never have a length.
|
||||
*
|
||||
* @param name
|
||||
* the type name
|
||||
* @param canHaveLength
|
||||
* set this to false for type that should never have a length
|
||||
*/
|
||||
public DbType(String name, boolean canHaveLength) {
|
||||
this.name = name;
|
||||
this.defaultLength = 0;
|
||||
this.defaultScale = 0;
|
||||
this.canHaveLength = canHaveLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for a specific property that incorporates the name, length,
|
||||
* precision and scale.
|
||||
* <p>
|
||||
* The deployLength and deployScale are for the property we are rendering the
|
||||
* DB type for.
|
||||
* </p>
|
||||
*
|
||||
* @param deployLength
|
||||
* the length or precision defined by deployment on a specific
|
||||
* property.
|
||||
* @param deployScale
|
||||
* the scale defined by deployment on a specific property.
|
||||
*/
|
||||
public String renderType(int deployLength, int deployScale) {
|
||||
return renderType(deployLength, deployScale, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the type defining strict mode.
|
||||
* <p>
|
||||
* If strict mode if OFF then this will render with a scale value even if
|
||||
* that is not strictly supported. The reason for supporting this is to enable
|
||||
* use to use types like jsonb(200) as a "logical" type that maps to JSONB for
|
||||
* Postgres and VARCHAR(200) for other databases.
|
||||
* </p>
|
||||
*/
|
||||
public String renderType(int deployLength, int deployScale, boolean strict) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(name);
|
||||
|
||||
if (canHaveLength || !strict) {
|
||||
// see if there is a precision/scale to add (or not)
|
||||
int len = deployLength != 0 ? deployLength : defaultLength;
|
||||
if (len > 0) {
|
||||
sb.append("(");
|
||||
sb.append(len);
|
||||
int scale = deployScale != 0 ? deployScale : defaultScale;
|
||||
if (scale > 0) {
|
||||
sb.append(",");
|
||||
sb.append(scale);
|
||||
}
|
||||
sb.append(")");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Used to map bean property types to DB specific types for DDL generation.
|
||||
*/
|
||||
public class DbTypeMap {
|
||||
|
||||
private static final DbType JSON_CLOB_PLACEHOLDER = new DbType("jsonClobPlaceholder");
|
||||
private static final DbType JSON_BLOB_PLACEHOLDER = new DbType("jsonBlobPlaceholder");
|
||||
private static final DbType JSON_VARCHAR_PLACEHOLDER = new DbType("jsonVarcharPlaceholder");
|
||||
|
||||
/**
|
||||
* A map to reverse lookup the type by name.
|
||||
* <p>
|
||||
* Used when converting from logical types to platform types which we
|
||||
* want to do with 2 phase DDL generation.
|
||||
*/
|
||||
static Map<String, Integer> lookup = new HashMap<String, Integer>();
|
||||
|
||||
static {
|
||||
lookup.put("BOOLEAN", Types.BOOLEAN);
|
||||
lookup.put("BIT", Types.BIT);
|
||||
lookup.put("INTEGER", Types.INTEGER);
|
||||
lookup.put("BIGINT", Types.BIGINT);
|
||||
lookup.put("REAL", Types.REAL);
|
||||
// Float is most common REAL mapping to have that as well
|
||||
lookup.put("FLOAT", Types.REAL);
|
||||
|
||||
lookup.put("DOUBLE", Types.DOUBLE);
|
||||
lookup.put("SMALLINT", Types.SMALLINT);
|
||||
lookup.put("TINYINT", Types.TINYINT);
|
||||
lookup.put("DECIMAL", Types.DECIMAL);
|
||||
lookup.put("VARCHAR", Types.VARCHAR);
|
||||
// VARCHAR2 - extra for Oracle specific column definition
|
||||
lookup.put("VARCHAR2", Types.VARCHAR);
|
||||
lookup.put("CHAR", Types.CHAR);
|
||||
lookup.put("BLOB", Types.BLOB);
|
||||
lookup.put("CLOB", Types.CLOB);
|
||||
|
||||
lookup.put("LONGVARBINARY", Types.LONGVARBINARY);
|
||||
lookup.put("LONGVARCHAR", Types.LONGVARCHAR);
|
||||
lookup.put("VARBINARY", Types.VARBINARY);
|
||||
lookup.put("BINARY", Types.BINARY);
|
||||
lookup.put("DATE", Types.DATE);
|
||||
lookup.put("TIME", Types.TIME);
|
||||
lookup.put("TIMESTAMP", Types.TIMESTAMP);
|
||||
|
||||
lookup.put("ARRAY", Types.ARRAY);
|
||||
lookup.put("UUID", DbType.UUID);
|
||||
|
||||
// Not standard java.sql.Types
|
||||
// logical JSON storage types
|
||||
lookup.put("JSON", DbType.JSON);
|
||||
lookup.put("JSONB", DbType.JSONB);
|
||||
lookup.put("JSONCLOB", DbType.JSONClob);
|
||||
lookup.put("JSONBLOB", DbType.JSONBlob);
|
||||
lookup.put("JSONVARCHAR", DbType.JSONVarchar);
|
||||
}
|
||||
|
||||
|
||||
private final Map<Integer, DbType> typeMap = new HashMap<Integer, DbType>();
|
||||
|
||||
/**
|
||||
* Return the DbTypeMap with standard (not platform specific) types.
|
||||
*
|
||||
* This has some extended JSON types (JSON, JSONB, JSONVarchar, JSONClob, JSONBlob).
|
||||
* These types get translated to specific database platform types during DDL generation.
|
||||
*/
|
||||
public static DbTypeMap logicalTypes() {
|
||||
return new DbTypeMap(true);
|
||||
}
|
||||
|
||||
public DbTypeMap() {
|
||||
loadDefaults(false);
|
||||
}
|
||||
|
||||
private DbTypeMap(boolean logicalTypes) {
|
||||
loadDefaults(logicalTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the standard types. These can be overridden by DB specific platform.
|
||||
*/
|
||||
private void loadDefaults(boolean logicalTypes) {
|
||||
|
||||
put(Types.BOOLEAN, new DbType("boolean"));
|
||||
put(Types.BIT, new DbType("bit"));
|
||||
|
||||
put(Types.INTEGER, new DbType("integer"));
|
||||
put(Types.BIGINT, new DbType("bigint"));
|
||||
put(Types.REAL, new DbType("float"));
|
||||
put(Types.DOUBLE, new DbType("double"));
|
||||
put(Types.SMALLINT, new DbType("smallint"));
|
||||
put(Types.TINYINT, new DbType("tinyint"));
|
||||
put(Types.DECIMAL, new DbType("decimal", 38));
|
||||
|
||||
put(Types.VARCHAR, new DbType("varchar", 255));
|
||||
put(Types.CHAR, new DbType("char", 1));
|
||||
|
||||
put(Types.BLOB, new DbType("blob"));
|
||||
put(Types.CLOB, new DbType("clob"));
|
||||
|
||||
// DB native UUID support (H2 and Postgres)
|
||||
put(DbType.UUID, new DbType("uuid"));
|
||||
put(Types.ARRAY, new DbType("array"));
|
||||
|
||||
if (logicalTypes) {
|
||||
// keep it logical for 2 layer DDL generation
|
||||
put(DbType.HSTORE, new DbType("hstore", false));
|
||||
put(DbType.JSON, new DbType("json", false));
|
||||
put(DbType.JSONB, new DbType("jsonb", false));
|
||||
put(DbType.JSONClob, new DbType("jsonclob"));
|
||||
put(DbType.JSONBlob, new DbType("jsonblob"));
|
||||
put(DbType.JSONVarchar, new DbType("jsonvarchar", 1000));
|
||||
|
||||
} else {
|
||||
put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON
|
||||
put(DbType.JSONB, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSONB
|
||||
put(DbType.JSONClob, JSON_CLOB_PLACEHOLDER);
|
||||
put(DbType.JSONBlob, JSON_BLOB_PLACEHOLDER);
|
||||
put(DbType.JSONVarchar, JSON_VARCHAR_PLACEHOLDER);
|
||||
}
|
||||
|
||||
put(Types.LONGVARBINARY, new DbType("longvarbinary"));
|
||||
put(Types.LONGVARCHAR, new DbType("lonvarchar"));
|
||||
put(Types.VARBINARY, new DbType("varbinary", 255));
|
||||
put(Types.BINARY, new DbType("binary", 255));
|
||||
|
||||
put(Types.DATE, new DbType("date"));
|
||||
put(Types.TIME, new DbType("time"));
|
||||
put(Types.TIMESTAMP, new DbType("timestamp"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the platform specific DbType given the standard sql type name.
|
||||
*/
|
||||
public DbType lookup(String name, boolean withScale) {
|
||||
name = name.trim().toUpperCase();
|
||||
Integer typeKey = lookup.get(name);
|
||||
if (typeKey == null) {
|
||||
throw new IllegalArgumentException("Unknown type [" + name + "] - not standard sql type");
|
||||
}
|
||||
// handle JSON types mapped to clob, blob and varchar
|
||||
switch (typeKey) {
|
||||
case DbType.JSONBlob:
|
||||
return get(Types.BLOB);
|
||||
case DbType.JSONClob:
|
||||
return get(Types.CLOB);
|
||||
case DbType.JSONVarchar:
|
||||
return get(Types.VARCHAR);
|
||||
case DbType.JSON:
|
||||
return getJsonType(DbType.JSON, withScale);
|
||||
case DbType.JSONB:
|
||||
return getJsonType(DbType.JSONB, withScale);
|
||||
default:
|
||||
return get(typeKey);
|
||||
}
|
||||
}
|
||||
|
||||
private DbType getJsonType(int type, boolean withScale) {
|
||||
DbType dbType = get(type);
|
||||
if (dbType == JSON_CLOB_PLACEHOLDER) {
|
||||
// if we have scale that implies this maps to varchar
|
||||
return withScale ? get(Types.VARCHAR) : get(Types.CLOB);
|
||||
}
|
||||
if (dbType == JSON_BLOB_PLACEHOLDER) {
|
||||
return get(Types.BLOB);
|
||||
}
|
||||
if (dbType == JSON_VARCHAR_PLACEHOLDER) {
|
||||
return get(Types.VARCHAR);
|
||||
}
|
||||
// Postgres has specific type
|
||||
return get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the type for a given JDBC type.
|
||||
*/
|
||||
public void put(int jdbcType, DbType dbType) {
|
||||
typeMap.put(jdbcType, dbType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for a given jdbc type.
|
||||
*/
|
||||
public DbType get(int jdbcType) {
|
||||
return typeMap.get(jdbcType);
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,8 @@ package com.avaje.ebean.config.dbplatform;
|
||||
*/
|
||||
public abstract class DbViewHistorySupport implements DbHistorySupport {
|
||||
|
||||
/**
|
||||
* Return false for view based implementations where we append extra 'as of' predicates to the end.
|
||||
*/
|
||||
@Override
|
||||
public boolean isBindWithFromClause() {
|
||||
public boolean isStandardsBased() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Integer codes for the extra types beyond java.sql.Types.
|
||||
*/
|
||||
public interface ExtraDbTypes {
|
||||
|
||||
/**
|
||||
* DB native UUID type (H2 and Postgres).
|
||||
*/
|
||||
int UUID = 5010;
|
||||
|
||||
/**
|
||||
* Type to map Map content to Postgres HSTORE.
|
||||
*/
|
||||
int HSTORE = 5000;
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Clob or Postgres JSON type.
|
||||
*/
|
||||
int JSON = 5001;
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Clob or Postgres JSONB type.
|
||||
*/
|
||||
int JSONB = 5002;
|
||||
|
||||
/**
|
||||
* Type to map JSON content to VARCHAR.
|
||||
*/
|
||||
int JSONVarchar = 5003;
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Clob.
|
||||
*/
|
||||
int JSONClob = 5004;
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Blob.
|
||||
*/
|
||||
int JSONBlob = 5005;
|
||||
|
||||
/**
|
||||
* Geo Point
|
||||
*/
|
||||
int POINT = 6000;
|
||||
|
||||
/**
|
||||
* Geo Polygon
|
||||
*/
|
||||
int POLYGON = 6001;
|
||||
|
||||
/**
|
||||
* Geo Point
|
||||
*/
|
||||
int LINESTRING = 6002;
|
||||
|
||||
/**
|
||||
* Geo MultiPolygon
|
||||
*/
|
||||
int MULTIPOINT = 6005;
|
||||
|
||||
/**
|
||||
* Geo MultiPolygon
|
||||
*/
|
||||
int MULTIPOLYGON = 6006;
|
||||
|
||||
/**
|
||||
* Geo MultiPolygon
|
||||
*/
|
||||
int MULTILINESTRING = 6007;
|
||||
|
||||
}
|
||||
@@ -9,9 +9,7 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* H2 database trigger used to populate history tables to support the @History feature.
|
||||
@@ -54,7 +52,6 @@ public class H2HistoryTrigger implements Trigger {
|
||||
insertSql.append("insert into ").append(tableName).append(HISTORY_SUFFIX).append(" (");
|
||||
|
||||
int count = 0;
|
||||
List<String> columns = new ArrayList<String>();
|
||||
while (rs.next()) {
|
||||
if (++count > 1) {
|
||||
insertSql.append(",");
|
||||
@@ -66,7 +63,6 @@ public class H2HistoryTrigger implements Trigger {
|
||||
this.effectEndPosition = count - 1;
|
||||
}
|
||||
insertSql.append(columnName);
|
||||
columns.add(columnName);
|
||||
}
|
||||
insertSql.append(") values (");
|
||||
for (int i = 0; i < count; i++) {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.H2Ddl;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* H2 specific platform.
|
||||
@@ -19,9 +21,7 @@ public class H2Platform extends DatabasePlatform {
|
||||
this.nativeUuidType = true;
|
||||
this.dbDefaultValue.setNow("now()");
|
||||
|
||||
// only support getGeneratedKeys with non-batch JDBC
|
||||
// so generally use SEQUENCE instead of IDENTITY for H2
|
||||
this.dbIdentity.setIdType(IdType.SEQUENCE);
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
@@ -34,6 +34,18 @@ public class H2Platform extends DatabasePlatform {
|
||||
// so no changes to dbTypeMap required
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(ServerConfig serverConfig) {
|
||||
super.configure(serverConfig);
|
||||
Properties properties = serverConfig.getProperties();
|
||||
if (properties != null) {
|
||||
String idType = properties.getProperty("ebean.h2.idtype");
|
||||
if (idType != null) {
|
||||
this.dbIdentity.setIdType(IdType.valueOf(idType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a H2 specific sequence IdGenerator that supports batch fetching
|
||||
* sequence values.
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.HsqldbDdl;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* H2 specific platform.
|
||||
@@ -22,7 +21,7 @@ public class HsqldbPlatform extends DatabasePlatform {
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.sql.Types;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
/**
|
||||
* Microsoft SQL Server 2000 specific platform.
|
||||
@@ -18,6 +18,7 @@ public class MsSqlServer2000Platform extends DatabasePlatform {
|
||||
public MsSqlServer2000Platform() {
|
||||
super();
|
||||
this.name = "mssqlserver2000";
|
||||
this.persistBatchOnCascade = PersistBatch.NONE;
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
this.dbIdentity.setSelectLastInsertedIdTemplate("select @@IDENTITY as X");
|
||||
@@ -26,22 +27,22 @@ public class MsSqlServer2000Platform extends DatabasePlatform {
|
||||
this.openQuote = "[";
|
||||
this.closeQuote = "]";
|
||||
|
||||
dbTypeMap.put(Types.BOOLEAN, new DbType("bit default 0"));
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0"));
|
||||
|
||||
dbTypeMap.put(Types.BIGINT, new DbType("numeric", 19));
|
||||
dbTypeMap.put(Types.REAL, new DbType("float(16)"));
|
||||
dbTypeMap.put(Types.DOUBLE, new DbType("float(32)"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("numeric", 28));
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("numeric", 19));
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)"));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float(32)"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28));
|
||||
|
||||
dbTypeMap.put(Types.BLOB, new DbType("image"));
|
||||
dbTypeMap.put(Types.CLOB, new DbType("text"));
|
||||
dbTypeMap.put(Types.LONGVARBINARY, new DbType("image"));
|
||||
dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
|
||||
dbTypeMap.put(DbType.BLOB, new DbPlatformType("image"));
|
||||
dbTypeMap.put(DbType.CLOB, new DbPlatformType("text"));
|
||||
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("image"));
|
||||
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("text"));
|
||||
|
||||
dbTypeMap.put(Types.DATE, new DbType("datetime"));
|
||||
dbTypeMap.put(Types.TIME, new DbType("datetime"));
|
||||
dbTypeMap.put(Types.TIMESTAMP, new DbType("datetime"));
|
||||
dbTypeMap.put(DbType.DATE, new DbPlatformType("datetime"));
|
||||
dbTypeMap.put(DbType.TIME, new DbPlatformType("datetime"));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.MsSqlServerDdl;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Microsoft SQL Server 2005 specific platform.
|
||||
* <p>
|
||||
@@ -21,7 +20,7 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
|
||||
this.name = "mssqlserver2005";
|
||||
// effectively disable persistBatchOnCascade mode for SQL Server
|
||||
// due to lack of support for getGeneratedKeys in batch mode
|
||||
this.disallowBatchOnCascade = true;
|
||||
this.persistBatchOnCascade = PersistBatch.NONE;
|
||||
this.idInExpandedForm = true;
|
||||
this.selectCountWithAlias = true;
|
||||
this.sqlLimiter = new MsSqlServer2005SqlLimiter();
|
||||
@@ -33,23 +32,23 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
|
||||
this.openQuote = "[";
|
||||
this.closeQuote = "]";
|
||||
|
||||
dbTypeMap.put(Types.BOOLEAN, new DbType("bit default 0"));
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0"));
|
||||
|
||||
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
|
||||
dbTypeMap.put(Types.BIGINT, new DbType("numeric", 19));
|
||||
dbTypeMap.put(Types.REAL, new DbType("float(16)"));
|
||||
dbTypeMap.put(Types.DOUBLE, new DbType("float(32)"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("numeric", 28));
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("numeric", 19));
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)"));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float(32)"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28));
|
||||
|
||||
dbTypeMap.put(Types.BLOB, new DbType("image"));
|
||||
dbTypeMap.put(Types.CLOB, new DbType("text"));
|
||||
dbTypeMap.put(Types.LONGVARBINARY, new DbType("image"));
|
||||
dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
|
||||
dbTypeMap.put(DbType.BLOB, new DbPlatformType("image"));
|
||||
dbTypeMap.put(DbType.CLOB, new DbPlatformType("text"));
|
||||
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("image"));
|
||||
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("text"));
|
||||
|
||||
dbTypeMap.put(Types.DATE, new DbType("date"));
|
||||
dbTypeMap.put(Types.TIME, new DbType("time"));
|
||||
dbTypeMap.put(Types.TIMESTAMP, new DbType("datetime2"));
|
||||
dbTypeMap.put(DbType.DATE, new DbPlatformType("date"));
|
||||
dbTypeMap.put(DbType.TIME, new DbPlatformType("time"));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime2"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ package com.avaje.ebean.config.dbplatform;
|
||||
* If no deployment length is defined longblob is used.
|
||||
* </p>
|
||||
*/
|
||||
public class MySqlBlob extends DbType {
|
||||
public class MySqlBlob extends DbPlatformType {
|
||||
|
||||
private static final int POWER_2_16 = 65536;
|
||||
private static final int POWER_2_24 = 16777216;
|
||||
|
||||
@@ -7,7 +7,7 @@ package com.avaje.ebean.config.dbplatform;
|
||||
* If no deployment length is defined longtext is used.
|
||||
* </p>
|
||||
*/
|
||||
public class MySqlClob extends DbType {
|
||||
public class MySqlClob extends DbPlatformType {
|
||||
|
||||
private static final int POWER_2_16 = 65536;
|
||||
private static final int POWER_2_24 = 16777216;
|
||||
|
||||
@@ -39,13 +39,13 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
this.forwardOnlyHintOnFindIterate = true;
|
||||
this.booleanDbType = Types.BIT;
|
||||
|
||||
dbTypeMap.put(Types.BIT, new DbType("tinyint(1) default 0"));
|
||||
dbTypeMap.put(Types.BOOLEAN, new DbType("tinyint(1) default 0"));
|
||||
dbTypeMap.put(Types.TIMESTAMP, new DbType("datetime(6)"));
|
||||
dbTypeMap.put(Types.CLOB, new MySqlClob());
|
||||
dbTypeMap.put(Types.BLOB, new MySqlBlob());
|
||||
dbTypeMap.put(Types.BINARY, new DbType("binary", 255));
|
||||
dbTypeMap.put(Types.VARBINARY, new DbType("varbinary", 255));
|
||||
dbTypeMap.put(DbType.BIT, new DbPlatformType("tinyint(1) default 0"));
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("tinyint(1) default 0"));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime(6)"));
|
||||
dbTypeMap.put(DbType.CLOB, new MySqlClob());
|
||||
dbTypeMap.put(DbType.BLOB, new MySqlBlob());
|
||||
dbTypeMap.put(DbType.BINARY, new DbPlatformType("binary", 255));
|
||||
dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,7 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
this.maxConstraintNameLength = 30;
|
||||
this.dbEncrypt = new OracleDbEncrypt();
|
||||
this.sqlLimiter = new RownumSqlLimiter();
|
||||
this.basicSqlLimiter = new BasicSqlAnsiLimiter();
|
||||
this.platformDdl = new Oracle10Ddl(this);
|
||||
this.historySupport = new OracleDbHistorySupport();
|
||||
|
||||
@@ -33,24 +34,24 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
this.closeQuote = "\"";
|
||||
|
||||
booleanDbType = Types.INTEGER;
|
||||
dbTypeMap.put(Types.BOOLEAN, new DbType("number(1) default 0"));
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("number(1) default 0"));
|
||||
|
||||
dbTypeMap.put(Types.INTEGER, new DbType("number", 10));
|
||||
dbTypeMap.put(Types.BIGINT, new DbType("number", 19));
|
||||
dbTypeMap.put(Types.REAL, new DbType("number", 19, 4));
|
||||
dbTypeMap.put(Types.DOUBLE, new DbType("number", 19, 4));
|
||||
dbTypeMap.put(Types.SMALLINT, new DbType("number", 5));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("number", 3));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("number", 38));
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("number", 10));
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("number", 19));
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("number", 19, 4));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("number", 19, 4));
|
||||
dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("number", 5));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("number", 3));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("number", 38));
|
||||
|
||||
dbTypeMap.put(Types.VARCHAR, new DbType("varchar2", 255));
|
||||
dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("varchar2", 255));
|
||||
|
||||
dbTypeMap.put(Types.LONGVARBINARY, new DbType("blob"));
|
||||
dbTypeMap.put(Types.LONGVARCHAR, new DbType("clob"));
|
||||
dbTypeMap.put(Types.VARBINARY, new DbType("raw", 255));
|
||||
dbTypeMap.put(Types.BINARY, new DbType("raw", 255));
|
||||
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("blob"));
|
||||
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("clob"));
|
||||
dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("raw", 255));
|
||||
dbTypeMap.put(DbType.BINARY, new DbPlatformType("raw", 255));
|
||||
|
||||
dbTypeMap.put(Types.TIME, new DbType("timestamp"));
|
||||
dbTypeMap.put(DbType.TIME, new DbPlatformType("timestamp"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -41,36 +41,53 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
this.openQuote = "\"";
|
||||
this.closeQuote = "\"";
|
||||
|
||||
DbType dbTypeText = new DbType("text");
|
||||
DbType dbBytea = new DbType("bytea", false);
|
||||
DbPlatformType dbTypeText = new DbPlatformType("text");
|
||||
DbPlatformType dbBytea = new DbPlatformType("bytea", false);
|
||||
|
||||
dbTypeMap.put(DbType.HSTORE, new DbType("hstore", false));
|
||||
dbTypeMap.put(DbType.JSON, new DbType("json", false));
|
||||
dbTypeMap.put(DbType.JSONB, new DbType("jsonb", false));
|
||||
dbTypeMap.put(DbType.HSTORE, new DbPlatformType("hstore", false));
|
||||
dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false));
|
||||
dbTypeMap.put(DbType.JSONB, new DbPlatformType("jsonb", false));
|
||||
|
||||
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
|
||||
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(DbType.INTEGER, new DbPlatformType("integer", false));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 38));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("timestamptz"));
|
||||
|
||||
dbTypeMap.put(Types.BINARY, dbBytea);
|
||||
dbTypeMap.put(Types.VARBINARY, dbBytea);
|
||||
dbTypeMap.put(DbType.BINARY, dbBytea);
|
||||
dbTypeMap.put(DbType.VARBINARY, dbBytea);
|
||||
|
||||
dbTypeMap.put(Types.BLOB, dbBytea);
|
||||
dbTypeMap.put(Types.CLOB, dbTypeText);
|
||||
dbTypeMap.put(Types.LONGVARBINARY, dbBytea);
|
||||
dbTypeMap.put(Types.LONGVARCHAR, dbTypeText);
|
||||
dbTypeMap.put(DbType.BLOB, dbBytea);
|
||||
dbTypeMap.put(DbType.CLOB, dbTypeText);
|
||||
dbTypeMap.put(DbType.LONGVARBINARY, dbBytea);
|
||||
dbTypeMap.put(DbType.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));
|
||||
public void configure(ServerConfig serverConfig) {
|
||||
super.configure(serverConfig);
|
||||
Properties properties = serverConfig.getProperties();
|
||||
if (properties != null) {
|
||||
String tsType = properties.getProperty("ebean.postgres.timestamp");
|
||||
if (tsType != null) {
|
||||
// set timestamp type to "timestamp" without time zone
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType(tsType));
|
||||
}
|
||||
}
|
||||
addGeoTypes(serverConfig.getGeometrySRID());
|
||||
}
|
||||
|
||||
private void addGeoTypes(int srid) {
|
||||
dbTypeMap.put(DbType.POINT, geoType("point",srid));
|
||||
dbTypeMap.put(DbType.POLYGON, geoType("polygon",srid));
|
||||
dbTypeMap.put(DbType.LINESTRING, geoType("linestring",srid));
|
||||
dbTypeMap.put(DbType.MULTIPOINT, geoType("multipoint",srid));
|
||||
dbTypeMap.put(DbType.MULTILINESTRING, geoType("multilinestring",srid));
|
||||
dbTypeMap.put(DbType.MULTIPOLYGON, geoType("multipolygon",srid));
|
||||
}
|
||||
|
||||
private DbPlatformType geoType(String type, int srid) {
|
||||
return new DbPlatformType("geometry("+type+","+srid+")");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,10 +18,10 @@ public class SQLitePlatform extends DatabasePlatform {
|
||||
|
||||
this.booleanDbType = Types.INTEGER;
|
||||
|
||||
dbTypeMap.put(Types.BIT, new DbType("int default 0"));
|
||||
dbTypeMap.put(Types.BOOLEAN, new DbType("int default 0"));
|
||||
dbTypeMap.put(Types.BIGINT, new DbType("integer"));
|
||||
dbTypeMap.put(Types.SMALLINT, new DbType("integer"));
|
||||
dbTypeMap.put(DbType.BIT, new DbPlatformType("int default 0"));
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("int default 0"));
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("integer"));
|
||||
dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("integer"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
public Object nextId(Transaction t) {
|
||||
synchronized (monitor) {
|
||||
|
||||
if (idList.size() == 0) {
|
||||
if (idList.isEmpty()) {
|
||||
loadMoreIds(batchSize, t);
|
||||
}
|
||||
Long nextId = idList.remove(0);
|
||||
@@ -193,7 +193,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
while (rset.next()) {
|
||||
newIds.add(rset.getLong(1));
|
||||
}
|
||||
if (newIds.size() == 0) {
|
||||
if (newIds.isEmpty()) {
|
||||
throw new PersistenceException("Always expecting more than 1 row from " + sql);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Use top xx and start at xx to limit sql results. Based on
|
||||
* MsSqlServer2005SqlLimiter and LimitOffsetSqlLimiter
|
||||
* Use top xx and start at xx to limit sql results.
|
||||
*/
|
||||
public class SqlAnywhereLimiter implements SqlLimiter {
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Sybase SQL Anywhere specific platform.
|
||||
* <p>
|
||||
@@ -23,17 +21,17 @@ public class SqlAnywherePlatform extends DatabasePlatform {
|
||||
this.dbIdentity.setSelectLastInsertedIdTemplate("select @@IDENTITY as X");
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
dbTypeMap.put(Types.BOOLEAN, new DbType("bit default 0"));
|
||||
dbTypeMap.put(Types.BIGINT, new DbType("numeric", 19));
|
||||
dbTypeMap.put(Types.REAL, new DbType("float(16)"));
|
||||
dbTypeMap.put(Types.DOUBLE, new DbType("float(32)"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("numeric", 28));
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0"));
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("numeric", 19));
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)"));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float(32)"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28));
|
||||
|
||||
dbTypeMap.put(Types.BLOB, new DbType("binary(4500)"));
|
||||
dbTypeMap.put(Types.CLOB, new DbType("long varchar"));
|
||||
dbTypeMap.put(Types.LONGVARBINARY, new DbType("long binary"));
|
||||
dbTypeMap.put(Types.LONGVARCHAR, new DbType("long varchar"));
|
||||
dbTypeMap.put(DbType.BLOB, new DbPlatformType("binary(4500)"));
|
||||
dbTypeMap.put(DbType.CLOB, new DbPlatformType("long varchar"));
|
||||
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("long binary"));
|
||||
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("long varchar"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.avaje.ebean.config.DbMigrationConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DB2Platform;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformName;
|
||||
import com.avaje.ebean.config.Platform;
|
||||
import com.avaje.ebean.config.dbplatform.H2Platform;
|
||||
import com.avaje.ebean.config.dbplatform.MsSqlServer2005Platform;
|
||||
import com.avaje.ebean.config.dbplatform.MySqlPlatform;
|
||||
@@ -139,7 +139,7 @@ public class DbMigration {
|
||||
* If not set this defaults to the platform of the default server.
|
||||
* </p>
|
||||
*/
|
||||
public void setPlatform(DbPlatformName platform) {
|
||||
public void setPlatform(Platform platform) {
|
||||
setPlatform(getPlatform(platform));
|
||||
}
|
||||
|
||||
@@ -163,10 +163,7 @@ public class DbMigration {
|
||||
* from the migration (e.g. generate migration sql for MySql, Postgres and Oracle).
|
||||
* </p>
|
||||
*/
|
||||
public void addPlatform(DbPlatformName platform, String prefix) {
|
||||
if (!prefix.endsWith("-")) {
|
||||
prefix += "-";
|
||||
}
|
||||
public void addPlatform(Platform platform, String prefix) {
|
||||
platforms.add(new Pair(getPlatform(platform), prefix));
|
||||
}
|
||||
|
||||
@@ -204,13 +201,20 @@ public class DbMigration {
|
||||
|
||||
// use this flag to stop other plugins like full DDL generation
|
||||
if (!online) {
|
||||
DbOffline.setRunningMigration();
|
||||
DbOffline.setGenerateMigration();
|
||||
if (databasePlatform == null && !platforms.isEmpty()) {
|
||||
// for multiple platform generation set the general platform
|
||||
// to H2 so that it runs offline without DB connection
|
||||
setPlatform(platforms.get(0).platform);
|
||||
}
|
||||
}
|
||||
setDefaults();
|
||||
try {
|
||||
Request request = createRequest();
|
||||
|
||||
generateExtraDdl(request);
|
||||
if (platforms.isEmpty()) {
|
||||
generateExtraDdl(request.migrationDir, databasePlatform);
|
||||
}
|
||||
|
||||
String pendingVersion = generatePendingDrop();
|
||||
if (pendingVersion != null) {
|
||||
@@ -234,15 +238,15 @@ public class DbMigration {
|
||||
* migration runner.
|
||||
* </p>
|
||||
*/
|
||||
private void generateExtraDdl(Request request) throws IOException {
|
||||
private void generateExtraDdl(File migrationDir, DatabasePlatform dbPlatform) throws IOException {
|
||||
|
||||
if (databasePlatform != null) {
|
||||
if (dbPlatform != 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);
|
||||
if (ExtraDdlXmlReader.matchPlatform(dbPlatform.getName(), script.getPlatforms())) {
|
||||
writeExtraDdl(migrationDir, script);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,13 +256,13 @@ public class DbMigration {
|
||||
/**
|
||||
* Write (or override) the "repeatable" migration script.
|
||||
*/
|
||||
private void writeExtraDdl(Request request, DdlScript script) throws IOException {
|
||||
private void writeExtraDdl(File migrationDir, DdlScript script) throws IOException {
|
||||
|
||||
String fullName = repeatableMigrationName(script.getName());
|
||||
|
||||
logger.info("writing repeatable script {}", fullName);
|
||||
|
||||
File file = new File(request.migrationDir, fullName);
|
||||
File file = new File(migrationDir, fullName);
|
||||
FileWriter writer = new FileWriter(file);
|
||||
writer.write(script.getValue());
|
||||
writer.flush();
|
||||
@@ -363,14 +367,16 @@ public class DbMigration {
|
||||
logger.warn("migration already exists, not generating DDL");
|
||||
|
||||
} else {
|
||||
if (databasePlatform != null) {
|
||||
if (!platforms.isEmpty()) {
|
||||
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
|
||||
|
||||
} else if (databasePlatform != null) {
|
||||
// writer needs the current model to provide table/column details for
|
||||
// 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);
|
||||
}
|
||||
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,7 +432,10 @@ public class DbMigration {
|
||||
for (Pair pair : platforms) {
|
||||
DdlWrite platformBuffer = new DdlWrite(new MConfiguration(), currentModel.read());
|
||||
PlatformDdlWriter platformWriter = createDdlWriter(pair);
|
||||
platformWriter.processMigration(dbMigration, platformBuffer, writePath, fullVersion);
|
||||
File subPath = platformWriter.subPath(writePath, pair.prefix);
|
||||
platformWriter.processMigration(dbMigration, platformBuffer, subPath, fullVersion);
|
||||
|
||||
generateExtraDdl(subPath, pair.platform);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,7 +515,7 @@ public class DbMigration {
|
||||
/**
|
||||
* Return the DatabasePlatform given the platform key.
|
||||
*/
|
||||
protected DatabasePlatform getPlatform(DbPlatformName platform) {
|
||||
protected DatabasePlatform getPlatform(Platform platform) {
|
||||
switch (platform) {
|
||||
case H2:
|
||||
return new H2Platform();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformName;
|
||||
import com.avaje.ebean.config.Platform;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -14,12 +14,12 @@ public class DbOffline {
|
||||
|
||||
private static final String KEY = "ebean.dboffline";
|
||||
|
||||
private static boolean runningMigration;
|
||||
private static boolean generateMigration;
|
||||
|
||||
/**
|
||||
* Set the platform to use when creating the next EbeanServer instance.
|
||||
*/
|
||||
public static void setPlatform(DbPlatformName dbPlatform) {
|
||||
public static void setPlatform(Platform dbPlatform) {
|
||||
System.setProperty(KEY, dbPlatform.name());
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class DbOffline {
|
||||
* Bring up the next EbeanServer instance using the H2 platform.
|
||||
*/
|
||||
public static void asH2() {
|
||||
setPlatform(DbPlatformName.H2);
|
||||
setPlatform(Platform.H2);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,23 +55,23 @@ public class DbOffline {
|
||||
* Return true if the migration is running. This typically means don't run the
|
||||
* plugins like full DDL generation.
|
||||
*/
|
||||
public static boolean isRunningMigration() {
|
||||
return runningMigration;
|
||||
public static boolean isGenerateMigration() {
|
||||
return generateMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the migration is running is order to stop other plugins
|
||||
* like the full DDL generation from executing.
|
||||
*/
|
||||
public static void setRunningMigration() {
|
||||
runningMigration = true;
|
||||
public static void setGenerateMigration() {
|
||||
generateMigration = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the offline platform and runningMigration flag.
|
||||
*/
|
||||
public static void reset() {
|
||||
runningMigration = false;
|
||||
generateMigration = false;
|
||||
System.clearProperty(KEY);
|
||||
logger.debug("reset");
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ 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 org.avaje.dbmigration.ddl.DdlRunner;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.File;
|
||||
@@ -95,7 +96,13 @@ public class DdlGenerator {
|
||||
Transaction transaction = server.createTransaction();
|
||||
Connection connection = transaction.getConnection();
|
||||
try {
|
||||
if (expectErrors) {
|
||||
connection.setAutoCommit(true);
|
||||
}
|
||||
int count = runner.runAll(content, connection);
|
||||
if (expectErrors) {
|
||||
connection.setAutoCommit(false);
|
||||
}
|
||||
transaction.commit();
|
||||
return count;
|
||||
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Parses string content into separate SQL/DDL statements.
|
||||
*/
|
||||
public class DdlParser {
|
||||
|
||||
/**
|
||||
* Break up the sql in reader into a list of statements using the semi-colon and $$ delimiters;
|
||||
*/
|
||||
public List<String> parse(StringReader reader) {
|
||||
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(reader);
|
||||
StatementsSeparator statements = new StatementsSeparator();
|
||||
|
||||
String s;
|
||||
while ((s = br.readLine()) != null) {
|
||||
s = s.trim();
|
||||
statements.nextLine(s);
|
||||
}
|
||||
|
||||
return statements.statements;
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Local utility used to detect the end of statements / separate statements.
|
||||
* This is often just the semicolon character but for trigger/procedures this
|
||||
* detects the $$ demarcation used in the history DDL generation for MySql and
|
||||
* Postgres.
|
||||
*/
|
||||
static class StatementsSeparator {
|
||||
|
||||
ArrayList<String> statements = new ArrayList<String>();
|
||||
|
||||
boolean trimDelimiter;
|
||||
|
||||
boolean inDbProcedure;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
void lineContainsDollars(String line) {
|
||||
if (inDbProcedure) {
|
||||
if (trimDelimiter) {
|
||||
line = line.replace("$$","");
|
||||
}
|
||||
endOfStatement(line);
|
||||
} else {
|
||||
// MySql style delimiter needs to be trimmed/removed
|
||||
trimDelimiter = line.equals("delimiter $$");
|
||||
if (!trimDelimiter) {
|
||||
sb.append(line).append(" ");
|
||||
}
|
||||
}
|
||||
inDbProcedure = !inDbProcedure;
|
||||
}
|
||||
|
||||
void endOfStatement(String line) {
|
||||
// end of Db procedure
|
||||
sb.append(line);
|
||||
statements.add(sb.toString().trim());
|
||||
sb = new StringBuilder();
|
||||
}
|
||||
|
||||
void nextLine(String line) {
|
||||
|
||||
if (line.contains("$$")) {
|
||||
lineContainsDollars(line);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sb.length() == 0 && (line.isEmpty() || line.startsWith("--"))) {
|
||||
// ignore leading empty lines and sql comments
|
||||
return;
|
||||
}
|
||||
|
||||
if (inDbProcedure) {
|
||||
sb.append(line).append(" ");
|
||||
return;
|
||||
}
|
||||
|
||||
int semiPos = line.indexOf(';');
|
||||
if (semiPos == -1) {
|
||||
sb.append(line).append(" ");
|
||||
|
||||
} else if (semiPos == line.length() - 1) {
|
||||
// semicolon at end of line
|
||||
endOfStatement(line);
|
||||
|
||||
} else {
|
||||
// semicolon in middle of line
|
||||
String preSemi = line.substring(0, semiPos);
|
||||
endOfStatement(preSemi);
|
||||
sb.append(line.substring(semiPos + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Runs DDL scripts.
|
||||
*/
|
||||
public class DdlRunner {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(DdlRunner.class);
|
||||
|
||||
private DdlParser ddlParser = new DdlParser();
|
||||
|
||||
private final String scriptName;
|
||||
|
||||
private final boolean expectErrors;
|
||||
|
||||
/**
|
||||
* Construct with a script name (for logging) and flag indicating if errors are expected.
|
||||
*/
|
||||
public DdlRunner(boolean expectErrors, String scriptName) {
|
||||
this.expectErrors = expectErrors;
|
||||
this.scriptName = scriptName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the content into sql statements and execute them in a transaction.
|
||||
*/
|
||||
public int runAll(String content, Connection connection) throws SQLException {
|
||||
|
||||
List<String> statements = ddlParser.parse(new StringReader(content));
|
||||
return runStatements(statements, connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all the statements in a single transaction.
|
||||
*/
|
||||
private int runStatements(List<String> statements, Connection connection) throws SQLException {
|
||||
|
||||
List<String> noDuplicates = new ArrayList<String>();
|
||||
|
||||
for (String statement : statements) {
|
||||
if (!noDuplicates.contains(statement)) {
|
||||
noDuplicates.add(statement);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Executing {} - {} statements", scriptName, noDuplicates.size());
|
||||
|
||||
for (int i = 0; i < noDuplicates.size(); i++) {
|
||||
String xOfy = (i + 1) + " of " + noDuplicates.size();
|
||||
runStatement(expectErrors, xOfy, noDuplicates.get(i), connection);
|
||||
}
|
||||
|
||||
return noDuplicates.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the statement.
|
||||
*/
|
||||
private void runStatement(boolean expectErrors, String oneOf, String stmt, Connection c) throws SQLException {
|
||||
|
||||
PreparedStatement pstmt = null;
|
||||
try {
|
||||
|
||||
// trim and remove trailing ; or /
|
||||
stmt = stmt.trim();
|
||||
if (stmt.endsWith(";")) {
|
||||
stmt = stmt.substring(0, stmt.length() - 1);
|
||||
} else if (stmt.endsWith("/")) {
|
||||
stmt = stmt.substring(0, stmt.length() - 1);
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("executing " + oneOf + " " + getSummary(stmt));
|
||||
}
|
||||
|
||||
pstmt = c.prepareStatement(stmt);
|
||||
pstmt.execute();
|
||||
|
||||
} 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 SQLException(msg, e);
|
||||
}
|
||||
|
||||
} finally {
|
||||
if (pstmt != null) {
|
||||
try {
|
||||
pstmt.close();
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error closing pstmt", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getSummary(String s) {
|
||||
if (s.length() > 80) {
|
||||
return s.substring(0, 80).trim() + "...";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -583,6 +583,12 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
}
|
||||
|
||||
for (Column column : columns) {
|
||||
if (hasValue(column.getReferences())) {
|
||||
writeForeignKey(writer, tableName, column);
|
||||
}
|
||||
}
|
||||
|
||||
// add a bit of whitespace
|
||||
writer.apply().end();
|
||||
}
|
||||
@@ -831,9 +837,10 @@ public class BaseTableDdl implements TableDdl {
|
||||
|
||||
protected void alterTableAddColumn(DdlBuffer buffer, String tableName, Column column, boolean onHistoryTable) throws IOException {
|
||||
|
||||
String convertedType = platformDdl.convert(column.getType(), false);
|
||||
buffer.append("alter table ").append(tableName)
|
||||
.append(" add column ").append(column.getName())
|
||||
.append(" ").append(column.getType());
|
||||
.append(" ").append(convertedType);
|
||||
|
||||
if (!onHistoryTable) {
|
||||
if (isTrue(column.isNotnull())) {
|
||||
|
||||
@@ -11,6 +11,8 @@ public class Oracle10Ddl extends PlatformDdl {
|
||||
super(platform);
|
||||
this.dropTableIfExists = "drop table ";
|
||||
this.dropSequenceIfExists = "drop sequence ";
|
||||
this.dropConstraintIfExists = "drop constraint";
|
||||
this.dropIndexIfExists = "drop index ";
|
||||
this.dropTableCascade = " cascade constraints purge";
|
||||
this.foreignKeyRestrict = "";
|
||||
this.alterColumn = "modify";
|
||||
|
||||
@@ -26,6 +26,8 @@ import java.util.List;
|
||||
*/
|
||||
public class PlatformDdl {
|
||||
|
||||
protected final DatabasePlatform platform;
|
||||
|
||||
protected PlatformHistoryDdl historyDdl = new NoHistorySupportDdl();
|
||||
|
||||
/**
|
||||
@@ -98,6 +100,7 @@ public class PlatformDdl {
|
||||
protected final DbDefaultValue dbDefaultValue;
|
||||
|
||||
public PlatformDdl(DatabasePlatform platform) {
|
||||
this.platform = platform;
|
||||
this.dbIdentity = platform.getDbIdentity();
|
||||
this.dbDefaultValue = platform.getDbDefaultValue();
|
||||
this.typeConverter = new PlatformTypeConverter(platform.getDbTypeMap());
|
||||
|
||||
@@ -13,6 +13,7 @@ public class PostgresDdl extends PlatformDdl {
|
||||
this.dropTableCascade = " cascade";
|
||||
this.columnSetType = "type ";
|
||||
this.alterTableIfExists = "if exists ";
|
||||
this.columnSetNull = "drop not null";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-6
@@ -1,7 +1,7 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform.util;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformType;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformTypeMapping;
|
||||
|
||||
/**
|
||||
* Converts a logical column definition into platform specific one.
|
||||
@@ -10,12 +10,12 @@ import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
*/
|
||||
public class PlatformTypeConverter {
|
||||
|
||||
protected final DbTypeMap platformTypes;
|
||||
protected final DbPlatformTypeMapping platformTypes;
|
||||
|
||||
/**
|
||||
* Construct with the platform specific types.
|
||||
*/
|
||||
public PlatformTypeConverter(DbTypeMap platformTypes) {
|
||||
public PlatformTypeConverter(DbPlatformTypeMapping platformTypes) {
|
||||
this.platformTypes = platformTypes;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class PlatformTypeConverter {
|
||||
String suffix = close + 1 < columnDefinition.length() ? columnDefinition.substring(close + 1) : "";
|
||||
String type = columnDefinition.substring(0, open);
|
||||
try {
|
||||
DbType dbType = platformTypes.lookup(type, true);
|
||||
DbPlatformType dbType = platformTypes.lookup(type, true);
|
||||
int comma = columnDefinition.indexOf(',', open);
|
||||
if (comma > -1) {
|
||||
// scale and precision - decimal(10,4)
|
||||
@@ -73,7 +73,7 @@ public class PlatformTypeConverter {
|
||||
protected String convertNoScale(String columnDefinition) {
|
||||
|
||||
try {
|
||||
DbType dbType = platformTypes.lookup(columnDefinition, false);
|
||||
DbPlatformType dbType = platformTypes.lookup(columnDefinition, false);
|
||||
return dbType.renderType(0, 0);
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
||||
@@ -11,7 +11,6 @@ import com.avaje.ebean.dbmigration.model.visitor.VisitAllUsing;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Reads EbeanServer bean descriptors to build the current model.
|
||||
@@ -24,6 +23,8 @@ public class CurrentModel {
|
||||
|
||||
private final DbConstraintNaming.MaxLength maxLength;
|
||||
|
||||
private final boolean platformTypes;
|
||||
|
||||
private ModelContainer model;
|
||||
|
||||
private ChangeSet changeSet;
|
||||
@@ -31,32 +32,31 @@ public class CurrentModel {
|
||||
private DdlWrite write;
|
||||
|
||||
/**
|
||||
* Construct with a given EbeanServer instance.
|
||||
* Construct with a given EbeanServer instance for DDL create all generation, not migration.
|
||||
*/
|
||||
public CurrentModel(SpiEbeanServer server) {
|
||||
this(server, server.getServerConfig().getConstraintNaming());
|
||||
this(server, server.getServerConfig().getConstraintNaming(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a given EbeanServer, platformDdl and constraintNaming convention.
|
||||
* <p>
|
||||
* Note the EbeanServer is just used to read the BeanDescriptors and platformDdl supplies
|
||||
* the platform specific handling on
|
||||
* Note the EbeanServer is just used to read the BeanDescriptors and platformDdl supplies
|
||||
* the platform specific handling on
|
||||
* </p>
|
||||
*/
|
||||
public CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming) {
|
||||
this(server, constraintNaming, false);
|
||||
}
|
||||
|
||||
private CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, boolean platformTypes) {
|
||||
this.server = server;
|
||||
this.constraintNaming = constraintNaming;
|
||||
this.maxLength = maxLength(server, constraintNaming);
|
||||
this.platformTypes = platformTypes;
|
||||
}
|
||||
|
||||
public CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, int maxConstraintLength) {
|
||||
this.server = server;
|
||||
this.constraintNaming = constraintNaming;
|
||||
this.maxLength = new DefaultConstraintMaxLength(maxConstraintLength);
|
||||
}
|
||||
|
||||
private DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
|
||||
private static DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
|
||||
|
||||
if (naming.getMaxLength() != null) {
|
||||
return naming.getMaxLength();
|
||||
@@ -73,7 +73,7 @@ public class CurrentModel {
|
||||
if (model == null) {
|
||||
model = new ModelContainer();
|
||||
|
||||
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength);
|
||||
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength, platformTypes);
|
||||
ModelBuildBeanVisitor visitor = new ModelBuildBeanVisitor(context);
|
||||
VisitAllUsing visit = new VisitAllUsing(visitor, server);
|
||||
visit.visitAllBeans();
|
||||
|
||||
@@ -268,6 +268,10 @@ public class MColumn {
|
||||
return val != null && !val.isEmpty();
|
||||
}
|
||||
|
||||
private boolean hasValue(Boolean val) {
|
||||
return val != null;
|
||||
}
|
||||
|
||||
private AlterColumn getAlterColumn(String tableName, boolean tableWithHistory) {
|
||||
if (alterColumn == null) {
|
||||
alterColumn = new AlterColumn();
|
||||
@@ -396,6 +400,9 @@ public class MColumn {
|
||||
if (hasValue(alterColumn.getType())) {
|
||||
type = alterColumn.getType();
|
||||
}
|
||||
if (hasValue(alterColumn.isNotnull())) {
|
||||
notnull = alterColumn.isNotnull();
|
||||
}
|
||||
if (hasValue(alterColumn.getDefaultValue())) {
|
||||
defaultValue = alterColumn.getDefaultValue();
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ public class MTable {
|
||||
/**
|
||||
* Compound unique constraints.
|
||||
*/
|
||||
private List<MCompoundUniqueConstraint> compoundUniqueConstraints = new ArrayList<MCompoundUniqueConstraint>();
|
||||
private List<MCompoundUniqueConstraint> uniqueConstraints = new ArrayList<MCompoundUniqueConstraint>();
|
||||
|
||||
/**
|
||||
* Compound foreign keys.
|
||||
@@ -216,7 +216,7 @@ public class MTable {
|
||||
createTable.getForeignKey().add(compoundKey.createForeignKey());
|
||||
}
|
||||
|
||||
for (MCompoundUniqueConstraint constraint : compoundUniqueConstraints) {
|
||||
for (MCompoundUniqueConstraint constraint : uniqueConstraints) {
|
||||
UniqueConstraint uq = new UniqueConstraint();
|
||||
uq.setName(constraint.getName());
|
||||
String[] columns = constraint.getColumns();
|
||||
@@ -270,17 +270,15 @@ public class MTable {
|
||||
}
|
||||
|
||||
// compare existing columns (look for dropped columns)
|
||||
int columnPosition = 0;
|
||||
for (MColumn existingColumn : allColumns()) {
|
||||
MColumn newColumn = newColumnMap.get(existingColumn.getName());
|
||||
if (newColumn == null) {
|
||||
diffDropColumn(modelDiff, existingColumn, columnPosition, newTable);
|
||||
diffDropColumn(modelDiff, existingColumn);
|
||||
} else if (newColumn.isDraftOnly() && !draft) {
|
||||
// effectively a drop column (draft only column on a non-draft table)
|
||||
logger.trace("... drop column {} from table {} as now draftOnly", newColumn.getName(), name);
|
||||
diffDropColumn(modelDiff, existingColumn, columnPosition, newTable);
|
||||
diffDropColumn(modelDiff, existingColumn);
|
||||
}
|
||||
columnPosition++;
|
||||
}
|
||||
|
||||
if (addColumn != null) {
|
||||
@@ -404,8 +402,8 @@ public class MTable {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public List<MCompoundUniqueConstraint> getCompoundUniqueConstraints() {
|
||||
return compoundUniqueConstraints;
|
||||
public List<MCompoundUniqueConstraint> getUniqueConstraints() {
|
||||
return uniqueConstraints;
|
||||
}
|
||||
|
||||
public List<MCompoundForeignKey> getCompoundKeys() {
|
||||
@@ -476,21 +474,21 @@ public class MTable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a compound unique constraint.
|
||||
* Add a unique constraint.
|
||||
*/
|
||||
public void addCompoundUniqueConstraint(String[] columns, boolean oneToOne, String constraintName) {
|
||||
compoundUniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne, constraintName));
|
||||
public void addUniqueConstraint(String[] columns, boolean oneToOne, String constraintName) {
|
||||
uniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne, constraintName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a compound unique constraint.
|
||||
* Add a unique constraint.
|
||||
*/
|
||||
public void addCompoundUniqueConstraint(List<MColumn> columns, boolean oneToOne, String constraintName) {
|
||||
public void addUniqueConstraint(List<MColumn> columns, boolean oneToOne, String constraintName) {
|
||||
String[] cols = new String[columns.size()];
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
cols[i] = columns.get(i).getName();
|
||||
}
|
||||
addCompoundUniqueConstraint(cols, oneToOne, constraintName);
|
||||
addUniqueConstraint(cols, oneToOne, constraintName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -540,7 +538,7 @@ public class MTable {
|
||||
/**
|
||||
* Add a 'drop column' to the diff.
|
||||
*/
|
||||
private void diffDropColumn(ModelDiff modelDiff, MColumn existingColumn, int columnPosition, MTable newTable) {
|
||||
private void diffDropColumn(ModelDiff modelDiff, MColumn existingColumn) {
|
||||
|
||||
DropColumn dropColumn = new DropColumn();
|
||||
dropColumn.setTableName(name);
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSet;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSetType;
|
||||
import com.avaje.ebean.dbmigration.migration.Migration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
@@ -21,6 +23,8 @@ import java.util.List;
|
||||
*/
|
||||
public class PlatformDdlWriter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PlatformDdlWriter.class);
|
||||
|
||||
private final ServerConfig serverConfig;
|
||||
|
||||
private final DatabasePlatform platform;
|
||||
@@ -67,7 +71,7 @@ public class PlatformDdlWriter {
|
||||
protected void writePlatformDdl(DdlWrite write, File resourcePath, String fullVersion) throws IOException {
|
||||
|
||||
if (!write.isApplyEmpty()) {
|
||||
FileWriter applyWriter = createWriter(resourcePath, fullVersion, "", config.getApplySuffix());
|
||||
FileWriter applyWriter = createWriter(resourcePath, fullVersion, config.getApplySuffix());
|
||||
try {
|
||||
writeApplyDdl(applyWriter, write);
|
||||
applyWriter.flush();
|
||||
@@ -77,28 +81,12 @@ public class PlatformDdlWriter {
|
||||
}
|
||||
}
|
||||
|
||||
protected FileWriter createWriter(File path, String fullVersion, String subPath, String suffix) throws IOException {
|
||||
protected FileWriter createWriter(File path, String fullVersion, String suffix) throws IOException {
|
||||
|
||||
String fileName = fullVersion;
|
||||
if (!platformPrefix.isEmpty()) {
|
||||
fileName += "-"+platformPrefix;
|
||||
}
|
||||
if (subPath != null && !subPath.isEmpty()) {
|
||||
path = subPath(path, subPath);
|
||||
}
|
||||
fileName += suffix;
|
||||
File applyFile = new File(path, fileName);
|
||||
File applyFile = new File(path, fullVersion + suffix);
|
||||
return new FileWriter(applyFile);
|
||||
}
|
||||
|
||||
protected File subPath(File path, String suffix) {
|
||||
File subPath = new File(path, suffix);
|
||||
if (!subPath.exists()) {
|
||||
subPath.mkdirs();
|
||||
}
|
||||
return subPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the 'Apply' DDL buffers to the writer.
|
||||
*/
|
||||
@@ -127,4 +115,17 @@ public class PlatformDdlWriter {
|
||||
return platform.createDdlHandler(serverConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a sub directory (for multi-platform ddl generation).
|
||||
*/
|
||||
public File subPath(File path, String suffix) {
|
||||
File subPath = new File(path, suffix);
|
||||
if (!subPath.exists()) {
|
||||
if (!subPath.mkdirs()) {
|
||||
logger.error("failed to create directories for " + subPath.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
return subPath;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.avaje.ebean.dbmigration.model.build;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformType;
|
||||
import com.avaje.ebean.config.dbplatform.IdType;
|
||||
import com.avaje.ebean.dbmigration.migration.IdentityType;
|
||||
import com.avaje.ebean.dbmigration.model.MColumn;
|
||||
@@ -52,7 +52,7 @@ public class ModelBuildBeanVisitor implements BeanVisitor {
|
||||
if (inheritInfo != null && inheritInfo.isRoot()) {
|
||||
// add the discriminator column
|
||||
String discColumn = inheritInfo.getDiscriminatorColumn();
|
||||
DbType dbType = ctx.getDbTypeMap().get(inheritInfo.getDiscriminatorType());
|
||||
DbPlatformType dbType = ctx.getDbTypeMap().get(inheritInfo.getDiscriminatorType());
|
||||
String discDbType = dbType.renderType(inheritInfo.getDiscriminatorLength(), 0);
|
||||
|
||||
table.addColumn(new MColumn(discColumn, discDbType, true));
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.avaje.ebean.dbmigration.model.build;
|
||||
|
||||
import com.avaje.ebean.config.DbConstraintNaming;
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformType;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformTypeMapping;
|
||||
import com.avaje.ebean.dbmigration.model.MColumn;
|
||||
import com.avaje.ebean.dbmigration.model.MTable;
|
||||
import com.avaje.ebean.dbmigration.model.ModelContainer;
|
||||
@@ -21,7 +21,7 @@ public class ModelBuildContext {
|
||||
* Use platform agnostic logical types. These types are converted to
|
||||
* platform specific types in the DDL generation.
|
||||
*/
|
||||
private final DbTypeMap dbTypeMap = DbTypeMap.logicalTypes();
|
||||
private final DbPlatformTypeMapping dbTypeMap = DbPlatformTypeMapping.logicalTypes();
|
||||
|
||||
private final ModelContainer model;
|
||||
|
||||
@@ -29,10 +29,13 @@ public class ModelBuildContext {
|
||||
|
||||
private final DbConstraintNaming.MaxLength maxLength;
|
||||
|
||||
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength) {
|
||||
private final boolean platformTypes;
|
||||
|
||||
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength, boolean platformTypes) {
|
||||
this.model = model;
|
||||
this.constraintNaming = naming;
|
||||
this.maxLength = maxLength;
|
||||
this.platformTypes = platformTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +106,7 @@ public class ModelBuildContext {
|
||||
* Return the map used to determine the DB specific type
|
||||
* for a given bean property.
|
||||
*/
|
||||
public DbTypeMap getDbTypeMap() {
|
||||
public DbPlatformTypeMapping getDbTypeMap() {
|
||||
return dbTypeMap;
|
||||
}
|
||||
|
||||
@@ -112,14 +115,14 @@ public class ModelBuildContext {
|
||||
* Render the DB type for this property given the strict mode.
|
||||
*/
|
||||
public String getColumnDefn(BeanProperty p, boolean strict) {
|
||||
DbType dbType = getDbType(p);
|
||||
DbPlatformType dbType = getDbType(p);
|
||||
if (dbType == null) {
|
||||
throw new IllegalStateException("Unknown DbType mapping for " + p.getFullBeanName());
|
||||
}
|
||||
return p.renderDbType(dbType, strict);
|
||||
}
|
||||
|
||||
private DbType getDbType(BeanProperty p) {
|
||||
private DbPlatformType getDbType(BeanProperty p) {
|
||||
|
||||
if (p.isDbEncrypted()) {
|
||||
return dbTypeMap.get(p.getDbEncryptedType());
|
||||
@@ -132,7 +135,7 @@ public class ModelBuildContext {
|
||||
}
|
||||
|
||||
// can be the logical JSON types (JSON, JSONB, JSONClob, JSONBlob, JSONVarchar)
|
||||
int dbType = p.getDbType();
|
||||
int dbType = p.getDbType(platformTypes);
|
||||
if (dbType == 0) {
|
||||
throw new RuntimeException("No scalarType defined for " + p.getFullBeanName());
|
||||
}
|
||||
|
||||
@@ -85,6 +85,11 @@ public class ModelBuildIntersectionTable {
|
||||
|
||||
String tableName = intersectionTableJoin.getTable();
|
||||
MTable table = new MTable(tableName);
|
||||
if (!manyProp.isExcludedFromHistory()) {
|
||||
if (localDesc.isHistorySupport()) {
|
||||
table.setWithHistory(true);
|
||||
}
|
||||
}
|
||||
table.setPkName(ctx.primaryKeyName(tableName));
|
||||
|
||||
TableJoinColumn[] columns = intersectionTableJoin.columns();
|
||||
|
||||
+38
-25
@@ -10,13 +10,14 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueConstraint;
|
||||
import com.avaje.ebeaninternal.server.deploy.IndexDefinition;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoinColumn;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Used as part of ModelBuildBeanVisitor and generally adds the MColumn to the associated
|
||||
@@ -44,30 +45,30 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
this.ctx = ctx;
|
||||
this.table = table;
|
||||
this.beanDescriptor = beanDescriptor;
|
||||
addCompoundUniqueConstraint(beanDescriptor.getCompoundUniqueConstraints());
|
||||
addIndexes(beanDescriptor.getIndexDefinitions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add unique constraints defined via JPA UniqueConstraint annotations.
|
||||
*/
|
||||
private void addCompoundUniqueConstraint(CompoundUniqueConstraint[] constraints) {
|
||||
private void addIndexes(IndexDefinition[] indexes) {
|
||||
|
||||
if (constraints != null) {
|
||||
for (int i = 0; i < constraints.length; i++) {
|
||||
CompoundUniqueConstraint constraint = constraints[i];
|
||||
String[] columns = constraint.getColumns();
|
||||
if (indexes != null) {
|
||||
for (int i = 0; i < indexes.length; i++) {
|
||||
IndexDefinition index = indexes[i];
|
||||
String[] columns = index.getColumns();
|
||||
indexSet.add(columns);
|
||||
|
||||
if (constraint.isUnique()) {
|
||||
String uqName = constraint.getName();
|
||||
if (index.isUnique()) {
|
||||
String uqName = index.getName();
|
||||
if (uqName == null || uqName.trim().isEmpty()) {
|
||||
uqName = determineUniqueConstraintName(columns);
|
||||
}
|
||||
table.addCompoundUniqueConstraint(columns, false, uqName);
|
||||
table.addUniqueConstraint(columns, false, uqName);
|
||||
|
||||
} else {
|
||||
// 'just' an index (not a unique constraint)
|
||||
String idxName = constraint.getName();
|
||||
String idxName = index.getName();
|
||||
if (idxName == null || idxName.trim().isEmpty()) {
|
||||
idxName = determineIndexName(columns);
|
||||
}
|
||||
@@ -215,7 +216,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
|
||||
} else {
|
||||
String uqName = determineUniqueConstraintName(p.getName());
|
||||
table.addCompoundUniqueConstraint(modelColumns, true, uqName);
|
||||
table.addUniqueConstraint(modelColumns, true, uqName);
|
||||
indexSetAdd(modelColumns);
|
||||
}
|
||||
}
|
||||
@@ -235,6 +236,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
col.setDefaultValue(p.getDbColumnDefault());
|
||||
col.setComment(p.getDbComment());
|
||||
col.setDraftOnly(p.isDraftOnly());
|
||||
col.setHistoryExclude(p.isExcludedFromHistory());
|
||||
|
||||
if (p.isId()) {
|
||||
col.setPrimaryKey(true);
|
||||
@@ -249,25 +251,36 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
col.setUnique(determineUniqueConstraintName(col.getName()));
|
||||
indexSetAdd(col.getName());
|
||||
}
|
||||
String checkConstraint = p.getDbConstraintExpression();
|
||||
if (checkConstraint != null) {
|
||||
col.setCheckConstraint(checkConstraint);
|
||||
col.setCheckConstraintName(determineCheckConstraintName(col.getName()));
|
||||
}
|
||||
|
||||
String indexName = p.getIndexName();
|
||||
if (indexName != null) {
|
||||
// single column non-unique index
|
||||
if (indexName.trim().isEmpty()) {
|
||||
indexName = determineIndexName(col.getName());
|
||||
Set<String> checkConstraintValues = p.getDbCheckConstraintValues();
|
||||
if (checkConstraintValues != null) {
|
||||
if (beanDescriptor.hasInheritance()) {
|
||||
InheritInfo inheritInfo = beanDescriptor.getInheritInfo();
|
||||
inheritInfo.appendCheckConstraintValues(p.getName(), checkConstraintValues);
|
||||
}
|
||||
ctx.addIndex(indexName, table.getName(), p.getDbColumn());
|
||||
col.setCheckConstraint(buildCheckConstraint(p.getDbColumn(), checkConstraintValues));
|
||||
col.setCheckConstraintName(determineCheckConstraintName(col.getName()));
|
||||
}
|
||||
|
||||
lastColumn = col;
|
||||
table.addColumn(col);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the check constraint clause given the db column and values.
|
||||
*/
|
||||
private String buildCheckConstraint(String dbColumn, Set<String> checkConstraintValues) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("check ( ").append(dbColumn).append(" in (");
|
||||
int count = 0;
|
||||
for (String value : checkConstraintValues) {
|
||||
if (count++ > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(value);
|
||||
}
|
||||
sb.append("))");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void indexSetAdd(String column) {
|
||||
indexSet.add(column);
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user