mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
343
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e68e496207 | ||
|
|
088110385f | ||
|
|
a355f66561 | ||
|
|
00fdb632d7 | ||
|
|
a54c4157e6 | ||
|
|
a89a9f0202 | ||
|
|
331f49824f | ||
|
|
94a857d345 | ||
|
|
1005f177fd | ||
|
|
96a4b93c75 | ||
|
|
5869187368 | ||
|
|
eac50b8f5b | ||
|
|
6e2712ea49 | ||
|
|
f6e5446dab | ||
|
|
4879d44da4 | ||
|
|
2c5bf98d0b | ||
|
|
45a571bd97 | ||
|
|
d0ca75c25b | ||
|
|
fb1c7667cc | ||
|
|
1909ba1557 | ||
|
|
e4eca4bbe9 | ||
|
|
b2438ecd71 | ||
|
|
ed08567d06 | ||
|
|
bbe8abcc2e | ||
|
|
1651d5e119 | ||
|
|
64bf6d6a35 | ||
|
|
47b0a917a2 | ||
|
|
2fe1a349c3 | ||
|
|
f168a8fd0d | ||
|
|
dda98c1dda | ||
|
|
88a13c5416 | ||
|
|
16b8f5da35 | ||
|
|
3471f6d206 | ||
|
|
0bf4c84bc8 | ||
|
|
d366336ee5 | ||
|
|
bf3f8ecff5 | ||
|
|
7524903aea | ||
|
|
90cf3fddc9 | ||
|
|
8e0f9f7591 | ||
|
|
24936c0a41 | ||
|
|
f02a552cdf | ||
|
|
5a5cb7ffbd | ||
|
|
f85fa772bf | ||
|
|
9f9ec8ef9f | ||
|
|
62707caf64 | ||
|
|
c6fc7a032d | ||
|
|
10faa1fae6 | ||
|
|
764f5ce4d4 | ||
|
|
65ba231fc0 | ||
|
|
1da2382e45 | ||
|
|
a86af94a8c | ||
|
|
8301cb634e | ||
|
|
721654d033 | ||
|
|
fe1817ef02 | ||
|
|
fc996659f2 | ||
|
|
368d22baa6 | ||
|
|
daf3d97266 | ||
|
|
f2179fca2d | ||
|
|
2c436c3af5 | ||
|
|
8d334ff2e8 | ||
|
|
f3e4696498 | ||
|
|
221260fa44 | ||
|
|
f8e7a79e9a | ||
|
|
b66f18bfd6 | ||
|
|
ac6708e0d0 | ||
|
|
a5f46c095d | ||
|
|
3ac7ea6e60 | ||
|
|
b2e0271ce7 | ||
|
|
c7a7651602 | ||
|
|
1e6678cbb4 | ||
|
|
a6e4e181bf | ||
|
|
b8e1dffca2 | ||
|
|
7e8ed72b7b | ||
|
|
ec8dd30a04 | ||
|
|
f81d5c9f3a | ||
|
|
74b24b1db1 | ||
|
|
179ef8c8a0 | ||
|
|
f77f3c3d6e | ||
|
|
9a7646195c | ||
|
|
84d3578e33 | ||
|
|
ef05b81014 | ||
|
|
726c682984 | ||
|
|
0c22a99fdf | ||
|
|
c062c8e001 | ||
|
|
06f3c000f5 | ||
|
|
8c0232fdb8 | ||
|
|
2470486f20 | ||
|
|
8fbf0374dd | ||
|
|
dd8fff0277 | ||
|
|
73b3d1d977 | ||
|
|
2a76ae2192 | ||
|
|
39931a3a2c | ||
|
|
58eb49617b | ||
|
|
9b621d2ec7 | ||
|
|
f2e8b652fa | ||
|
|
f342d9d561 | ||
|
|
8009bdf099 | ||
|
|
7336ce81bd | ||
|
|
f805bec8f2 | ||
|
|
46cdc84e6b | ||
|
|
e908d16ba8 | ||
|
|
96e3f4138f | ||
|
|
977dd52890 | ||
|
|
a9b7bb2175 | ||
|
|
f83c7fdac8 | ||
|
|
a695fb59b2 | ||
|
|
e197bb2900 | ||
|
|
b54b8815d9 | ||
|
|
1d1fde61be | ||
|
|
683186cbe9 | ||
|
|
5e6be40454 | ||
|
|
c00febd95b | ||
|
|
4c8e1113bf | ||
|
|
6f854da70b | ||
|
|
3f5a162a4e | ||
|
|
d14529b602 | ||
|
|
f471961f06 | ||
|
|
457c1356a4 | ||
|
|
419ac2bf50 | ||
|
|
727d088577 | ||
|
|
972d2dcc6b | ||
|
|
a5bcd49ecb | ||
|
|
ff496ad2d3 | ||
|
|
24d438ba23 | ||
|
|
591067e39e | ||
|
|
38a95dc5c4 | ||
|
|
53426d8493 | ||
|
|
a06238558e | ||
|
|
b3a3b19d5d | ||
|
|
57231c80a8 | ||
|
|
dc96fb9ad5 | ||
|
|
567847b47a | ||
|
|
b74fed7073 | ||
|
|
cdaf8ee6d5 | ||
|
|
c6c5073e47 | ||
|
|
2a58b954e9 | ||
|
|
9772623880 | ||
|
|
27b6183aad | ||
|
|
55e19618f8 | ||
|
|
5c60ba4d7f | ||
|
|
b9cc584086 | ||
|
|
bf5a8c2fad | ||
|
|
66138e5ea2 | ||
|
|
75fb89ef76 | ||
|
|
a2cb468222 | ||
|
|
166bcd7c45 | ||
|
|
95aed6af54 | ||
|
|
7a697c12af | ||
|
|
23278ce30b | ||
|
|
36a5610e25 | ||
|
|
08263c4588 | ||
|
|
1e88a52208 | ||
|
|
e770a42175 | ||
|
|
35b467c04f | ||
|
|
2001539755 | ||
|
|
e49c4bfe5a | ||
|
|
15be31fd5f | ||
|
|
4777ec46be | ||
|
|
80ab731aec | ||
|
|
080bafe18f | ||
|
|
e913f88f52 | ||
|
|
e94c5484a0 | ||
|
|
4af00c51d3 | ||
|
|
23d1256dbf | ||
|
|
ed0ef46d2e | ||
|
|
1860ded735 | ||
|
|
d432854b82 | ||
|
|
93582c8ea3 | ||
|
|
520d35b1d6 | ||
|
|
8ca3599cbf | ||
|
|
283ae74219 | ||
|
|
cebd3f92a4 | ||
|
|
4b2481d3ea | ||
|
|
f1f2a416d3 | ||
|
|
74dd97a55f | ||
|
|
3f04f7f363 | ||
|
|
800f854a12 | ||
|
|
bef9e6d54f | ||
|
|
0e4c0ae6c3 | ||
|
|
a0ea9887df | ||
|
|
0413c22e6e | ||
|
|
989ae44a6d | ||
|
|
100d314e63 | ||
|
|
dbf4e99187 | ||
|
|
7b8a85106c | ||
|
|
58c5f01e2b | ||
|
|
bc74d35651 | ||
|
|
a1f95bf25e | ||
|
|
c454e1f8a7 | ||
|
|
5a3669e1db | ||
|
|
7a2e0b3695 | ||
|
|
ce6d6269cd | ||
|
|
7d800b7080 | ||
|
|
136154e247 | ||
|
|
0a5ce1bee8 | ||
|
|
b4e2c89e2d | ||
|
|
9e2923f571 | ||
|
|
d0c1ae76f4 | ||
|
|
fe9500e6d0 | ||
|
|
79f7c73983 | ||
|
|
d04954e46f | ||
|
|
88c6ec358c | ||
|
|
d3ea01b76e | ||
|
|
0c1a9786a3 | ||
|
|
db298a349e | ||
|
|
c1bed9f578 | ||
|
|
c7cbe4ead8 | ||
|
|
4064aaf714 | ||
|
|
6ad808003a | ||
|
|
70de6101db | ||
|
|
933595ceea | ||
|
|
461c2aef60 | ||
|
|
0c49b6514c | ||
|
|
0ec425928b | ||
|
|
711701932a | ||
|
|
951e517caf | ||
|
|
8cef603d1c | ||
|
|
2a64a02211 | ||
|
|
67ef0cd5d9 | ||
|
|
9f2334362a | ||
|
|
44ff304423 | ||
|
|
f9c70d2a2b | ||
|
|
e51f7f11f1 | ||
|
|
54ef0e7465 | ||
|
|
63def00626 | ||
|
|
335c4de109 | ||
|
|
a120c2aaee | ||
|
|
43408fcb87 | ||
|
|
8432f7b0d5 | ||
|
|
bdd7884f42 | ||
|
|
485e62b5d6 | ||
|
|
0557e6cd08 | ||
|
|
b821702b8d | ||
|
|
c5b23c321e | ||
|
|
964d2d00a2 | ||
|
|
1778afa17d | ||
|
|
0d9f9982b7 | ||
|
|
7178085680 | ||
|
|
4d82b86f81 | ||
|
|
1d99a5c5a4 | ||
|
|
41a7f2c97e | ||
|
|
c8d01828b3 | ||
|
|
a3dbd4538f | ||
|
|
3051412d90 | ||
|
|
a22eb555d0 | ||
|
|
cb89300027 | ||
|
|
27cb0d062d | ||
|
|
140c1dd965 | ||
|
|
75b9e748f4 | ||
|
|
289c0253b1 | ||
|
|
07ce758302 | ||
|
|
d91729f65d | ||
|
|
9e64d09e07 | ||
|
|
5f63d5c35f | ||
|
|
23e1ab4bfd | ||
|
|
0e2900d796 | ||
|
|
a46e086dc4 | ||
|
|
40ca179509 | ||
|
|
7632910027 | ||
|
|
ca777d7967 | ||
|
|
a315c7c11e | ||
|
|
35f3f53443 | ||
|
|
40f5596837 | ||
|
|
43c978e41a | ||
|
|
6120a465e1 | ||
|
|
8bb884374b | ||
|
|
3d8db775f7 | ||
|
|
b3b8f6b154 | ||
|
|
e4c80582a5 | ||
|
|
1846427859 | ||
|
|
82102340b8 | ||
|
|
d9e884b8bd | ||
|
|
6744c7886a | ||
|
|
271b4ee095 | ||
|
|
7cfdd331ca | ||
|
|
7e15faa9a8 | ||
|
|
1292c86b76 | ||
|
|
0260a73cb6 | ||
|
|
085fdaf177 | ||
|
|
a4b49dfa27 | ||
|
|
d056151852 | ||
|
|
f9ba6f9a3a | ||
|
|
2fa4345742 | ||
|
|
d9147327c1 | ||
|
|
5ad9a611f9 | ||
|
|
3fb497b651 | ||
|
|
fbfe5d1ff8 | ||
|
|
b6f21f8649 | ||
|
|
8fd04807c7 | ||
|
|
e49c42302a | ||
|
|
d96abece75 | ||
|
|
c953da637e | ||
|
|
8d39b0a996 | ||
|
|
0efcf1eeb3 | ||
|
|
335cef870f | ||
|
|
4c40962f04 | ||
|
|
9be0d22cfb | ||
|
|
2893d73fad | ||
|
|
33d66ea9d1 | ||
|
|
073ea9c550 | ||
|
|
8467934021 | ||
|
|
96ba63407f | ||
|
|
88df6ffc6e | ||
|
|
3efcfec300 | ||
|
|
e51eb00889 | ||
|
|
9ae27ddcdd | ||
|
|
b9516e64a3 | ||
|
|
f7f5552bf0 | ||
|
|
adec2ab1b8 | ||
|
|
da6d7284f8 | ||
|
|
1c160fea5a | ||
|
|
cc87de76d7 | ||
|
|
70b380e6e7 | ||
|
|
3e419d3e3a | ||
|
|
7e2be20b6e | ||
|
|
ab2d5fb4c8 | ||
|
|
809901ff13 | ||
|
|
fcc58d77e8 | ||
|
|
bc93a82b1a | ||
|
|
84e1e12b66 | ||
|
|
2eb0c12213 | ||
|
|
4941134ce1 | ||
|
|
cf37fda3f4 | ||
|
|
f429811f79 | ||
|
|
70fd988d8c | ||
|
|
fe4167ed60 | ||
|
|
0eef69a277 | ||
|
|
76bfd805c0 | ||
|
|
971e2dc91b | ||
|
|
5821dc96b9 | ||
|
|
e027110006 | ||
|
|
b5e6e9a66c | ||
|
|
514047e680 | ||
|
|
a727a98a21 | ||
|
|
e75b5e8b30 | ||
|
|
ad0e085ff5 | ||
|
|
322a2f500d | ||
|
|
1c7454d249 | ||
|
|
e1efca6736 | ||
|
|
8ae61074ad | ||
|
|
c3bc0c4975 | ||
|
|
611bba272a | ||
|
|
4c9ec38c88 |
+2
-1
@@ -1,3 +1,4 @@
|
||||
dist: trusty
|
||||
sudo: required
|
||||
language: java
|
||||
jdk:
|
||||
@@ -7,7 +8,7 @@ git:
|
||||
depth: 3
|
||||
|
||||
addons:
|
||||
postgresql: "9.4"
|
||||
postgresql: "9.6"
|
||||
|
||||
services:
|
||||
- postgresql
|
||||
|
||||
@@ -6,12 +6,12 @@ Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Web
|
||||
|
||||
|
||||
## Maven cental links:
|
||||
[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 - ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.ebean%22%20AND%20a%3A%22ebean%22 "maven central ebean")
|
||||
|
||||
[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.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
|
||||
* [](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
|
||||
|
||||
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
This is a short description how to run tests
|
||||
============================================
|
||||
|
||||
Run tests from maven
|
||||
--------------------
|
||||
|
||||
Just type `mvn test` - it will run the whole test suite with the settings
|
||||
from `src/test/resources/ebean.properties`.
|
||||
|
||||
Run tests from eclipse
|
||||
----------------------
|
||||
|
||||
Running tests requires, that the classes are enhanced. By default, the
|
||||
`BaseTestCase` tries to load the enhancer-agent in a very early stage. This
|
||||
also works for most test cases, but it does not work if you try to run a
|
||||
complete test-suite, as classes that are loaded before the enhancer-agent
|
||||
kicks in will not get enhanced. To solve this problem, you need either the
|
||||
[Eclipse-Enhancer-Plugin](https://github.com/ebean-orm-tools/ebean-eclipse-enhancer)
|
||||
or add the agent to your JVM arguments (Preferences->Installed JREs) or to
|
||||
your run configuration:
|
||||
`-javaagent:<USER_HOME>/.m2/repository/io/ebean/ebean-agent/<VERSION>/ebean-agent-<VERSION>.jar=debug=0`
|
||||
|
||||
|
||||
Platform Tests
|
||||
==============
|
||||
|
||||
By default, the `h2` platform is used. To test a different platform, add
|
||||
`-Ddatasource.default=xxx` to your maven command or JVM arguments.
|
||||
|
||||
'h2' platform
|
||||
-------------
|
||||
|
||||
Reqires no setup
|
||||
|
||||
run: `mvn clean test`
|
||||
|
||||
Current status: PASS
|
||||
Tests run: 1986, Failures: 0, Errors: 0, Skipped: 16
|
||||
|
||||
'pg' platform
|
||||
-------------
|
||||
|
||||
Reqirements
|
||||
- a locally installed PostgreSQL server with PostGis.
|
||||
- Create a user "unit" with password "unit" and a database "unit"
|
||||
- Give the user all permissions to that db
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=pg`
|
||||
|
||||
Current status: PASS
|
||||
Tests run: 1986, Failures: 0, Errors: 0, Skipped: 16
|
||||
|
||||
|
||||
'mysql' platform
|
||||
-------------
|
||||
|
||||
Reqirements
|
||||
- a locally installed MySQL server.
|
||||
- Create a user "unit" with password "unit" and a database "unit"
|
||||
- Give the user all permissions to that db
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=mysql`
|
||||
|
||||
Current status: FAIL
|
||||
Tests run: 1986, Failures: 2, Errors: 4, Skipped: 16
|
||||
|
||||
|
||||
|
||||
'sqlserver' platform
|
||||
--------------------
|
||||
|
||||
Reqires an installed sqlserver - e.g. https://hub.docker.com/r/microsoft/mssql-server-linux/
|
||||
|
||||
- Create a user "ebean" with password "ebean" and a database "ebean_unittest"
|
||||
- Adjust the connection string and/or username in ebean.properties
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=mssql`
|
||||
|
||||
Current status: FAIL
|
||||
Tests run: 1986, Failures: 19, Errors: 43, Skipped: 16
|
||||
|
||||
|
||||
|
||||
'oracle' platform
|
||||
-----------------
|
||||
|
||||
Reqires a locally installed Oracle server.
|
||||
- Create a user "unit" with password "unit" with all permissions
|
||||
- The test wirtes directly to the "xe" SID - so do not use a productive server!
|
||||
- As the Oracle JDBC driver is only available on an oracle repository,
|
||||
you need a special maven setup as described [here](http://docs.oracle.com/middleware/1213/core/MAVEN/config_maven_repo.htm#MAVEN9010)
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=ora -Poracle`
|
||||
|
||||
Current status: FAIL
|
||||
Tests run: 1986, Failures: 17, Errors: 34, Skipped: 16
|
||||
|
||||
|
||||
|
||||
'db2' platform
|
||||
--------------
|
||||
|
||||
Reqires a locally installed DB2 Express-C server.
|
||||
- Create a user "unit" with password "unit" with all permissions
|
||||
- Install the db2jcc4 driver (see pom.xml)
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=db2 -Pdb2`
|
||||
|
||||
Current status: FAIL
|
||||
Tests run: 1986, Failures: 33, Errors: 26, Skipped: 16
|
||||
|
||||
|
||||
'sqlite' platform
|
||||
-----------------
|
||||
|
||||
Reqires no setup
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=sqlite`
|
||||
|
||||
Current status: FAIL
|
||||
Tests run: 1986, Failures: 24, Errors: 86, Skipped: 16
|
||||
|
||||
After some time, the db locks up, every test takes 3 seconds and fails with
|
||||
"the database file is locked"
|
||||
|
||||
|
||||
|
||||
'hsqldb' platform
|
||||
-----------------
|
||||
|
||||
Reqires no setup
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=hsqldb`
|
||||
|
||||
Current status: FAIL
|
||||
Tests run: 1980, Failures: 3, Errors: 657, Skipped: 16
|
||||
|
||||
|
||||
@Rob FYI
|
||||
The problem is https://sourceforge.net/p/hsqldb/bugs/1364/
|
||||
In `InsertHandler.getPstmt` the `meta.getIdentityDbColumns()` contains
|
||||
'id' in lowercase. Changing that to uppercase gives me this result:
|
||||
`Tests run: 1986, Failures: 2, Errors: 18, Skipped: 16`
|
||||
(as quick hack I added temporary a toUpperCase to BindableIdScalar.getIdentityColumn)
|
||||
|
||||
|
||||
'sqlanywhere' platform
|
||||
----------------------
|
||||
|
||||
TODO: not yet tested
|
||||
|
||||
|
||||
@@ -4,26 +4,72 @@
|
||||
<parent>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>java8-parent</artifactId>
|
||||
<version>1.1</version>
|
||||
<version>1.3</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>9.4.1</version>
|
||||
<version>11.2.3</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
<url>http://ebean-orm.github.io/</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-9.4.1</tag>
|
||||
<tag>ebean-11.2.3</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<!-- Note: to use this profile, you need credentials for the oracle repository in your
|
||||
settings.xml as described here:
|
||||
http://docs.oracle.com/middleware/1213/core/MAVEN/config_maven_repo.htm#MAVEN9010 -->
|
||||
<id>oracle</id>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.oracle.jdbc</groupId>
|
||||
<artifactId>ojdbc8</artifactId>
|
||||
<version>12.2.0.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>maven.oracle.com</id>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<url>https://maven.oracle.com</url>
|
||||
<layout>default</layout>
|
||||
</repository>
|
||||
</repositories>
|
||||
</profile>
|
||||
<profile>
|
||||
<!-- Note: to use this profile, you need to download manually the db2jcc4 driver.
|
||||
After that, install it into your local maven repository:
|
||||
|
||||
mvn install:install-file \
|
||||
-Dfile=db2jcc4.jar \
|
||||
-DgroupId=com.ibm.jdbc \
|
||||
-DartifactId=db2jcc4 \
|
||||
-Dversion=4.23.42 \
|
||||
-Dpackaging=jar
|
||||
-->
|
||||
<id>db2</id>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.ibm.jdbc</groupId>
|
||||
<artifactId>db2jcc4</artifactId>
|
||||
<version>4.23.42</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
@@ -33,15 +79,15 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>2.1.3</version>
|
||||
<version>2.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>1.4</version>
|
||||
<version>3.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -53,7 +99,7 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-datasource</artifactId>
|
||||
<version>1.1.3</version>
|
||||
<version>2.1.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -65,13 +111,13 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-classpath-scanner</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<version>2.2.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-dbmigration</artifactId>
|
||||
<version>1.2.1</version>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>11.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -83,21 +129,21 @@
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-runtime</artifactId>
|
||||
<version>4.5.3</version>
|
||||
<version>4.6</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.6.5</version>
|
||||
<version>2.9.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope for JsonNode support -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.6.5</version>
|
||||
<version>2.9.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -112,21 +158,21 @@
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>1.0.0.GA</version>
|
||||
<version>1.1.0.Final</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.4</version>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>1.6</version>
|
||||
<version>2.9.7</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -134,7 +180,7 @@
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>9.4-1202-jdbc41</version>
|
||||
<version>9.4.1212</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -157,14 +203,14 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-agentloader</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<version>2.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-agent</artifactId>
|
||||
<version>8.1.1</version>
|
||||
<version>11.1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -173,28 +219,36 @@
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.192</version>
|
||||
<version>1.4.193</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.8.11.2</version>
|
||||
<version>3.15.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>2.3.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
<version>6.1.3.jre8-preview</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.36</version>
|
||||
<!-- Do not upgrade to 6.0.6: https://bugs.mysql.com/bug.php?id=82896 -->
|
||||
<version>5.1.43</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -209,14 +263,14 @@
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
<version>2.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.moduuid</groupId>
|
||||
<artifactId>avaje-moduuid</artifactId>
|
||||
<version>1.2</version>
|
||||
<version>2.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -227,19 +281,18 @@
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>8.1.1</version>
|
||||
<version>11.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
<phase>process-test-classes</phase>
|
||||
<configuration>
|
||||
<classSource>target/test-classes</classSource>
|
||||
<transformArgs>debug=1</transformArgs>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>enhance</goal>
|
||||
<goal>testEnhance</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
@@ -283,11 +336,11 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<doctitle>Ebean 9</doctitle>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
<doctitle>Ebean 10</doctitle>
|
||||
<overview>src/main/java/io/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
<excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util:com.avaje.ebean.dbmigration.ddlgeneration:com.avaje.ebean.dbmigration.migration:com.avaje.ebean.dbmigration.migrationreader:com.avaje.ebean.dbmigration.model</excludePackageNames>
|
||||
<excludePackageNames>io.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
|
||||
<docletArtifact>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>pygments-doclet</artifactId>
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Execute a TxCallable in a Transaction scope.
|
||||
* <p>
|
||||
* Use this with the {@link Ebean#execute(TxCallable)} method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that this is basically the same as TxRunnable except that it returns an
|
||||
* Object (and you specify the return type via generics).
|
||||
* </p>
|
||||
* <p>
|
||||
* See also {@link TxRunnable}.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Ebean.execute(new TxCallable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* User u2 = Ebean.find(User.class, 2);
|
||||
*
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
*
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
*
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see TxRunnable
|
||||
*/
|
||||
public interface TxCallable<T> {
|
||||
|
||||
/**
|
||||
* Execute the method within a transaction scope returning the result.
|
||||
* <p>
|
||||
* If you do not want to return a result you should look to use TxRunnable
|
||||
* instead.
|
||||
* </p>
|
||||
*/
|
||||
T call();
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Execute a TxRunnable in a Transaction scope.
|
||||
* <p>
|
||||
* Use this with the {@link Ebean#execute(TxRunnable)} method.
|
||||
* </p>
|
||||
* <p>
|
||||
* See also {@link TxCallable}.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // this run method runs in a transaction scope
|
||||
* // which by default is TxScope.REQUIRED
|
||||
*
|
||||
* Ebean.execute(new TxRunnable() {
|
||||
* public void run() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* User u2 = Ebean.find(User.class, 2);
|
||||
*
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
*
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see TxCallable
|
||||
*/
|
||||
public interface TxRunnable {
|
||||
|
||||
/**
|
||||
* Run the method in a transaction sope.
|
||||
*/
|
||||
void run();
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.config.Platform;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Assign to a property to be based on a SQL formula.
|
||||
* <p>
|
||||
* This is typically a SQL Literal value, SQL case statement, SQL function or
|
||||
* similar.
|
||||
* </p>
|
||||
* <p>
|
||||
* Any property based on a formula becomes a read only property.
|
||||
* </p>
|
||||
* <p>
|
||||
* You may also put use the Transient annotation with the Formula annotation.
|
||||
* The effect of the Transient annotation in this case is that the formula will
|
||||
* <b>NOT</b> be included in queries by default - you have to explicitly include
|
||||
* it via {@link Query#select(String)} or {@link Query#fetch(String, String, com.avaje.ebean.FetchConfig)}.
|
||||
* You may want to do this if the Formula is relatively expensive and only want
|
||||
* it included in the query when you explicitly state it.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
* // On the Order "master" bean
|
||||
* // ... a formula using the Order details
|
||||
* // ... sum(order_qty*unit_price)
|
||||
* @Transient
|
||||
* @Formula(select = "_b${ta}.total_amount", join = "join (select order_id, sum(order_qty*unit_price) as total_amount from o_order_detail group by order_id) as _b${ta} on _b${ta}.order_id = ${ta}.id")
|
||||
* Double totalAmount;
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* As the totalAmount formula is also Transient it is not included by default in
|
||||
* queries - it needs to be explicitly included.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // find by Id
|
||||
* Order o1 = Ebean.find(Order.class)
|
||||
* .select("id, totalAmount")
|
||||
* .setId(1).findUnique();
|
||||
*
|
||||
* // find list ... using totalAmount in the where clause
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .select("id, totalAmount")
|
||||
* .where()
|
||||
* .eq("status", Order.Status.NEW)
|
||||
* .gt("totalAmount", 10)
|
||||
* .findList();
|
||||
*
|
||||
* // as a join from customer
|
||||
* List<Customer> l0 = Ebean.find(Customer.class)
|
||||
* .select("id, name")
|
||||
* .fetch("orders", "status, totalAmount")
|
||||
* .where()
|
||||
* .gt("id", 0)
|
||||
* .gt("orders.totalAmount", 10)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(Formula.List.class)
|
||||
public @interface Formula {
|
||||
|
||||
/**
|
||||
* The SQL to be used in the SELECT part of the SQL to populate a property.
|
||||
*/
|
||||
String select();
|
||||
|
||||
/**
|
||||
* OPTIONAL - the SQL to be used in the JOIN part of the SQL to support the
|
||||
* formula.
|
||||
* <p>
|
||||
* This is commonly used to join a 'dynamic view' to support aggregation such
|
||||
* as count, sum etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* The join string should start with either "left join" or "join".
|
||||
* </p>
|
||||
* <p>
|
||||
* You will almost certainly use the "${ta}" as a place holder for the table
|
||||
* alias of the table you are joining back to (the "base table" of the entity
|
||||
* bean).
|
||||
* </p>
|
||||
* <p>
|
||||
* The example below is used to support a total count of topics created by a
|
||||
* user.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* join (select user_id, count(*) as topic_count from f_topic group by user_id) as _tc on _tc.user_id = ${ta}.id
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
String join() default "";
|
||||
|
||||
Platform[] platforms() default {};
|
||||
|
||||
/**
|
||||
* Repeatable support for {@link Formula}.
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface List {
|
||||
|
||||
Formula[] value() default {};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import com.avaje.ebean.TxIsolation;
|
||||
import com.avaje.ebean.TxType;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify transaction scoping for a method.
|
||||
* <p>
|
||||
* <b><i> This is only supported if "Enhancement" is used via javaagent, ANT
|
||||
* task or IDE enhancement plugin etc. </i></b>
|
||||
* </p>
|
||||
* <p>
|
||||
* Note: Currently there are 3 known annotations that perform this role.
|
||||
* <ul>
|
||||
* <li>EJB's javax.ejb.TransactionAttribute</li>
|
||||
* <li>Spring's org.springframework.transaction.annotation.Transactional</li>
|
||||
* <li>and this one, Ebean's own com.avaje.ebean.annotation.Transactional</li>
|
||||
* </ul>
|
||||
* Spring created their one because the EJB annotation does not support features
|
||||
* such as isolation level and specifying rollbackOn, noRollbackOn exceptions.
|
||||
* This one exists for Ebean because I agree that the standard one is
|
||||
* insufficient and don't want to include a dependency on Spring.
|
||||
* </p>
|
||||
* <p>
|
||||
* The default behaviour of EJB (and hence Spring) is to NOT ROLLBACK on checked
|
||||
* exceptions. I find this very counter-intuitive. Ebean will provide a property
|
||||
* to set the default behaviour to rollback on any exception and optionally
|
||||
* change the setting to be consistent with EJB/Spring if people wish to do so.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // a normal class
|
||||
* public class MySimpleUserService {
|
||||
*
|
||||
* // this method is transactional automatically handling
|
||||
* // transaction begin, commit and rollback etc
|
||||
* @Transactional
|
||||
* public void runInTrans() throws IOException {
|
||||
*
|
||||
* // tasks performed within the transaction
|
||||
* ...
|
||||
* // find some objects
|
||||
* Customer cust = ebeanServer.find(Customer.class, 42);
|
||||
*
|
||||
* Order order = ...;
|
||||
* ...
|
||||
* // save some objects
|
||||
* ebeanServer.save(customer);
|
||||
* ebeanServer.save(order);
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Transactional {
|
||||
|
||||
/**
|
||||
* The type of transaction scoping. Defaults to REQUIRED.
|
||||
*/
|
||||
TxType type() default TxType.REQUIRED;
|
||||
|
||||
/**
|
||||
* Persist batch mode for the transaction.
|
||||
*/
|
||||
PersistBatch batch() default PersistBatch.INHERIT;
|
||||
|
||||
/**
|
||||
* Persist batch mode for the request if not set on the transaction.
|
||||
* <p>
|
||||
* If batch is set to NONE then batchOnCascade can be set to INSERT or ALL
|
||||
* and then each save(), delete(), insert(), update() request that cascades
|
||||
* to child beans can use JDBC batch.
|
||||
* </p>
|
||||
*/
|
||||
PersistBatch batchOnCascade() default PersistBatch.INHERIT;
|
||||
|
||||
/**
|
||||
* The batch size to use when using JDBC batch mode.
|
||||
* <p>
|
||||
* If unset this defaults to the value set in ServerConfig.
|
||||
* </p>
|
||||
*/
|
||||
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>
|
||||
* This will only be used if this scope creates the transaction. If the
|
||||
* transaction has already started then this will currently be ignored (you
|
||||
* could argue that it should throw an exception).
|
||||
* </p>
|
||||
*/
|
||||
TxIsolation isolation() default TxIsolation.DEFAULT;
|
||||
|
||||
/**
|
||||
* Set this to true if the transaction should be only contain queries.
|
||||
*/
|
||||
boolean readOnly() default false;
|
||||
|
||||
/**
|
||||
* The name of the server that you want the transaction to be created from.
|
||||
* <p>
|
||||
* If left blank the 'default' server is used.
|
||||
* </p>
|
||||
*/
|
||||
String serverName() default "";
|
||||
|
||||
// int timeout() default 0;
|
||||
|
||||
/**
|
||||
* The Throwable's that will explicitly cause a rollback to occur.
|
||||
*/
|
||||
Class<? extends Throwable>[] rollbackFor() default {};
|
||||
|
||||
/**
|
||||
* The Throwable's that will explicitly NOT cause a rollback to occur.
|
||||
*/
|
||||
Class<? extends Throwable>[] noRollbackFor() default {};
|
||||
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import com.avaje.ebean.config.Platform;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Add an Literal to add to the where clause when a many property (List, Set or
|
||||
* Map) is loaded or refreshed.
|
||||
* <pre>{@code
|
||||
*
|
||||
* // on a OneToMany property...
|
||||
*
|
||||
* @OneToMany
|
||||
* @Where(clause = "deleted='y'")
|
||||
* List<Topic> topics;
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Note that you can include "${ta}" as a place holder for the table alias if
|
||||
* you need to include the table alias in the clause.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* // ... including the ${ta} table alias placeholder...
|
||||
*
|
||||
* @OneToMany
|
||||
* @Where(clause = "${ta}.deleted='y'")
|
||||
* List<Topic> topics;
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* This will be added to the where clause when lazy loading the OneToMany
|
||||
* property or when there is a join to that OneToMany property.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(Where.List.class)
|
||||
public @interface Where {
|
||||
|
||||
/**
|
||||
* The clause added to the lazy load query.
|
||||
* <p>
|
||||
* Note that you can include "${ta}" as a place holder for the table alias if
|
||||
* you need to include the table alias in the clause.
|
||||
* </p>
|
||||
*/
|
||||
String clause();
|
||||
|
||||
/**
|
||||
* The platform where this annotation is active. Default: any platform
|
||||
*/
|
||||
Platform[] platforms() default {};
|
||||
|
||||
/**
|
||||
* Repeatable support for {@link Where}.
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface List {
|
||||
|
||||
Where[] value() default {};
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* DB Column default values mapping to database platform specific literals.
|
||||
*/
|
||||
public class DbDefaultValue {
|
||||
|
||||
/**
|
||||
* The key for FALSE.
|
||||
*/
|
||||
public static final String FALSE = "false";
|
||||
|
||||
/**
|
||||
* The key for TRUE.
|
||||
*/
|
||||
public static final String TRUE = "true";
|
||||
|
||||
/**
|
||||
* The key for the NOW / current timestamp.
|
||||
*/
|
||||
public static final String NOW = "now";
|
||||
|
||||
protected Map<String, String> map = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* Set the DB now function.
|
||||
*/
|
||||
public void setNow(String dbFunction) {
|
||||
put(NOW, dbFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB false literal.
|
||||
*/
|
||||
public void setFalse(String dbFalseLiteral) {
|
||||
put(FALSE, dbFalseLiteral);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB true literal.
|
||||
*/
|
||||
public void setTrue(String dbTrueLiteral) {
|
||||
put(TRUE, dbTrueLiteral);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an translation entry.
|
||||
*/
|
||||
public void put(String dbLiteral, String dbTranslated) {
|
||||
map.put(dbLiteral, dbTranslated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the DB default literal to platform specific type or function.
|
||||
* <p>
|
||||
* This is intended for the DB column default clause in DDL.
|
||||
* </p>
|
||||
*/
|
||||
public String convert(String dbDefaultLiteral) {
|
||||
if (dbDefaultLiteral == null) {
|
||||
return null;
|
||||
}
|
||||
String val = map.get(dbDefaultLiteral);
|
||||
return val != null ? val : dbDefaultLiteral;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.avaje.ebean.config.dbplatform.db2;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformType;
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.avaje.ebean.config.dbplatform.PlatformIdGenerator;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.DB2Ddl;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* DB2 specific platform.
|
||||
*/
|
||||
public class DB2Platform extends DatabasePlatform {
|
||||
|
||||
public DB2Platform() {
|
||||
super();
|
||||
this.name = "db2";
|
||||
this.maxTableNameLength = 18;
|
||||
this.maxConstraintNameLength = 18;
|
||||
this.sqlLimiter = new Db2SqlLimiter();
|
||||
this.platformDdl = new DB2Ddl(this);
|
||||
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
booleanDbType = Types.BOOLEAN;
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("real"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 15));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a DB2 specific sequence IdGenerator that supports batch fetching
|
||||
* sequence values.
|
||||
*/
|
||||
@Override
|
||||
public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be,
|
||||
DataSource ds, String seqName, int batchSize) {
|
||||
|
||||
return new DB2SequenceIdGenerator(be, ds, seqName, batchSize);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
/**
|
||||
* DB2 platform specific DDL.
|
||||
*/
|
||||
public class DB2Ddl extends PlatformDdl {
|
||||
|
||||
public DB2Ddl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.identitySuffix = " generated by default as identity";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
/**
|
||||
* H2 platform specific DDL.
|
||||
*/
|
||||
public class H2Ddl extends PlatformDdl {
|
||||
|
||||
public H2Ddl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.historyDdl = new H2HistoryDdl();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import com.avaje.ebean.dbmigration.migration.AlterColumn;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* MS SQL Server platform specific DDL.
|
||||
*/
|
||||
public class MsSqlServerDdl extends PlatformDdl {
|
||||
|
||||
public MsSqlServerDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.identitySuffix = " identity(1,1)";
|
||||
this.foreignKeyRestrict = "";
|
||||
this.inlineUniqueOneToOne = false;
|
||||
this.columnSetDefault = "add default";
|
||||
this.dropConstraintIfExists = "drop constraint";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dropTable(String tableName) {
|
||||
return "IF OBJECT_ID('" + tableName + "', 'U') IS NOT NULL drop table " + tableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterTableDropForeignKey(String tableName, String fkName) {
|
||||
return "IF OBJECT_ID('" + fkName + "', 'F') IS NOT NULL " + super.alterTableDropForeignKey(tableName, fkName);
|
||||
}
|
||||
|
||||
/**
|
||||
* MsSqlServer specific null handling on unique constraints.
|
||||
*/
|
||||
@Override
|
||||
public String alterTableAddUniqueConstraint(String tableName, String uqName, String[] columns) {
|
||||
|
||||
// issues#233
|
||||
String start = "create unique nonclustered index " + uqName + " on " + tableName + "(";
|
||||
StringBuilder sb = new StringBuilder(start);
|
||||
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(columns[i]);
|
||||
}
|
||||
sb.append(") where");
|
||||
for (String column : columns) {
|
||||
sb.append(" ").append(column).append(" is not null");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) {
|
||||
|
||||
if (isDropDefault(defaultValue)) {
|
||||
return "-- alter table " + tableName + " drop constraint <unknown> -- find the appropriate constraint for default value on column " + columnName;
|
||||
} else {
|
||||
return "alter table " + tableName + " add default " + defaultValue + " for " + columnName;
|
||||
}
|
||||
}
|
||||
|
||||
public String alterColumnBaseAttributes(AlterColumn alter) {
|
||||
|
||||
String tableName = alter.getTableName();
|
||||
String columnName = alter.getColumnName();
|
||||
String type = alter.getType() != null ? alter.getType() : alter.getCurrentType();
|
||||
boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull());
|
||||
String notnullClause = notnull ? " not null" : "";
|
||||
|
||||
return "alter table " + tableName + " alter column " + columnName + " " + type + notnullClause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnType(String tableName, String columnName, String type) {
|
||||
|
||||
// can't alter itself - done in alterColumnBaseAttributes()
|
||||
return null;
|
||||
}
|
||||
|
||||
public String alterColumnNotnull(String tableName, String columnName, boolean notnull) {
|
||||
|
||||
// can't alter itself - done in alterColumnBaseAttributes()
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add table comment as a separate statement (from the create table statement).
|
||||
*/
|
||||
public void addTableComment(DdlBuffer apply, String tableName, String tableComment) throws IOException {
|
||||
|
||||
// do nothing for MS SQL Server (cause it requires stored procedures etc)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add column comment as a separate statement.
|
||||
*/
|
||||
public void addColumnComment(DdlBuffer apply, String table, String column, String comment) throws IOException {
|
||||
|
||||
// do nothing for MS SQL Server (cause it requires stored procedures etc)
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
package com.avaje.ebean.event.changelog;
|
||||
|
||||
import com.avaje.ebean.ValuePair;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A bean insert, update or delete change sent as part of a ChangeSet.
|
||||
*/
|
||||
public class BeanChange {
|
||||
|
||||
/**
|
||||
* The underling base table name.
|
||||
*/
|
||||
String table;
|
||||
|
||||
/**
|
||||
* The id value.
|
||||
*/
|
||||
Object id;
|
||||
|
||||
/**
|
||||
* The INSERT, UPDATE or DELETE change type.
|
||||
*/
|
||||
ChangeType type;
|
||||
|
||||
/**
|
||||
* The time the bean change was created.
|
||||
*/
|
||||
long eventTime;
|
||||
|
||||
/**
|
||||
* The values for insert or update. Note that null values are not included for insert.
|
||||
*/
|
||||
Map<String, ValuePair> values;
|
||||
|
||||
/**
|
||||
* Construct with all the details.
|
||||
*/
|
||||
public BeanChange(String table, Object id, ChangeType type, Map<String, ValuePair> values) {
|
||||
this.table = table;
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.eventTime = System.currentTimeMillis();
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor for JSON tools.
|
||||
*/
|
||||
public BeanChange() {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "table:" + table + " id:" + id + " values:" + values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object type (typically table name).
|
||||
*/
|
||||
public String getTable() {
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object type (for JSON tools).
|
||||
*/
|
||||
public void setTable(String table) {
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object id.
|
||||
*/
|
||||
public Object getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean id (for JSON tools).
|
||||
*/
|
||||
public void setId(Object id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the change type (INSERT, UPDATE or DELETE).
|
||||
*/
|
||||
public ChangeType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type (for JSON tools).
|
||||
*/
|
||||
public void setType(ChangeType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the event time in epoch millis.
|
||||
*/
|
||||
public long getEventTime() {
|
||||
return eventTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the event time in epoch millis.
|
||||
*/
|
||||
public void setEventTime(long eventTime) {
|
||||
this.eventTime = eventTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value pairs. For inserts the ValuePair oldValue is always null.
|
||||
*/
|
||||
public Map<String, ValuePair> getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value pairs (for JSON tools).
|
||||
*/
|
||||
public void setValues(Map<String, ValuePair> values) {
|
||||
this.values = values;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.avaje.ebean.util;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Helper to find classes taking into account the context class loader.
|
||||
*/
|
||||
public class ClassUtil {
|
||||
|
||||
/**
|
||||
* Returns the raw type for the 2nd generic parameter for a subclass.
|
||||
*/
|
||||
public static Class<?> getSecondArgumentType(Class<?> subclass) {
|
||||
Type[] typeArguments = getSuperclassTypeParameter(subclass);
|
||||
if (typeArguments.length != 2) {
|
||||
throw new IllegalArgumentException("Expected type with 2 generic argument types but got "
|
||||
+ typeArguments.length + " - " + Arrays.toString(typeArguments));
|
||||
}
|
||||
|
||||
return getRawType(typeArguments[1]);
|
||||
}
|
||||
|
||||
static Type[] getSuperclassTypeParameter(Class<?> subclass) {
|
||||
Type superclass = subclass.getGenericSuperclass();
|
||||
if (superclass instanceof Class) {
|
||||
throw new RuntimeException("Missing generics type parameters on subclass " + subclass);
|
||||
}
|
||||
return ((ParameterizedType) superclass).getActualTypeArguments();
|
||||
}
|
||||
|
||||
private static Class<?> getRawType(Type type) {
|
||||
|
||||
if (type instanceof Class<?>) {
|
||||
return (Class<?>) type;
|
||||
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
Type rawType = parameterizedType.getRawType();
|
||||
if (rawType instanceof Class<?>) {
|
||||
return (Class<?>) rawType;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Unable to obtain raw class type from " + type);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.autotune.service;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.autotune.AutoTuneService;
|
||||
|
||||
public class AutoTuneServiceFactory {
|
||||
|
||||
public static AutoTuneService create(SpiEbeanServer server, ServerConfig serverConfig) {
|
||||
|
||||
return new DefaultAutoTuneService(server, serverConfig);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.cache;
|
||||
@@ -1,130 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.changelog;
|
||||
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebean.event.changelog.BeanChange;
|
||||
import com.avaje.ebean.event.changelog.ChangeSet;
|
||||
import com.avaje.ebean.event.changelog.ChangeType;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Builds JSON document for a bean change.
|
||||
*/
|
||||
public class ChangeJsonBuilder {
|
||||
|
||||
protected final JsonFactory jsonFactory = new JsonFactory();
|
||||
|
||||
protected final JsonContext json;
|
||||
|
||||
protected ChangeJsonBuilder(JsonContext json) {
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the bean change as JSON.
|
||||
*/
|
||||
public void writeBeanJson(Writer writer, BeanChange bean, ChangeSet changeSet, int position) throws IOException {
|
||||
|
||||
JsonGenerator generator = jsonFactory.createGenerator(writer);
|
||||
|
||||
writeBeanChange(generator, bean, changeSet, position);
|
||||
|
||||
generator.flush();
|
||||
generator.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the bean change as JSON document containing the transaction header details.
|
||||
*/
|
||||
protected void writeBeanChange(JsonGenerator gen, BeanChange bean, ChangeSet changeSet, int position) throws IOException {
|
||||
|
||||
gen.writeStartObject();
|
||||
|
||||
writeBeanTransactionDetails(gen, changeSet, position);
|
||||
|
||||
gen.writeStringField("object", bean.getTable());
|
||||
gen.writeStringField("objectId", bean.getId().toString());
|
||||
gen.writeStringField("change", bean.getType().getCode());
|
||||
gen.writeNumberField("eventTime", bean.getEventTime());
|
||||
|
||||
writeBeanValues(gen, bean);
|
||||
|
||||
gen.writeEndObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Denormalise by writing the transaction header details.
|
||||
*/
|
||||
protected void writeBeanTransactionDetails(JsonGenerator gen, ChangeSet changeSet, int position) throws IOException {
|
||||
|
||||
gen.writeStringField("txnId", changeSet.getTxnId());
|
||||
gen.writeStringField("txnState", changeSet.getTxnState().getCode());
|
||||
gen.writeNumberField("txnBatch", changeSet.getTxnBatch());
|
||||
gen.writeNumberField("txnPosition", position);
|
||||
String source = changeSet.getSource();
|
||||
if (source != null) {
|
||||
gen.writeStringField("source", source);
|
||||
}
|
||||
String userId = changeSet.getUserId();
|
||||
if (userId != null) {
|
||||
gen.writeStringField("userId", userId);
|
||||
}
|
||||
String userIpAddress = changeSet.getUserIpAddress();
|
||||
if (userIpAddress != null) {
|
||||
gen.writeStringField("userIpAddress", userIpAddress);
|
||||
}
|
||||
Map<String, String> userContext = changeSet.getUserContext();
|
||||
if (userContext != null && !userContext.isEmpty()) {
|
||||
gen.writeObjectFieldStart("userContext");
|
||||
for (Map.Entry<String, String> entry : userContext.entrySet()) {
|
||||
gen.writeStringField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
gen.writeEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For insert and update write the new/old values.
|
||||
*/
|
||||
protected void writeBeanValues(JsonGenerator gen, BeanChange bean) throws IOException {
|
||||
|
||||
if (bean.getType() != ChangeType.DELETE) {
|
||||
gen.writeFieldName("values");
|
||||
gen.writeStartObject();
|
||||
writeValuePairs(bean, gen);
|
||||
gen.writeEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write all the value pairs suppressing null values.
|
||||
* <p>
|
||||
* We are intentionally keeping the same new/old structure for both inserts and updates.
|
||||
* </p>
|
||||
*/
|
||||
protected void writeValuePairs(BeanChange bean, JsonGenerator gen) throws IOException {
|
||||
|
||||
for (Map.Entry<String, ValuePair> entry : bean.getValues().entrySet()) {
|
||||
gen.writeFieldName(entry.getKey());
|
||||
gen.writeStartObject();
|
||||
ValuePair value = entry.getValue();
|
||||
Object newValue = value.getNewValue();
|
||||
if (newValue != null) {
|
||||
gen.writeFieldName("new");
|
||||
json.writeScalar(gen, newValue);
|
||||
}
|
||||
Object oldValue = value.getOldValue();
|
||||
if (oldValue != null) {
|
||||
gen.writeFieldName("old");
|
||||
json.writeScalar(gen, oldValue);
|
||||
}
|
||||
gen.writeEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonExecutorService;
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonScheduleThreadPool;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* The default implementation of the BackgroundExecutor.
|
||||
*/
|
||||
public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
private final DaemonScheduleThreadPool schedulePool;
|
||||
|
||||
private final DaemonExecutorService pool;
|
||||
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*/
|
||||
public DefaultBackgroundExecutor(int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = new DaemonExecutorService(shutdownWaitSeconds, namePrefix);
|
||||
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix + "-periodic-");
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a Runnable using a background thread.
|
||||
*/
|
||||
public void execute(Runnable r) {
|
||||
pool.execute(r);
|
||||
}
|
||||
|
||||
public void executePeriodically(Runnable r, long delay, TimeUnit unit) {
|
||||
schedulePool.scheduleWithFixedDelay(r, delay, delay, unit);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
pool.shutdown();
|
||||
schedulePool.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Helper to perform a diff given two beans of the same type.
|
||||
* <p>
|
||||
* This intentionally does not include any OneToMany or ManyToMany properties.
|
||||
* </p>
|
||||
*/
|
||||
public class DiffHelp {
|
||||
|
||||
private DiffHelp() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of the differences between a and b.
|
||||
* <p>
|
||||
* A and B must be of the same type. B can be null, in which case the 'dirty
|
||||
* values' of a is returned.
|
||||
* </p>
|
||||
* <p>
|
||||
* This intentionally does not include as OneToMany or ManyToMany properties.
|
||||
* </p>
|
||||
*/
|
||||
public static Map<String, ValuePair> diff(Object newBean, Object oldBean, BeanDescriptor<?> desc) {
|
||||
|
||||
if (!(newBean instanceof EntityBean)) {
|
||||
throw new IllegalArgumentException("First bean expected to be an enhanced EntityBean? bean:" + newBean);
|
||||
}
|
||||
|
||||
if (oldBean != null) {
|
||||
if (!(oldBean instanceof EntityBean)) {
|
||||
throw new IllegalArgumentException("Second bean expected to be an enhanced EntityBean? bean:" + oldBean);
|
||||
}
|
||||
if (!newBean.getClass().isAssignableFrom(oldBean.getClass())) {
|
||||
throw new IllegalArgumentException("Second bean not assignable to the first bean?");
|
||||
}
|
||||
}
|
||||
|
||||
if (oldBean == null) {
|
||||
return ((EntityBean) newBean)._ebean_getIntercept().getDirtyValues();
|
||||
}
|
||||
|
||||
return desc.diff((EntityBean) newBean, (EntityBean) oldBean);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Flattens an existing diff map converting assoc one beans into the associated id changes.
|
||||
*/
|
||||
public static Map<String, ValuePair> flatten(Map<String, ValuePair> values, BeanDescriptor<?> desc) {
|
||||
|
||||
Map<String, ValuePair> flattened = null;
|
||||
|
||||
Iterator<Map.Entry<String, ValuePair>> iterator = values.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, ValuePair> entry = iterator.next();
|
||||
BeanProperty beanProperty = desc.getBeanProperty(entry.getKey());
|
||||
if (beanProperty instanceof BeanPropertyAssocMany) {
|
||||
// filter out assoc many bean properties
|
||||
iterator.remove();
|
||||
|
||||
} else if (beanProperty instanceof BeanPropertyAssocOne) {
|
||||
BeanPropertyAssocOne<?> assoc = (BeanPropertyAssocOne<?>) beanProperty;
|
||||
if (!assoc.isEmbedded()) {
|
||||
// flatten for assoc one beans
|
||||
if (flattened == null) {
|
||||
flattened = new LinkedHashMap<>();
|
||||
}
|
||||
flattenToId(flattened, entry, beanProperty, assoc);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flattened != null) {
|
||||
values.putAll(flattened);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
private static void flattenToId(Map<String, ValuePair> flattened, Map.Entry<String, ValuePair> entry, BeanProperty beanProperty, BeanPropertyAssocOne<?> assoc) {
|
||||
|
||||
BeanDescriptor<?> oneDesc = assoc.getTargetDescriptor();
|
||||
|
||||
ValuePair value = entry.getValue();
|
||||
Object newId = value.getNewValue() == null ? null : oneDesc.getId((EntityBean) value.getNewValue());
|
||||
Object oldId = value.getOldValue() == null ? null : oneDesc.getId((EntityBean) value.getOldValue());
|
||||
|
||||
String propName = beanProperty.getName() + "." + oneDesc.getIdProperty().getName();
|
||||
flattened.put(propName, new ValuePair(newId, oldId));
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
|
||||
/**
|
||||
* Used to temporarily wrap a thread local based transaction.
|
||||
* <p>
|
||||
* Additionally notes if the transaction was created by the request in which
|
||||
* case it needs to be commited after the request has been processed.
|
||||
* </p>
|
||||
*/
|
||||
final class TransWrapper {
|
||||
|
||||
final SpiTransaction transaction;
|
||||
|
||||
private final boolean wasCreated;
|
||||
|
||||
/**
|
||||
* Wrap the transaction indicating if it was just created.
|
||||
*/
|
||||
TransWrapper(SpiTransaction t, boolean created) {
|
||||
transaction = t;
|
||||
wasCreated = created;
|
||||
}
|
||||
|
||||
void batchEscalateOnCollection() {
|
||||
transaction.checkBatchEscalationOnCollection();
|
||||
}
|
||||
|
||||
void flushBatchOnCollection() {
|
||||
if (!wasCreated) {
|
||||
transaction.flushBatchOnCollection();
|
||||
}
|
||||
}
|
||||
|
||||
void commitIfCreated() {
|
||||
if (wasCreated) {
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
void rollbackIfCreated() {
|
||||
if (wasCreated) {
|
||||
transaction.rollbackIfActive();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the transaction was just created. If true it should be
|
||||
* committed after the request has been processed.
|
||||
*/
|
||||
boolean wasCreated() {
|
||||
return wasCreated;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Used for associated beans in place of a BeanDescriptor. This is done to avoid
|
||||
* recursion issues due to the potentially bi-directional and circular
|
||||
* relationships between beans.
|
||||
* <p>
|
||||
* It holds the main deployment information and not all the detail that is held
|
||||
* in a BeanDescriptor.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanTable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BeanTable.class);
|
||||
|
||||
private final BeanDescriptorMap owner;
|
||||
|
||||
private final Class<?> beanType;
|
||||
|
||||
/**
|
||||
* The base table.
|
||||
*/
|
||||
private final String baseTable;
|
||||
|
||||
private final BeanProperty[] idProperties;
|
||||
|
||||
/**
|
||||
* Create the BeanTable.
|
||||
*/
|
||||
public BeanTable(DeployBeanTable mutable, BeanDescriptorMap owner) {
|
||||
this.owner = owner;
|
||||
this.beanType = mutable.getBeanType();
|
||||
this.baseTable = InternString.intern(mutable.getBaseTable());
|
||||
this.idProperties = mutable.createIdProperties(owner);
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return baseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base table for this BeanTable.
|
||||
* This is used to determine the join information
|
||||
* for associations.
|
||||
*/
|
||||
public String getBaseTable() {
|
||||
return baseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unqualified base table.
|
||||
*
|
||||
* @return the unqualified base table
|
||||
*/
|
||||
public String getUnqualifiedBaseTable(){
|
||||
final String[] chunks = baseTable.split("\\.");
|
||||
return chunks.length == 2 ? chunks[1] :chunks[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Id properties.
|
||||
*/
|
||||
public BeanProperty[] getIdProperties() {
|
||||
return idProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class for this beanTable.
|
||||
*/
|
||||
public Class<?> getBeanType() {
|
||||
return beanType;
|
||||
}
|
||||
|
||||
public void createJoinColumn(String foreignKeyPrefix, DeployTableJoin join, boolean reverse, String sqlFormulaSelect) {
|
||||
|
||||
boolean complexKey = false;
|
||||
BeanProperty[] props = idProperties;
|
||||
|
||||
if (idProperties.length == 1){
|
||||
if (idProperties[0] instanceof BeanPropertyAssocOne<?>) {
|
||||
BeanPropertyAssocOne<?> assocOne = (BeanPropertyAssocOne<?>)idProperties[0];
|
||||
props = assocOne.getProperties();
|
||||
complexKey = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (BeanProperty prop : props) {
|
||||
|
||||
String lc = prop.getDbColumn();
|
||||
String fk = lc;
|
||||
if (foreignKeyPrefix != null) {
|
||||
fk = owner.getNamingConvention().getForeignKey(foreignKeyPrefix, fk);
|
||||
}
|
||||
|
||||
if (complexKey) {
|
||||
// just to copy the column name rather than prefix with the foreignKeyPrefix.
|
||||
// I think that with complex keys this is the more common approach.
|
||||
logger.debug("On table[{}] foreign key column [{}]", baseTable, lc);
|
||||
fk = lc;
|
||||
}
|
||||
if (sqlFormulaSelect != null) {
|
||||
fk = sqlFormulaSelect;
|
||||
}
|
||||
|
||||
DeployTableJoinColumn joinCol = new DeployTableJoinColumn(lc, fk);
|
||||
joinCol.setForeignSqlFormula(sqlFormulaSelect);
|
||||
if (reverse) {
|
||||
joinCol = joinCol.reverse();
|
||||
}
|
||||
join.addJoinColumn(joinCol);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-185
@@ -1,185 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebean.event.BeanPersistRequest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Chains multiple BeanPersistController's together.
|
||||
*
|
||||
* Used when multiple BeanPersistController register for the same bean type.
|
||||
*/
|
||||
public class ChainedBeanPersistController implements BeanPersistController {
|
||||
|
||||
private static final Sorter SORTER = new Sorter();
|
||||
|
||||
private final List<BeanPersistController> list;
|
||||
|
||||
private final BeanPersistController[] chain;
|
||||
|
||||
/**
|
||||
* Construct adding 2 BeanPersistController's.
|
||||
*/
|
||||
public ChainedBeanPersistController(BeanPersistController c1, BeanPersistController c2) {
|
||||
this(addList(c1, c2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method used to create a list from 2 BeanPersistController's.
|
||||
*/
|
||||
private static List<BeanPersistController> addList(BeanPersistController c1, BeanPersistController c2) {
|
||||
ArrayList<BeanPersistController> addList = new ArrayList<>(2);
|
||||
addList.add(c1);
|
||||
addList.add(c2);
|
||||
return addList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct given the list of BeanPersistController's.
|
||||
*/
|
||||
public ChainedBeanPersistController(List<BeanPersistController> list) {
|
||||
this.list = list;
|
||||
BeanPersistController[] c = list.toArray(new BeanPersistController[list.size()]);
|
||||
Arrays.sort(c, SORTER);
|
||||
this.chain = c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the chain.
|
||||
*/
|
||||
protected int size() {
|
||||
return chain.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new BeanPersistController and return the resulting chain.
|
||||
*/
|
||||
public ChainedBeanPersistController register(BeanPersistController c) {
|
||||
if (list.contains(c)){
|
||||
return this;
|
||||
} else {
|
||||
ArrayList<BeanPersistController> newList = new ArrayList<>();
|
||||
newList.addAll(list);
|
||||
newList.add(c);
|
||||
|
||||
return new ChainedBeanPersistController(newList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* De-register a BeanPersistController and return the resulting chain.
|
||||
*/
|
||||
public ChainedBeanPersistController deregister(BeanPersistController c) {
|
||||
if (!list.contains(c)){
|
||||
return this;
|
||||
} else {
|
||||
ArrayList<BeanPersistController> newList = new ArrayList<>();
|
||||
newList.addAll(list);
|
||||
newList.remove(c);
|
||||
|
||||
return new ChainedBeanPersistController(newList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns 0 (not used for this object).
|
||||
*/
|
||||
@Override
|
||||
public int getExecutionOrder() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns false (not used for this object).
|
||||
*/
|
||||
@Override
|
||||
public boolean isRegisterFor(Class<?> cls) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDelete(BeanPersistRequest<?> request) {
|
||||
for (BeanPersistController aChain : chain) {
|
||||
aChain.postDelete(request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInsert(BeanPersistRequest<?> request) {
|
||||
for (BeanPersistController aChain : chain) {
|
||||
aChain.postInsert(request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postUpdate(BeanPersistRequest<?> request) {
|
||||
for (BeanPersistController aChain : chain) {
|
||||
aChain.postUpdate(request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postSoftDelete(BeanPersistRequest<?> request) {
|
||||
for (BeanPersistController aChain : chain) {
|
||||
aChain.postSoftDelete(request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preDelete(BeanPersistRequest<?> request) {
|
||||
for (BeanPersistController aChain : chain) {
|
||||
if (!aChain.preDelete(request)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preSoftDelete(BeanPersistRequest<?> request) {
|
||||
for (BeanPersistController aChain : chain) {
|
||||
if (!aChain.preSoftDelete(request)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preInsert(BeanPersistRequest<?> request) {
|
||||
for (BeanPersistController aChain : chain) {
|
||||
if (!aChain.preInsert(request)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preUpdate(BeanPersistRequest<?> request) {
|
||||
for (BeanPersistController aChain : chain) {
|
||||
if (!aChain.preUpdate(request)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to order the BeanPersistController's in a chain.
|
||||
*/
|
||||
private static class Sorter implements Comparator<BeanPersistController> {
|
||||
|
||||
public int compare(BeanPersistController o1, BeanPersistController o2) {
|
||||
|
||||
int i1 = o1.getExecutionOrder() ;
|
||||
int i2 = o2.getExecutionOrder() ;
|
||||
return (i1<i2 ? -1 : (i1==i2 ? 0 : 1));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.event.BeanPersistListener;
|
||||
|
||||
/**
|
||||
* Handles multiple BeanPersistListener's for a given entity type.
|
||||
*/
|
||||
public class ChainedBeanPersistListener implements BeanPersistListener {
|
||||
|
||||
private final List<BeanPersistListener> list;
|
||||
|
||||
private final BeanPersistListener[] chain;
|
||||
|
||||
/**
|
||||
* Construct adding 2 BeanPersistListener's.
|
||||
*/
|
||||
ChainedBeanPersistListener(BeanPersistListener c1, BeanPersistListener c2) {
|
||||
this(addList(c1, c2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the chain.
|
||||
*/
|
||||
protected int size() {
|
||||
return chain.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegisterFor(Class<?> cls) {
|
||||
// never called
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method used to create a list from 2 BeanPersistListener.
|
||||
*/
|
||||
private static List<BeanPersistListener> addList(BeanPersistListener c1, BeanPersistListener c2) {
|
||||
ArrayList<BeanPersistListener> addList = new ArrayList<>(2);
|
||||
addList.add(c1);
|
||||
addList.add(c2);
|
||||
return addList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct given the list of BeanPersistListener's.
|
||||
*/
|
||||
public ChainedBeanPersistListener(List<BeanPersistListener> list) {
|
||||
this.list = list;
|
||||
this.chain = list.toArray(new BeanPersistListener[list.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new BeanPersistListener and return the resulting chain.
|
||||
*/
|
||||
public ChainedBeanPersistListener register(BeanPersistListener c) {
|
||||
if (list.contains(c)){
|
||||
return this;
|
||||
} else {
|
||||
List<BeanPersistListener> newList = new ArrayList<>();
|
||||
newList.addAll(list);
|
||||
newList.add(c);
|
||||
|
||||
return new ChainedBeanPersistListener(newList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* De-register a BeanPersistListener and return the resulting chain.
|
||||
*/
|
||||
public ChainedBeanPersistListener deregister(BeanPersistListener c) {
|
||||
if (!list.contains(c)){
|
||||
return this;
|
||||
} else {
|
||||
ArrayList<BeanPersistListener> newList = new ArrayList<>();
|
||||
newList.addAll(list);
|
||||
newList.remove(c);
|
||||
|
||||
return new ChainedBeanPersistListener(newList);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleted(Object bean) {
|
||||
for (BeanPersistListener aChain : chain) {
|
||||
aChain.deleted(bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void softDeleted(Object bean) {
|
||||
for (BeanPersistListener aChain : chain) {
|
||||
aChain.softDeleted(bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void inserted(Object bean) {
|
||||
for (BeanPersistListener aChain : chain) {
|
||||
aChain.inserted(bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void updated(Object bean, Set<String> updatedProperties) {
|
||||
for (BeanPersistListener aChain : chain) {
|
||||
aChain.updated(bean, updatedProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.event.BeanPostLoad;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Handles multiple BeanPostLoad's for a given entity type.
|
||||
*/
|
||||
public class ChainedBeanPostLoad implements BeanPostLoad {
|
||||
|
||||
private final List<BeanPostLoad> list;
|
||||
|
||||
private final BeanPostLoad[] chain;
|
||||
|
||||
/**
|
||||
* Construct given the list of BeanPostLoad's.
|
||||
*/
|
||||
public ChainedBeanPostLoad(List<BeanPostLoad> list) {
|
||||
this.list = list;
|
||||
this.chain = list.toArray(new BeanPostLoad[list.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new BeanPostLoad and return the resulting chain.
|
||||
*/
|
||||
public ChainedBeanPostLoad register(BeanPostLoad c) {
|
||||
if (list.contains(c)){
|
||||
return this;
|
||||
} else {
|
||||
List<BeanPostLoad> newList = new ArrayList<>();
|
||||
newList.addAll(list);
|
||||
newList.add(c);
|
||||
|
||||
return new ChainedBeanPostLoad(newList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* De-register a BeanPostLoad and return the resulting chain.
|
||||
*/
|
||||
public ChainedBeanPostLoad deregister(BeanPostLoad c) {
|
||||
if (!list.contains(c)){
|
||||
return this;
|
||||
} else {
|
||||
ArrayList<BeanPostLoad> newList = new ArrayList<>();
|
||||
newList.addAll(list);
|
||||
newList.remove(c);
|
||||
|
||||
return new ChainedBeanPostLoad(newList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the chain.
|
||||
*/
|
||||
protected int size() {
|
||||
return chain.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegisterFor(Class<?> cls) {
|
||||
// never called
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire postLoad on all registered BeanPostLoad implementations.
|
||||
*/
|
||||
@Override
|
||||
public void postLoad(Object bean) {
|
||||
for (BeanPostLoad aChain : chain) {
|
||||
aChain.postLoad(bean);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
|
||||
/**
|
||||
* Handles multiple BeanQueryAdapter for a given entity type.
|
||||
*/
|
||||
public class ChainedBeanQueryAdapter implements BeanQueryAdapter {
|
||||
|
||||
private static final Sorter SORTER = new Sorter();
|
||||
|
||||
private final List<BeanQueryAdapter> list;
|
||||
|
||||
private final BeanQueryAdapter[] chain;
|
||||
|
||||
/**
|
||||
* Construct given the list of BeanQueryAdapter's.
|
||||
*/
|
||||
public ChainedBeanQueryAdapter(List<BeanQueryAdapter> list) {
|
||||
this.list = list;
|
||||
BeanQueryAdapter[] c = list.toArray(new BeanQueryAdapter[list.size()]);
|
||||
Arrays.sort(c, SORTER);
|
||||
this.chain = c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new BeanQueryAdapter and return the resulting chain.
|
||||
*/
|
||||
public ChainedBeanQueryAdapter register(BeanQueryAdapter c) {
|
||||
if (list.contains(c)){
|
||||
return this;
|
||||
} else {
|
||||
List<BeanQueryAdapter> newList = new ArrayList<>();
|
||||
newList.addAll(list);
|
||||
newList.add(c);
|
||||
|
||||
return new ChainedBeanQueryAdapter(newList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* De-register a BeanQueryAdapter and return the resulting chain.
|
||||
*/
|
||||
public ChainedBeanQueryAdapter deregister(BeanQueryAdapter c) {
|
||||
if (!list.contains(c)){
|
||||
return this;
|
||||
} else {
|
||||
ArrayList<BeanQueryAdapter> newList = new ArrayList<>();
|
||||
newList.addAll(list);
|
||||
newList.remove(c);
|
||||
|
||||
return new ChainedBeanQueryAdapter(newList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return 0 as not used by this Chained adapter.
|
||||
*/
|
||||
public int getExecutionOrder() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false as only individual adapters are registered.
|
||||
*/
|
||||
public boolean isRegisterFor(Class<?> cls) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void preQuery(BeanQueryRequest<?> request) {
|
||||
|
||||
for (BeanQueryAdapter aChain : chain) {
|
||||
aChain.preQuery(request);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Helper to order the BeanQueryAdapter's in a chain.
|
||||
*/
|
||||
private static class Sorter implements Comparator<BeanQueryAdapter> {
|
||||
|
||||
public int compare(BeanQueryAdapter o1, BeanQueryAdapter o2) {
|
||||
|
||||
int i1 = o1.getExecutionOrder() ;
|
||||
int i2 = o2.getExecutionOrder() ;
|
||||
return (i1<i2 ? -1 : (i1==i2 ? 0 : 1));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Converts logical property names to database columns.
|
||||
*/
|
||||
public abstract class DeployParser {
|
||||
|
||||
/**
|
||||
* used to identify sql literal.
|
||||
*/
|
||||
protected static final char SINGLE_QUOTE = '\'';
|
||||
|
||||
/**
|
||||
* used to identify query named parameters.
|
||||
*/
|
||||
protected static final char COLON = ':';
|
||||
|
||||
/**
|
||||
* Used to determine when a column name terminates.
|
||||
*/
|
||||
protected static final char UNDERSCORE = '_';
|
||||
|
||||
/**
|
||||
* Used to determine when a column name terminates.
|
||||
*/
|
||||
protected static final char PERIOD = '.';
|
||||
|
||||
protected boolean encrypted;
|
||||
|
||||
protected String source;
|
||||
|
||||
protected StringBuilder sb;
|
||||
|
||||
protected int sourceLength;
|
||||
|
||||
protected int pos;
|
||||
|
||||
protected String word;
|
||||
|
||||
protected char wordTerminator;
|
||||
|
||||
protected abstract String convertWord();
|
||||
|
||||
public abstract String getDeployWord(String expression);
|
||||
|
||||
|
||||
/**
|
||||
* Return the join includes.
|
||||
*/
|
||||
public abstract Set<String> getIncludes();
|
||||
|
||||
public void setEncrypted(boolean encrypted) {
|
||||
this.encrypted = encrypted;
|
||||
}
|
||||
|
||||
public String parse(String source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
pos = -1;
|
||||
this.source = source;
|
||||
this.sourceLength = source.length();
|
||||
this.sb = new StringBuilder(source.length() + 20);
|
||||
|
||||
while (nextWord()) {
|
||||
String deployWord = convertWord();
|
||||
sb.append(deployWord);
|
||||
if (pos < sourceLength) {
|
||||
sb.append(wordTerminator);
|
||||
if (wordTerminator == SINGLE_QUOTE) {
|
||||
readLiteral();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private boolean nextWord() {
|
||||
|
||||
if (!findWordStart()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
StringBuilder wordBuffer = new StringBuilder();
|
||||
wordBuffer.append(source.charAt(pos));
|
||||
while (++pos < sourceLength) {
|
||||
char ch = source.charAt(pos);
|
||||
if (isWordPart(ch)) {
|
||||
wordBuffer.append(ch);
|
||||
} else {
|
||||
wordTerminator = ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
word = wordBuffer.toString();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean findWordStart() {
|
||||
while (++pos < sourceLength) {
|
||||
char ch = source.charAt(pos);
|
||||
if (ch == SINGLE_QUOTE) {
|
||||
// read a literal value and just
|
||||
// append to string builder
|
||||
sb.append(ch);
|
||||
readLiteral();
|
||||
} else if (ch == COLON) {
|
||||
// read a named parameter
|
||||
// just append to string builder
|
||||
sb.append(ch);
|
||||
readNamedParameter();
|
||||
} else if (isWordStart(ch)) {
|
||||
// its the start of a word that could
|
||||
// be translated
|
||||
return true;
|
||||
} else {
|
||||
sb.append(ch);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the rest of a literal value. These do not get translated so are just
|
||||
* read and appended to the string builder.
|
||||
*/
|
||||
private void readLiteral() {
|
||||
while (++pos < sourceLength) {
|
||||
char ch = source.charAt(pos);
|
||||
sb.append(ch);
|
||||
if (ch == SINGLE_QUOTE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a named parameter. These are not translated. They will be replaced
|
||||
* by positioned parameters later.
|
||||
*/
|
||||
private void readNamedParameter() {
|
||||
while (++pos < sourceLength) {
|
||||
char ch = source.charAt(pos);
|
||||
sb.append(ch);
|
||||
if (Character.isWhitespace(ch)) {
|
||||
break;
|
||||
} else if (ch == ',') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if the char is a letter, digit or underscore.
|
||||
*/
|
||||
private boolean isWordPart(char ch) {
|
||||
return Character.isLetterOrDigit(ch) || ch == UNDERSCORE || ch == PERIOD;
|
||||
}
|
||||
|
||||
private boolean isWordStart(char ch) {
|
||||
return Character.isLetter(ch);
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
|
||||
|
||||
/**
|
||||
* Converts logical property names to database columns with table alias.
|
||||
* <p>
|
||||
* In doing so it builds an 'includes' set which becomes the joins required to
|
||||
* support the properties parsed.
|
||||
* </p>
|
||||
*/
|
||||
public final class DeployPropertyParser extends DeployParser {
|
||||
|
||||
|
||||
private final BeanDescriptor<?> beanDescriptor;
|
||||
|
||||
private final Set<String> includes = new HashSet<>();
|
||||
|
||||
public DeployPropertyParser(BeanDescriptor<?> beanDescriptor) {
|
||||
this.beanDescriptor = beanDescriptor;
|
||||
}
|
||||
|
||||
public Set<String> getIncludes() {
|
||||
return includes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeployWord(String expression) {
|
||||
ElPropertyDeploy elProp = beanDescriptor.getElPropertyDeploy(expression);
|
||||
if (elProp == null){
|
||||
return null;
|
||||
} else {
|
||||
addIncludes(elProp.getElPrefix());
|
||||
return elProp.getElPlaceholder(encrypted);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertWord() {
|
||||
String r = getDeployWord(word);
|
||||
return r == null ? word : r;
|
||||
}
|
||||
|
||||
private void addIncludes(String prefix) {
|
||||
if (prefix != null){
|
||||
includes.add(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
|
||||
|
||||
/**
|
||||
* For updates converts logical property names to database columns and bean type to base table.
|
||||
*/
|
||||
public final class DeployUpdateParser extends DeployParser {
|
||||
|
||||
private final BeanDescriptor<?> beanDescriptor;
|
||||
|
||||
public DeployUpdateParser(BeanDescriptor<?> beanDescriptor) {
|
||||
this.beanDescriptor = beanDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return null as not used for updates.
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getIncludes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String convertWord() {
|
||||
|
||||
String dbWord = getDeployWord(word);
|
||||
|
||||
if (dbWord != null) {
|
||||
return dbWord;
|
||||
}
|
||||
// maybe tableAlias.propertyName
|
||||
return convertSubword(0, word, null);
|
||||
}
|
||||
|
||||
private String convertSubword(int start, String currentWord, StringBuilder localBuffer) {
|
||||
|
||||
int dotPos = currentWord.indexOf('.', start);
|
||||
if (start == 0 && dotPos == -1){
|
||||
return currentWord;
|
||||
}
|
||||
if (start == 0){
|
||||
localBuffer = new StringBuilder();
|
||||
}
|
||||
if (dotPos == -1){
|
||||
// no match...
|
||||
localBuffer.append(currentWord.substring(start));
|
||||
return localBuffer.toString();
|
||||
}
|
||||
|
||||
// append up to the dot
|
||||
localBuffer.append(currentWord.substring(start, dotPos+1));
|
||||
|
||||
if (dotPos == currentWord.length()-1){
|
||||
// ends with a "." ???
|
||||
return localBuffer.toString();
|
||||
}
|
||||
|
||||
// get the remainder after the dot
|
||||
start = dotPos+1;
|
||||
String remainder = currentWord.substring(start, currentWord.length());
|
||||
|
||||
//String dbWord = deployMap.get(remainder.toLowerCase());
|
||||
String dbWord = getDeployWord(remainder);
|
||||
if (dbWord != null){
|
||||
// we have found a match for the remainder
|
||||
localBuffer.append(dbWord);
|
||||
return localBuffer.toString();
|
||||
} else {
|
||||
//
|
||||
return convertSubword(start, currentWord, localBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
public String getDeployWord(String expression) {
|
||||
|
||||
if (expression.equalsIgnoreCase(beanDescriptor.getName())){
|
||||
return beanDescriptor.getBaseTable();
|
||||
}
|
||||
|
||||
ElPropertyDeploy elProp = beanDescriptor.getElPropertyDeploy(expression);
|
||||
if (elProp != null){
|
||||
return elProp.getDbColumn();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
/**
|
||||
* Used to visit all the InheritInfo in a single inheritance hierarchy.
|
||||
*/
|
||||
public interface InheritInfoVisitor {
|
||||
|
||||
/**
|
||||
* visit the InheritInfo for this node.
|
||||
*/
|
||||
void visit(InheritInfo inheritInfo);
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Helper object to find generic parameter types for a given class.
|
||||
*/
|
||||
public class ParamTypeUtil {
|
||||
|
||||
/**
|
||||
* Find and return the parameter type given a generic interface or class.
|
||||
* <p>
|
||||
* This assumes there is only one generic parameter.
|
||||
* </p>
|
||||
* <p>
|
||||
* Returns null if no match was found.
|
||||
* </p>
|
||||
* @param cls the class to search for the parameter type
|
||||
* @param matchType the type which has the generic parameter
|
||||
*/
|
||||
public static Class<?> findParamType(Class<?> cls, Class<?> matchType) {
|
||||
|
||||
// search for: implementing a generic interface
|
||||
Type paramType = matchByInterfaces(cls, matchType);
|
||||
if (paramType == null){
|
||||
// search for: extending a generic class
|
||||
Type genericSuperclass = cls.getGenericSuperclass();
|
||||
if (genericSuperclass != null){
|
||||
paramType = matchParamType(genericSuperclass, matchType);
|
||||
}
|
||||
}
|
||||
|
||||
if (paramType instanceof Class<?>){
|
||||
// only interested in classes
|
||||
return (Class<?>)paramType;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the type is a generic one with parameters and of the correct type we are
|
||||
* searching for. Return the parameter type if this matches otherwise return null.
|
||||
*/
|
||||
private static Type matchParamType(Type type, Class<?> matchType) {
|
||||
if (type instanceof ParameterizedType){
|
||||
ParameterizedType pt = (ParameterizedType)type;
|
||||
Type rawType = pt.getRawType();
|
||||
boolean isAssignable = matchType.isAssignableFrom((Class<?>) rawType);
|
||||
if (isAssignable) {
|
||||
// assume there is only one parameter type
|
||||
Type[] typeArguments = pt.getActualTypeArguments();
|
||||
if (typeArguments.length != 1){
|
||||
String m = "Expecting only 1 generic paramater but got "+typeArguments.length+" for "+type;
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
return typeArguments[0];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the interfaces this class implements.
|
||||
*/
|
||||
private static Type matchByInterfaces(Class<?> cls, Class<?> matchType) {
|
||||
|
||||
Type[] gis = cls.getGenericInterfaces();
|
||||
for (Type gi : gis) {
|
||||
Type match = matchParamType(gi, matchType);
|
||||
if (match != null) {
|
||||
return match;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebeaninternal.server.core.bootup.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Manages the assignment/registration of BeanPersistListener with their
|
||||
* respective DeployBeanDescriptor's.
|
||||
*/
|
||||
public class PersistListenerManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PersistListenerManager.class);
|
||||
|
||||
private final List<BeanPersistListener> list;
|
||||
|
||||
public PersistListenerManager(BootupClasses bootupClasses) {
|
||||
list = bootupClasses.getBeanPersistListeners();
|
||||
}
|
||||
|
||||
public int getRegisterCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanPersistController for a given entity type.
|
||||
*/
|
||||
public <T> void addPersistListeners(DeployBeanDescriptor<T> deployDesc) {
|
||||
|
||||
for (BeanPersistListener listener : list) {
|
||||
if (listener.isRegisterFor(deployDesc.getBeanType())) {
|
||||
logger.debug("BeanPersistListener on[{}] {}", deployDesc.getFullName(), listener.getClass().getName());
|
||||
deployDesc.addPersistListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
|
||||
<TITLE>Helpers for Id property conversion</TITLE>
|
||||
</HEAD>
|
||||
<Body BGCOLOR="#ffffff">
|
||||
Helpers for Id property conversion
|
||||
|
||||
</Body>
|
||||
</HTML>
|
||||
-150
@@ -1,150 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanCascadeInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
|
||||
/**
|
||||
* Abstract base for properties mapped to an associated bean, list, set or map.
|
||||
*/
|
||||
public abstract class DeployBeanPropertyAssoc<T> extends DeployBeanProperty {
|
||||
|
||||
/**
|
||||
* The type of the joined bean.
|
||||
*/
|
||||
protected Class<T> targetType;
|
||||
|
||||
/**
|
||||
* Persist settings.
|
||||
*/
|
||||
private final BeanCascadeInfo cascadeInfo = new BeanCascadeInfo();
|
||||
|
||||
/**
|
||||
* The join table information.
|
||||
*/
|
||||
private BeanTable beanTable;
|
||||
|
||||
/**
|
||||
* Join between the beans.
|
||||
*/
|
||||
protected final DeployTableJoin tableJoin = new DeployTableJoin();
|
||||
|
||||
/**
|
||||
* Literal added to where clause of lazy loading query.
|
||||
*/
|
||||
private String extraWhere;
|
||||
|
||||
/**
|
||||
* From the deployment mappedBy attribute.
|
||||
*/
|
||||
private String mappedBy;
|
||||
|
||||
private String docStoreDoc;
|
||||
|
||||
/**
|
||||
* Construct the property.
|
||||
*/
|
||||
DeployBeanPropertyAssoc(DeployBeanDescriptor<?> desc, Class<T> targetType) {
|
||||
super(desc, targetType, null, null);
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the target DeployBeanDescriptor for this associated bean property.
|
||||
*/
|
||||
public DeployBeanDescriptor<?> getTargetDeploy() {
|
||||
return desc.getDeploy(targetType).getDescriptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of the target.
|
||||
* <p>
|
||||
* This is the class of the associated bean, or beans contained in a list,
|
||||
* set or map.
|
||||
* </p>
|
||||
*/
|
||||
public Class<T> getTargetType() {
|
||||
return targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a literal expression that is added to the query that lazy loads
|
||||
* the collection.
|
||||
*/
|
||||
public String getExtraWhere() {
|
||||
return extraWhere;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a literal expression to add to the query that lazy loads the
|
||||
* collection.
|
||||
*/
|
||||
public void setExtraWhere(String extraWhere) {
|
||||
this.extraWhere = extraWhere;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the join to use for the bean.
|
||||
*/
|
||||
public DeployTableJoin getTableJoin() {
|
||||
return tableJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanTable for this association.
|
||||
* <p>
|
||||
* This has the table name which is used to determine the relationship for
|
||||
* this association.
|
||||
* </p>
|
||||
*/
|
||||
public BeanTable getBeanTable() {
|
||||
return beanTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean table.
|
||||
*/
|
||||
public void setBeanTable(BeanTable beanTable) {
|
||||
this.beanTable = beanTable;
|
||||
getTableJoin().setTable(beanTable.getBaseTable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the persist info.
|
||||
*/
|
||||
public BeanCascadeInfo getCascadeInfo() {
|
||||
return cascadeInfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the mappedBy deployment attribute.
|
||||
* <p>
|
||||
* This is the name of the property in the 'detail' bean that maps back to
|
||||
* this 'master' bean.
|
||||
* </p>
|
||||
*/
|
||||
public String getMappedBy() {
|
||||
return mappedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set mappedBy deployment attribute.
|
||||
*/
|
||||
public void setMappedBy(String mappedBy) {
|
||||
if (!"".equals(mappedBy)) {
|
||||
this.mappedBy = mappedBy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set DocStoreEmbedded deployment information.
|
||||
*/
|
||||
public void setDocStoreEmbedded(String embeddedDoc) {
|
||||
this.docStoreDoc = embeddedDoc;
|
||||
}
|
||||
|
||||
public String getDocStoreDoc() {
|
||||
return docStoreDoc;
|
||||
}
|
||||
|
||||
}
|
||||
-209
@@ -1,209 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection.ModifyListenMode;
|
||||
import com.avaje.ebeaninternal.server.deploy.ManyType;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
|
||||
/**
|
||||
* Property mapped to a List Set or Map.
|
||||
*/
|
||||
public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
|
||||
|
||||
/**
|
||||
* The type of the many, set, list or map.
|
||||
*/
|
||||
final ManyType manyType;
|
||||
|
||||
ModifyListenMode modifyListenMode = ModifyListenMode.NONE;
|
||||
|
||||
/**
|
||||
* Flag to indicate manyToMany relationship.
|
||||
*/
|
||||
boolean manyToMany;
|
||||
|
||||
/**
|
||||
* Flag to indicate this is a unidirectional relationship.
|
||||
*/
|
||||
boolean unidirectional;
|
||||
|
||||
/**
|
||||
* Join for manyToMany intersection table.
|
||||
*/
|
||||
DeployTableJoin intersectionJoin;
|
||||
|
||||
/**
|
||||
* For ManyToMany this is the Inverse join used to build reference queries.
|
||||
*/
|
||||
DeployTableJoin inverseJoin;
|
||||
|
||||
String fetchOrderBy;
|
||||
|
||||
String mapKey;
|
||||
|
||||
String intersectionDraftTable;
|
||||
|
||||
/**
|
||||
* Create this property.
|
||||
*/
|
||||
public DeployBeanPropertyAssocMany(DeployBeanDescriptor<?> desc, Class<T> targetType, ManyType manyType) {
|
||||
super(desc, targetType);
|
||||
this.manyType = manyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* When generics is not used for manyType you can specify via annotations.
|
||||
* <p>
|
||||
* Really only expect this for Scala due to a Scala compiler bug at the moment.
|
||||
* Otherwise I'd probably not bother support this.
|
||||
* </p>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setTargetType(Class<?> cls){
|
||||
this.targetType = (Class<T>)cls;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the many type.
|
||||
*/
|
||||
public ManyType getManyType() {
|
||||
return manyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is many to many.
|
||||
*/
|
||||
public boolean isManyToMany() {
|
||||
return manyToMany;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is a many to many.
|
||||
*/
|
||||
public void setManyToMany() {
|
||||
this.manyToMany = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mode for listening to changes to the List Set or Map.
|
||||
*/
|
||||
public ModifyListenMode getModifyListenMode() {
|
||||
return modifyListenMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mode for listening to changes to the List Set or Map.
|
||||
*/
|
||||
public void setModifyListenMode(ModifyListenMode modifyListenMode) {
|
||||
this.modifyListenMode = modifyListenMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a unidirectional relationship.
|
||||
*/
|
||||
public boolean isUnidirectional() {
|
||||
return unidirectional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is a unidirectional relationship.
|
||||
*/
|
||||
public void setUnidirectional() {
|
||||
this.unidirectional = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the immutable version of the intersection join.
|
||||
*/
|
||||
public TableJoin createIntersectionTableJoin() {
|
||||
if (intersectionJoin != null){
|
||||
return new TableJoin(intersectionJoin);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the immutable version of the inverse join.
|
||||
*/
|
||||
public TableJoin createInverseTableJoin() {
|
||||
if (inverseJoin != null){
|
||||
return new TableJoin(inverseJoin);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ManyToMany only, join from local table to intersection table.
|
||||
*/
|
||||
public DeployTableJoin getIntersectionJoin() {
|
||||
return intersectionJoin;
|
||||
}
|
||||
|
||||
public DeployTableJoin getInverseJoin() {
|
||||
return inverseJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* ManyToMany only, join from local table to intersection table.
|
||||
*/
|
||||
public void setIntersectionJoin(DeployTableJoin intersectionJoin) {
|
||||
this.intersectionJoin = intersectionJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* ManyToMany only, join from foreign table to intersection table.
|
||||
*/
|
||||
public void setInverseJoin(DeployTableJoin inverseJoin) {
|
||||
this.inverseJoin = inverseJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the order by clause used to order the fetching of the data for
|
||||
* this list, set or map.
|
||||
*/
|
||||
public String getFetchOrderBy() {
|
||||
return fetchOrderBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default mapKey when returning a Map.
|
||||
*/
|
||||
public String getMapKey() {
|
||||
return mapKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default mapKey to use when returning a Map.
|
||||
*/
|
||||
public void setMapKey(String mapKey) {
|
||||
if (mapKey != null && !mapKey.isEmpty()) {
|
||||
this.mapKey = mapKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the order by clause used to order the fetching or the data for this
|
||||
* list, set or map.
|
||||
*/
|
||||
public void setFetchOrderBy(String orderBy) {
|
||||
if (orderBy != null && !orderBy.isEmpty()) {
|
||||
fetchOrderBy = orderBy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a draft table for intersection between 2 @Draftable entities.
|
||||
*/
|
||||
public String getIntersectionDraftTable() {
|
||||
return (intersectionDraftTable != null) ? intersectionDraftTable : intersectionJoin.getTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* ManyToMany between 2 @Draftable entities to also need draft intersection table.
|
||||
*/
|
||||
public void setIntersectionDraftTable() {
|
||||
this.intersectionDraftTable = intersectionJoin.getTable()+"_draft";
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorMap;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
|
||||
|
||||
/**
|
||||
* Used for associated beans in place of a BeanDescriptor. This is done to avoid
|
||||
* recursion issues due to the potentially bi-directional and circular
|
||||
* relationships between beans.
|
||||
* <p>
|
||||
* It holds the main deployment information and not all the detail that is held
|
||||
* in a BeanDescriptor.
|
||||
* </p>
|
||||
*/
|
||||
public class DeployBeanTable {
|
||||
|
||||
private final Class<?> beanType;
|
||||
|
||||
/**
|
||||
* The base table.
|
||||
*/
|
||||
private String baseTable;
|
||||
|
||||
private List<DeployBeanProperty> idProperties;
|
||||
|
||||
/**
|
||||
* Create the BeanTable.
|
||||
*/
|
||||
public DeployBeanTable(Class<?> beanType) {
|
||||
this.beanType = beanType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base table for this BeanTable.
|
||||
* This is used to determine the join information
|
||||
* for associations.
|
||||
*/
|
||||
public String getBaseTable() {
|
||||
return baseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the base table for this BeanTable.
|
||||
*/
|
||||
public void setBaseTable(String baseTable) {
|
||||
this.baseTable = baseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the id properties.
|
||||
*/
|
||||
public BeanProperty[] createIdProperties(BeanDescriptorMap owner) {
|
||||
BeanProperty[] props = new BeanProperty[idProperties.size()];
|
||||
for (int i = 0; i < idProperties.size(); i++) {
|
||||
props[i] = createProperty(owner, idProperties.get(i));
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private BeanProperty createProperty(BeanDescriptorMap owner, DeployBeanProperty prop){
|
||||
|
||||
if (prop instanceof DeployBeanPropertyAssocOne<?>){
|
||||
return new BeanPropertyAssocOne(owner, (DeployBeanPropertyAssocOne<?>)prop);
|
||||
|
||||
} else {
|
||||
return new BeanProperty(prop);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Id properties.
|
||||
*/
|
||||
public void setIdProperties(List<DeployBeanProperty> idProperties) {
|
||||
this.idProperties = idProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class for this beanTable.
|
||||
*/
|
||||
public Class<?> getBeanType() {
|
||||
return beanType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
|
||||
/**
|
||||
* A join pair of local and foreign properties.
|
||||
*/
|
||||
public class DeployTableJoinColumn {
|
||||
|
||||
/**
|
||||
* The local database column name.
|
||||
*/
|
||||
String localDbColumn;
|
||||
|
||||
/**
|
||||
* SQL formula used for local column
|
||||
*/
|
||||
String localSqlFormula;
|
||||
|
||||
/**
|
||||
* The foreign database column name.
|
||||
*/
|
||||
String foreignDbColumn;
|
||||
|
||||
/**
|
||||
* SQL formula used for foreign column
|
||||
*/
|
||||
String foreignSqlFormula;
|
||||
|
||||
boolean insertable;
|
||||
|
||||
boolean updateable;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Construct when automatically determining the join.
|
||||
* <p>
|
||||
* Assume that we want the foreign key to be insertable and updateable.
|
||||
* </p>
|
||||
*/
|
||||
public DeployTableJoinColumn(String localDbColumn, String foreignDbColumn) {
|
||||
this(localDbColumn, foreignDbColumn, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with explicit insertable and updateable flags.
|
||||
*/
|
||||
public DeployTableJoinColumn(String localDbColumn, String foreignDbColumn, boolean insertable, boolean updateable) {
|
||||
this.localDbColumn = nullEmptyString(localDbColumn);
|
||||
this.foreignDbColumn = nullEmptyString(foreignDbColumn);
|
||||
this.insertable = insertable;
|
||||
this.updateable = updateable;
|
||||
}
|
||||
|
||||
public void setLocalSqlFormula(String localSqlFormula) {
|
||||
if (localSqlFormula != null) {
|
||||
this.localSqlFormula = localSqlFormula;
|
||||
this.localDbColumn = null;
|
||||
this.insertable = false;
|
||||
this.updateable = false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getLocalSqlFormula() {
|
||||
return localSqlFormula;
|
||||
}
|
||||
|
||||
public void setForeignSqlFormula(String foreignSqlFormula) {
|
||||
if (foreignSqlFormula != null) {
|
||||
this.foreignSqlFormula = foreignSqlFormula;
|
||||
this.foreignDbColumn = null;
|
||||
this.insertable = false;
|
||||
this.updateable = false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getForeignSqlFormula() {
|
||||
return foreignSqlFormula;
|
||||
}
|
||||
|
||||
|
||||
public DeployTableJoinColumn(boolean order, JoinColumn jc, BeanTable beanTable) {
|
||||
this(jc.referencedColumnName(), jc.name(), jc.insertable(), jc.updatable());
|
||||
setReferencedColumn(beanTable);
|
||||
if (!order){
|
||||
reverse();
|
||||
}
|
||||
}
|
||||
|
||||
private void setReferencedColumn(BeanTable beanTable){
|
||||
if (localDbColumn == null){
|
||||
BeanProperty[] idProperties = beanTable.getIdProperties();
|
||||
if (idProperties.length == 1){
|
||||
localDbColumn = idProperties[0].getDbColumn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the direction of the join.
|
||||
*/
|
||||
public DeployTableJoinColumn reverse() {
|
||||
String temp = localDbColumn;
|
||||
localDbColumn = foreignDbColumn;
|
||||
foreignDbColumn = temp;
|
||||
|
||||
temp = localSqlFormula;
|
||||
localSqlFormula = foreignSqlFormula;
|
||||
foreignSqlFormula = temp;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to null out empty strings.
|
||||
*/
|
||||
private String nullEmptyString(String s){
|
||||
if ("".equals(s)){
|
||||
return null;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
public DeployTableJoinColumn copy(boolean reverse) {
|
||||
// Note that the insertable and updateable are just copied
|
||||
// which may not always be the correct thing to do
|
||||
// but will leave it like this for now
|
||||
DeployTableJoinColumn ret;
|
||||
if (reverse){
|
||||
ret = new DeployTableJoinColumn(foreignDbColumn, localDbColumn, insertable, updateable);
|
||||
ret.setLocalSqlFormula(foreignSqlFormula);
|
||||
ret.setForeignSqlFormula(localSqlFormula);
|
||||
|
||||
} else {
|
||||
ret = new DeployTableJoinColumn(localDbColumn, foreignDbColumn, insertable, updateable);
|
||||
ret.setLocalSqlFormula(localSqlFormula);
|
||||
ret.setForeignSqlFormula(foreignSqlFormula);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return localDbColumn + " = " + foreignDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this column should be insertable.
|
||||
*/
|
||||
public boolean isInsertable() {
|
||||
return insertable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this column should be updateable.
|
||||
*/
|
||||
public boolean isUpdateable() {
|
||||
return updateable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign database column name.
|
||||
*/
|
||||
public String getForeignDbColumn() {
|
||||
return foreignDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the local database column name.
|
||||
*/
|
||||
public String getLocalDbColumn() {
|
||||
return localDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the local database column name.
|
||||
*/
|
||||
public void setLocalDbColumn(String localDbColumn) {
|
||||
this.localDbColumn = localDbColumn;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
|
||||
<title>Temporary objects used to collect deployment information</title>
|
||||
</head>
|
||||
<body BGCOLOR="#ffffff">
|
||||
Temporary objects used to collect deployment information
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,14 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
|
||||
<title>Bean description</title>
|
||||
</head>
|
||||
<body BGCOLOR="#ffffff">
|
||||
Bean description
|
||||
|
||||
<p>
|
||||
Describes beans with their properties and configuration.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,92 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import com.avaje.ebean.RawSql;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Wraps information about a bean during deployment parsing.
|
||||
*/
|
||||
public class DeployBeanInfo<T> {
|
||||
|
||||
/**
|
||||
* Holds TableJoins for secondary table properties.
|
||||
*/
|
||||
private final HashMap<String,DeployTableJoin> tableJoinMap = new HashMap<>();
|
||||
|
||||
private final DeployUtil util;
|
||||
|
||||
private final DeployBeanDescriptor<T> descriptor;
|
||||
|
||||
/**
|
||||
* Create with a DeployUtil and BeanDescriptor.
|
||||
*/
|
||||
public DeployBeanInfo(DeployUtil util, DeployBeanDescriptor<T> descriptor) {
|
||||
this.util = util;
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ""+descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor currently being processed.
|
||||
*/
|
||||
public DeployBeanDescriptor<T> getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DeployUtil we are using.
|
||||
*/
|
||||
public DeployUtil getUtil() {
|
||||
return util;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appropriate TableJoin for a property mapped to a secondary table.
|
||||
*/
|
||||
public DeployTableJoin getTableJoin(String tableName) {
|
||||
|
||||
String key = tableName.toLowerCase();
|
||||
|
||||
DeployTableJoin tableJoin = tableJoinMap.get(key);
|
||||
if (tableJoin == null) {
|
||||
tableJoin = new DeployTableJoin();
|
||||
tableJoin.setTable(tableName);
|
||||
tableJoin.setType(SqlJoinType.INNER);
|
||||
descriptor.addTableJoin(tableJoin);
|
||||
|
||||
tableJoinMap.put(key, tableJoin);
|
||||
}
|
||||
return tableJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a the join alias for a assoc one property.
|
||||
*/
|
||||
public void setBeanJoinType(DeployBeanPropertyAssocOne<?> beanProp, boolean outerJoin) {
|
||||
|
||||
DeployTableJoin tableJoin = beanProp.getTableJoin();
|
||||
tableJoin.setType(outerJoin ? SqlJoinType.OUTER : SqlJoinType.INNER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add named RawSql from ebean.xml.
|
||||
*/
|
||||
public void addRawSql(String name, RawSql rawSql) {
|
||||
descriptor.addRawSql(name, rawSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the named query.
|
||||
*/
|
||||
public void addNamedQuery(String name, String query) {
|
||||
descriptor.addNamedQuery(name, query);
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Keywords deemed inappropriate for use as table alias' column or table name.
|
||||
* <p>
|
||||
* That is, they might cause sql syntax errors if used.
|
||||
* </p>
|
||||
*/
|
||||
public class SqlReservedWords {
|
||||
|
||||
private static final String baseKeyWords =
|
||||
"ALIAS,ALTER,ADD,ALL,ARE,AND,ANY,ARRAY"
|
||||
+",AS,ASC,AT"
|
||||
+",AVG,BEGIN,BETWEEN,BIGINT,BINARY,BIT,BIT_LENGTH,BLOB,BOOLEAN"
|
||||
+",BOTH,BY,CALL,CALLED,CASCADE,CASCADED,CASE,CAST,CATALOG,CHAR"
|
||||
+",CHARACTER,CHECK,CLOB,CLOSE,COALESCE,COLLATE"
|
||||
+",COLLATION,COLUMN,COMMIT,CONDITION,CONNECT,CONNECTION,CONSTRAINT"
|
||||
+",CONSTRAINTS,CONSTRUCTOR,CONTAINS,CONTINUE,CONVERT"
|
||||
+",COUNT,CREATE,CROSS,CURRENT_DATE"
|
||||
+",CURRENT_PATH,CURRENT_ROLE,CURRENT_TIME,CURRENT_TIMESTAMP"
|
||||
+",CURRENT_USER,CURSOR,DATE"
|
||||
+",DAY,DEC,DECIMAL,DECLARE,DEFAULT,DELETE"
|
||||
+",DESC"
|
||||
+",DISTINCT,DO,DOUBLE,DROP,ELSE,ELSEIF,END,EQUALS"
|
||||
+",EXEC,EXIT,EXISTS,EXTRACT"
|
||||
+",FLOAT,FROM,FOR,FREE"
|
||||
+",GET,GLOBAL,GO,GOTO,GRANT,GROUP,HAVING,HOUR"
|
||||
+",IF,IN,INNER,INOUT,INSERT"
|
||||
+",INT,INTEGER,INTO,IS,JOIN"
|
||||
+",LAST,LIKE,LIMIT"
|
||||
+",MAX,MIN"
|
||||
+",NCHAR,NCLOB,NOT"
|
||||
+",NULL,NULLIF,NUMERIC,"
|
||||
+",OR,ORDER,OUTER"
|
||||
+",REAL,REF,REFERENCES"
|
||||
+",RETURN,RETURNS"
|
||||
+",SELECT,SSL"
|
||||
+",SMALLINT,"
|
||||
+",SYSTEM,SYSTEM_USER,TABLE"
|
||||
+",TO"
|
||||
+",TRIGGER,UNION,UNIQUE"
|
||||
+",UPDATE,USER,VARCHAR,VIEW,WHEN"
|
||||
+",WHERE,WITH";
|
||||
|
||||
|
||||
private static final HashSet<String> keywords = new HashSet<>();
|
||||
static {
|
||||
|
||||
String[] initialKeywords = baseKeyWords.split(",");
|
||||
for (String initialKeyword : initialKeywords) {
|
||||
keywords.add(initialKeyword.trim());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the tableAlias is a keyword.
|
||||
*/
|
||||
public static synchronized boolean isKeyword(String keyword){
|
||||
String s = keyword.trim().toUpperCase();
|
||||
return keywords.contains(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a sql keyword to the known set.
|
||||
*/
|
||||
public static synchronized void addKeyword(String keyword){
|
||||
if (keyword != null){
|
||||
keyword = keyword.trim().toUpperCase();
|
||||
if (!keyword.isEmpty()){
|
||||
keywords.add(keyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
|
||||
/**
|
||||
* Mark transient properties.
|
||||
*/
|
||||
public class TransientProperties {
|
||||
|
||||
public TransientProperties() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark any additional properties as transient.
|
||||
*/
|
||||
public void process(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
List<DeployBeanProperty> props = desc.propertiesBase();
|
||||
for (DeployBeanProperty prop : props) {
|
||||
if (!prop.isDbRead() && !prop.isDbInsertable() && !prop.isDbUpdateable()) {
|
||||
// non-transient...
|
||||
prop.setTransient();
|
||||
}
|
||||
}
|
||||
|
||||
List<DeployBeanPropertyAssocOne<?>> ones = desc.propertiesAssocOne();
|
||||
for (DeployBeanPropertyAssocOne<?> prop : ones) {
|
||||
if (prop.getBeanTable() == null) {
|
||||
if (!prop.isEmbedded()) {
|
||||
prop.setTransient();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<DeployBeanPropertyAssocMany<?>> manys = desc.propertiesAssocMany();
|
||||
for (DeployBeanPropertyAssocMany<?> prop : manys) {
|
||||
if (prop.getBeanTable() == null) {
|
||||
prop.setTransient();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<!ELEMENT ebean (table | iudextender | findextender | datasource | primarykeys | property)* >
|
||||
<!ELEMENT table EMPTY >
|
||||
<!ATTLIST table name CDATA #REQUIRED>
|
||||
<!ELEMENT iudextender EMPTY >
|
||||
<!ATTLIST iudextender classname CDATA #REQUIRED>
|
||||
<!ELEMENT findextender EMPTY >
|
||||
<!ATTLIST findextender classname CDATA #REQUIRED>
|
||||
<!ELEMENT datasource EMPTY >
|
||||
<!ATTLIST datasource name CDATA #REQUIRED>
|
||||
<!ELEMENT primarykeys EMPTY >
|
||||
<!ATTLIST primarykeys keys CDATA #REQUIRED>
|
||||
<!ELEMENT property EMPTY >
|
||||
<!ATTLIST property name CDATA #REQUIRED
|
||||
datatype CDATA #REQUIRED
|
||||
deploydatatype CDATA #IMPLIED
|
||||
deployname CDATA #IMPLIED >
|
||||
@@ -1,11 +0,0 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
|
||||
<TITLE>Deployment information parsing</TITLE>
|
||||
</HEAD>
|
||||
<Body BGCOLOR="#ffffff">
|
||||
Deployment information parsing
|
||||
|
||||
|
||||
</Body>
|
||||
</HTML>
|
||||
@@ -1 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.el;
|
||||
@@ -1,292 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utility String class that supports String manipulation functions.
|
||||
*/
|
||||
public class StringHelper {
|
||||
|
||||
/**
|
||||
* Parses out a list of Name Value pairs that are delimited together. Will
|
||||
* always return a StringMap. If allNameValuePairs is null, or no name
|
||||
* values can be parsed out an empty StringMap is returned.
|
||||
*
|
||||
* @param allNameValuePairs the entire string to be parsed.
|
||||
* @param listDelimiter (typically ';') the delimited between the list
|
||||
* @param nameValueSeparator (typically '=') the separator between the name and value
|
||||
*/
|
||||
public static Map<String, String> delimitedToMap(String allNameValuePairs,
|
||||
String listDelimiter, String nameValueSeparator) {
|
||||
|
||||
HashMap<String, String> params = new HashMap<>();
|
||||
if ((allNameValuePairs == null) || (allNameValuePairs.isEmpty())) {
|
||||
return params;
|
||||
}
|
||||
// trim off any leading listDelimiter...
|
||||
allNameValuePairs = trimFront(allNameValuePairs, listDelimiter);
|
||||
return getKeyValue(params, 0, allNameValuePairs, listDelimiter, nameValueSeparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims off recurring strings from the front of a string.
|
||||
*
|
||||
* @param source the source string
|
||||
* @param trim the string to trim off the front
|
||||
*/
|
||||
public static String trimFront(String source, String trim) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
if (source.indexOf(trim) == 0) {
|
||||
// dp("trim ...");
|
||||
return trimFront(source.substring(trim.length()), trim);
|
||||
} else {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the value is null or an empty string.
|
||||
*/
|
||||
public static boolean isNull(String value) {
|
||||
return value == null || value.trim().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively pulls out the key value pairs from a raw string.
|
||||
*/
|
||||
private static HashMap<String, String> getKeyValue(HashMap<String, String> map, int pos,
|
||||
String allNameValuePairs, String listDelimiter, String nameValueSeparator) {
|
||||
|
||||
if (pos >= allNameValuePairs.length()) {
|
||||
// dp("end as "+pos+" >= "+allNameValuePairs.length() );
|
||||
return map;
|
||||
}
|
||||
|
||||
int equalsPos = allNameValuePairs.indexOf(nameValueSeparator, pos);
|
||||
int delimPos = allNameValuePairs.indexOf(listDelimiter, pos);
|
||||
|
||||
if (delimPos == -1) {
|
||||
delimPos = allNameValuePairs.length();
|
||||
}
|
||||
if (equalsPos == -1) {
|
||||
// dp("no more equals...");
|
||||
return map;
|
||||
}
|
||||
if (delimPos == (equalsPos + 1)) {
|
||||
// dp("Ignoring as nothing between delim and equals...
|
||||
// delim:"+delimPos+" eq:"+equalsPos);
|
||||
return getKeyValue(map, delimPos + 1, allNameValuePairs, listDelimiter,
|
||||
nameValueSeparator);
|
||||
}
|
||||
if (equalsPos > delimPos) {
|
||||
// there is a key without a value?
|
||||
String key = allNameValuePairs.substring(pos, delimPos);
|
||||
key = key.trim();
|
||||
if (!key.isEmpty()) {
|
||||
map.put(key, null);
|
||||
}
|
||||
return getKeyValue(map, delimPos + 1, allNameValuePairs, listDelimiter,
|
||||
nameValueSeparator);
|
||||
|
||||
}
|
||||
String key = allNameValuePairs.substring(pos, equalsPos);
|
||||
|
||||
if (delimPos > -1) {
|
||||
String value = allNameValuePairs.substring(equalsPos + 1, delimPos);
|
||||
// dp("cont "+key+","+value+" pos:"+pos+"
|
||||
// len:"+allNameValuePairs.length());
|
||||
key = key.trim();
|
||||
|
||||
map.put(key, value);
|
||||
pos = delimPos + 1;
|
||||
|
||||
// recurse the rest of the values...
|
||||
return getKeyValue(map, pos, allNameValuePairs, listDelimiter, nameValueSeparator);
|
||||
} else {
|
||||
// dp("ERROR: delimPos < 0 ???");
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes a String and will replace all occurrences of the match
|
||||
* String with that of the replace String.
|
||||
*
|
||||
* @param source the source string
|
||||
* @param match the string used to find a match
|
||||
* @param replace the string used to replace match with
|
||||
* @return the source string after the search and replace
|
||||
*/
|
||||
public static String replaceString(String source, String match, String replace) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
if (replace == null) {
|
||||
return source;
|
||||
}
|
||||
if (match == null) {
|
||||
throw new NullPointerException("match is null?");
|
||||
}
|
||||
if (match.equals(replace)) {
|
||||
return source;
|
||||
}
|
||||
return replaceString(source, match, replace, 30, 0, source.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Additionally specify the additionalSize to add to the buffer. This will
|
||||
* make the buffer bigger so that it doesn't have to grow when replacement
|
||||
* occurs.
|
||||
*/
|
||||
public static String replaceString(String source, String match, String replace,
|
||||
int additionalSize, int startPos, int endPos) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
char match0 = match.charAt(0);
|
||||
|
||||
int matchLength = match.length();
|
||||
|
||||
if (matchLength == 1 && replace.length() == 1) {
|
||||
char replace0 = replace.charAt(0);
|
||||
return source.replace(match0, replace0);
|
||||
}
|
||||
if (matchLength >= replace.length()) {
|
||||
additionalSize = 0;
|
||||
}
|
||||
|
||||
|
||||
int sourceLength = source.length();
|
||||
int lastMatch = endPos - matchLength;
|
||||
|
||||
StringBuilder sb = new StringBuilder(sourceLength + additionalSize);
|
||||
|
||||
if (startPos > 0) {
|
||||
sb.append(source.substring(0, startPos));
|
||||
}
|
||||
|
||||
char sourceChar;
|
||||
boolean isMatch;
|
||||
int sourceMatchPos;
|
||||
|
||||
for (int i = startPos; i < sourceLength; i++) {
|
||||
sourceChar = source.charAt(i);
|
||||
if (i > lastMatch || sourceChar != match0) {
|
||||
sb.append(sourceChar);
|
||||
|
||||
} else {
|
||||
// check to see if this is a match
|
||||
isMatch = true;
|
||||
sourceMatchPos = i;
|
||||
|
||||
// check each following character...
|
||||
for (int j = 1; j < matchLength; j++) {
|
||||
sourceMatchPos++;
|
||||
if (source.charAt(sourceMatchPos) != match.charAt(j)) {
|
||||
isMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isMatch) {
|
||||
i = i + matchLength - 1;
|
||||
sb.append(replace);
|
||||
} else {
|
||||
// was not a match
|
||||
sb.append(sourceChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A search and replace with multiple matching strings.
|
||||
* <p>
|
||||
* Useful when converting CRNL CR and NL all to a BR tag for example.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre><code>
|
||||
* String[] multi = { "\r\n", "\r", "\n" };
|
||||
* content = StringHelper.replaceStringMulti(content, multi, "<br/>");
|
||||
* </code></pre>
|
||||
*/
|
||||
public static String replaceStringMulti(String source, String[] match, String replace) {
|
||||
return replaceStringMulti(source, match, replace, 30, 0, source.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Additionally specify an additional size estimate for the buffer plus
|
||||
* start and end positions.
|
||||
* <p>
|
||||
* The start and end positions can limit the search and replace. Otherwise
|
||||
* these default to startPos = 0 and endPos = source.length().
|
||||
* </p>
|
||||
*/
|
||||
public static String replaceStringMulti(String source, String[] match, String replace,
|
||||
int additionalSize, int startPos, int endPos) {
|
||||
|
||||
int shortestMatch = match[0].length();
|
||||
|
||||
char[] match0 = new char[match.length];
|
||||
for (int i = 0; i < match0.length; i++) {
|
||||
match0[i] = match[i].charAt(0);
|
||||
if (match[i].length() < shortestMatch) {
|
||||
shortestMatch = match[i].length();
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(source.length() + additionalSize);
|
||||
|
||||
char sourceChar;
|
||||
|
||||
int len = source.length();
|
||||
int lastMatch = endPos - shortestMatch;
|
||||
|
||||
if (startPos > 0) {
|
||||
sb.append(source.substring(0, startPos));
|
||||
}
|
||||
|
||||
int matchCount;
|
||||
|
||||
for (int i = startPos; i < len; i++) {
|
||||
sourceChar = source.charAt(i);
|
||||
if (i > lastMatch) {
|
||||
sb.append(sourceChar);
|
||||
} else {
|
||||
matchCount = 0;
|
||||
for (int k = 0; k < match0.length; k++) {
|
||||
if (matchCount == 0 && sourceChar == match0[k]) {
|
||||
if (match[k].length() + i <= len) {
|
||||
|
||||
++matchCount;
|
||||
int j = 1;
|
||||
for (; j < match[k].length(); j++) {
|
||||
if (source.charAt(i + j) != match[k].charAt(j)) {
|
||||
--matchCount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matchCount > 0) {
|
||||
i = i + j - 1;
|
||||
sb.append(replace);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matchCount == 0) {
|
||||
sb.append(sourceChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.loadcontext;
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
import com.avaje.ebeaninternal.server.persist.dml.GenerateDmlRequest;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Bindable for insert on a property with a GeneratedProperty.
|
||||
* <p>
|
||||
* This is typically a 'insert timestamp', 'update timestamp' or 'counter'.
|
||||
* </p>
|
||||
*/
|
||||
public class BindablePropertyInsertGenerated extends BindableProperty {
|
||||
|
||||
private final GeneratedProperty gen;
|
||||
|
||||
public BindablePropertyInsertGenerated(BeanProperty prop, GeneratedProperty gen) {
|
||||
super(prop);
|
||||
this.gen = gen;
|
||||
}
|
||||
|
||||
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
|
||||
|
||||
Object value = gen.getInsertValue(prop, bean, request.now());
|
||||
|
||||
// generated value should be the correct type
|
||||
if (bean != null) {
|
||||
// support PropertyChangeSupport
|
||||
//prop.setValueIntercept(bean, value);
|
||||
prop.setValue(bean, value);
|
||||
}
|
||||
request.bind(value, prop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bind on Insert SET.
|
||||
*/
|
||||
@Override
|
||||
public void dmlAppend(GenerateDmlRequest request) {
|
||||
request.appendColumn(prop.getDbColumn());
|
||||
}
|
||||
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
import com.avaje.ebeaninternal.server.persist.dml.GenerateDmlRequest;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Bindable for update on a property with a GeneratedProperty.
|
||||
* <p>
|
||||
* This is typically a 'update timestamp' or 'counter'.
|
||||
* </p>
|
||||
*/
|
||||
public class BindablePropertyUpdateGenerated extends BindableProperty {
|
||||
|
||||
private final GeneratedProperty gen;
|
||||
|
||||
public BindablePropertyUpdateGenerated(BeanProperty prop, GeneratedProperty gen) {
|
||||
super(prop);
|
||||
this.gen = gen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add BindablePropertyUpdateGenerated if the property is loaded.
|
||||
*/
|
||||
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
|
||||
if (gen.includeInAllUpdates()) {
|
||||
list.add(this);
|
||||
} else if (request.isLoadedProperty(prop)) {
|
||||
list.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
|
||||
|
||||
Object value = gen.getUpdateValue(prop, bean, request.now());
|
||||
|
||||
// generated value should be the correct type
|
||||
request.bind(value, prop);
|
||||
|
||||
if (prop.isVersion()) {
|
||||
if (request.getPersistRequest().isLoadedProperty(prop)) {
|
||||
// set to the bean after the where clause has been generated
|
||||
request.registerGeneratedVersion(value);
|
||||
}
|
||||
} else {
|
||||
// @WhenModified set without invoking interception
|
||||
prop.setValueChanged(bean, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bind on Insert SET.
|
||||
*/
|
||||
@Override
|
||||
public void dmlAppend(GenerateDmlRequest request) {
|
||||
request.appendColumn(prop.getDbColumn());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Creates a Bindable to support version concurrency where clauses.
|
||||
*/
|
||||
public class FactoryVersion {
|
||||
|
||||
|
||||
public FactoryVersion() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bindable for the version property(s) for a bean type.
|
||||
*/
|
||||
public Bindable create(BeanDescriptor<?> desc) {
|
||||
|
||||
BeanProperty versionProperty = desc.getVersionProperty();
|
||||
if (versionProperty == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new BindableProperty(versionProperty);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
@@ -1,133 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.querydefn;
|
||||
|
||||
import com.avaje.ebean.OrderBy;
|
||||
import com.avaje.ebean.RawSql;
|
||||
import com.avaje.ebeaninternal.api.BindParams;
|
||||
import com.avaje.ebeaninternal.api.CQueryPlanKey;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
|
||||
/**
|
||||
* Query plan key for ORM queries.
|
||||
*/
|
||||
class OrmQueryPlanKey implements CQueryPlanKey {
|
||||
|
||||
private final String m2mIncludeTable;
|
||||
private final String orderByAsSting;
|
||||
private final SpiExpression where;
|
||||
private final SpiExpression having;
|
||||
private final RawSql.Key rawSqlKey;
|
||||
private final boolean hasIdValue;
|
||||
private final SpiQuery.Type type;
|
||||
private final int maxRows;
|
||||
private final int firstRow;
|
||||
private final boolean disableLazyLoading;
|
||||
private final boolean distinct;
|
||||
private final boolean sqlDistinct;
|
||||
private final String mapKey;
|
||||
private final SpiQuery.TemporalMode temporalMode;
|
||||
private final boolean forUpdate;
|
||||
private final String rootTableAlias;
|
||||
private final OrmUpdateProperties updateProperties;
|
||||
|
||||
private final int planHash;
|
||||
private final int bindCount;
|
||||
|
||||
OrmQueryPlanKey(TableJoin m2mIncludeTable, SpiQuery.Type type, OrmQueryDetail detail, int maxRows, int firstRow, boolean disableLazyLoading, OrderBy<?> orderBy, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams, SpiExpression whereExpressions, SpiExpression havingExpressions, SpiQuery.TemporalMode temporalMode, boolean forUpdate, String rootTableAlias, RawSql rawSql, OrmUpdateProperties updateProperties) {
|
||||
|
||||
this.m2mIncludeTable = m2mIncludeTable == null ? null : m2mIncludeTable.getTable();
|
||||
this.type = type;
|
||||
this.maxRows = maxRows;
|
||||
this.firstRow = firstRow;
|
||||
this.disableLazyLoading = disableLazyLoading;
|
||||
this.orderByAsSting = (orderBy == null) ? null : orderBy.toStringFormat();
|
||||
this.distinct = distinct;
|
||||
this.sqlDistinct = sqlDistinct;
|
||||
this.mapKey = mapKey;
|
||||
this.hasIdValue = (id != null);
|
||||
this.where = (whereExpressions == null) ? null : whereExpressions.copyForPlanKey();
|
||||
this.having = (havingExpressions == null) ? null : havingExpressions.copyForPlanKey();
|
||||
this.temporalMode = temporalMode;
|
||||
this.forUpdate = forUpdate;
|
||||
this.rootTableAlias = rootTableAlias;
|
||||
this.updateProperties = updateProperties;
|
||||
this.rawSqlKey = (rawSql == null) ? null : rawSql.getKey();
|
||||
|
||||
// exclude bind values and things unrelated to the sql being generated
|
||||
HashQueryPlanBuilder builder = new HashQueryPlanBuilder();
|
||||
|
||||
builder.add((type == null ? 0 : type.ordinal() + 1));
|
||||
builder.add(distinct).add(sqlDistinct);
|
||||
builder.add(firstRow).add(maxRows);
|
||||
builder.add(orderBy).add(forUpdate);
|
||||
builder.add(mapKey);
|
||||
builder.add(disableLazyLoading);
|
||||
builder.add(hasIdValue);
|
||||
builder.add(temporalMode);
|
||||
builder.add(rawSqlKey == null ? 0 : rawSqlKey.hashCode());
|
||||
builder.add(this.m2mIncludeTable);
|
||||
builder.add(rootTableAlias);
|
||||
|
||||
if (detail != null) {
|
||||
detail.queryPlanHash(builder);
|
||||
}
|
||||
if (bindParams != null) {
|
||||
bindParams.buildQueryPlanHash(builder);
|
||||
}
|
||||
if (where != null) {
|
||||
where.queryPlanHash(builder);
|
||||
}
|
||||
if (having != null) {
|
||||
having.queryPlanHash(builder);
|
||||
}
|
||||
if (updateProperties != null) {
|
||||
updateProperties.buildQueryPlanHash(builder);
|
||||
}
|
||||
|
||||
this.planHash = builder.getPlanHash();
|
||||
this.bindCount = builder.getBindCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPartialKey() {
|
||||
return planHash + "_" + bindCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return planHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
OrmQueryPlanKey that = (OrmQueryPlanKey) o;
|
||||
|
||||
if (planHash != that.planHash) return false;
|
||||
if (bindCount != that.bindCount) return false;
|
||||
if (maxRows != that.maxRows) return false;
|
||||
if (firstRow != that.firstRow) return false;
|
||||
if (disableLazyLoading != that.disableLazyLoading) return false;
|
||||
if (distinct != that.distinct) return false;
|
||||
if (sqlDistinct != that.sqlDistinct) return false;
|
||||
if (forUpdate != that.forUpdate) return false;
|
||||
if (hasIdValue != that.hasIdValue) return false;
|
||||
if (type != that.type) return false;
|
||||
if (temporalMode != that.temporalMode) return false;
|
||||
if (m2mIncludeTable != null ? !m2mIncludeTable.equals(that.m2mIncludeTable) : that.m2mIncludeTable != null)
|
||||
return false;
|
||||
if (orderByAsSting != null ? !orderByAsSting.equals(that.orderByAsSting) : that.orderByAsSting != null)
|
||||
return false;
|
||||
if (where != null ? !where.isSameByPlan(that.where) : that.where != null) return false;
|
||||
if (having != null ? !having.isSameByPlan(that.having) : that.having != null) return false;
|
||||
if (updateProperties != null ? !updateProperties.isSameByPlan(that.updateProperties) : that.updateProperties != null)
|
||||
return false;
|
||||
if (rawSqlKey != null ? !rawSqlKey.equals(that.rawSqlKey) : that.rawSqlKey != null) return false;
|
||||
if (mapKey != null ? !mapKey.equals(that.mapKey) : that.mapKey != null) return false;
|
||||
return rootTableAlias != null ? rootTableAlias.equals(that.rootTableAlias) : that.rootTableAlias == null;
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.querydefn;
|
||||
@@ -1 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.text.csv;
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.transaction;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* Supply the DataSource to the transaction manager.
|
||||
* <p>
|
||||
* Implementations can support multi-tenancy via DB or SCHEMA.
|
||||
* </p>
|
||||
*/
|
||||
public interface DataSourceSupplier {
|
||||
|
||||
/**
|
||||
* Return the DataSource to use for the current request.
|
||||
* <p>
|
||||
* This should take into account multi-tenancy and the current tenantId.
|
||||
* </p>
|
||||
*/
|
||||
DataSource getDataSource();
|
||||
|
||||
/**
|
||||
* Shutdown the datasource de-registering the JDBC driver if requested.
|
||||
*/
|
||||
void shutdown(boolean deregisterDriver);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Wraps a Set for the purposes of detecting modifications.
|
||||
*/
|
||||
public class ModifyAwareSet<E> extends ModifyAwareCollection<E> implements Set<E>, ModifyAwareOwner {
|
||||
|
||||
/**
|
||||
* Create with an Owner that is notified of modifications.
|
||||
*/
|
||||
public ModifyAwareSet(ModifyAwareOwner owner, Set<E> s) {
|
||||
super(owner, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create as top level with it's own ModifyAwareOwner instance wrapping the given Set.
|
||||
*/
|
||||
public ModifyAwareSet(Set<E> s) {
|
||||
super(new ModifyAwareFlag(), s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedDirty() {
|
||||
return owner.isMarkedDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsModified() {
|
||||
owner.markAsModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetMarkedDirty() {
|
||||
owner.resetMarkedDirty();
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import org.joda.time.DateMidnight;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* ScalarType for Joda DateMidnight. This maps to a JDBC Date.
|
||||
*/
|
||||
public class ScalarTypeJodaDateMidnight extends ScalarTypeBaseDate<DateMidnight> {
|
||||
|
||||
/**
|
||||
* Instantiates a new scalar type joda date midnight.
|
||||
*/
|
||||
public ScalarTypeJodaDateMidnight() {
|
||||
super(DateMidnight.class, false, Types.DATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long convertToMillis(DateMidnight value) {
|
||||
return value.getMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateMidnight convertFromDate(Date ts) {
|
||||
return new DateMidnight(ts.getTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date convertToDate(DateMidnight t) {
|
||||
return new Date(t.getMillis());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object toJdbcType(Object value) {
|
||||
if (value instanceof DateMidnight) {
|
||||
return new Date(((DateMidnight) value).getMillis());
|
||||
}
|
||||
return BasicTypeConverter.toDate(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateMidnight toBeanType(Object value) {
|
||||
if (value instanceof java.util.Date) {
|
||||
return new DateMidnight(((java.util.Date) value).getTime());
|
||||
}
|
||||
return (DateMidnight) value;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.avaje.ebeanservice.docstore.api;
|
||||
|
||||
import com.avaje.ebean.text.json.JsonReadOptions;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
|
||||
/**
|
||||
* A Query request for the document store.
|
||||
*/
|
||||
public interface DocQueryRequest<T> {
|
||||
|
||||
/**
|
||||
* Return the query for this request.
|
||||
*/
|
||||
SpiQuery<T> getQuery();
|
||||
|
||||
/**
|
||||
* Create JsonReadOptions taking into account persistence context and lazy loading support.
|
||||
*/
|
||||
JsonReadOptions createJsonReadOptions();
|
||||
|
||||
/**
|
||||
* Execute secondary queries.
|
||||
*/
|
||||
void executeSecondaryQueries(boolean forEach);
|
||||
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* Mapping for document store integration.
|
||||
*/
|
||||
package com.avaje.ebeanservice.docstore.api.mapping;
|
||||
@@ -0,0 +1,21 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.persistence.PessimisticLockException;
|
||||
|
||||
/**
|
||||
* Thrown when failing to acquire a pessimistic lock.
|
||||
* <p>
|
||||
* Typically when "select for update nowait" or "select for update" is being used and
|
||||
* the lock can not be obtained (as it is held by another transaction).
|
||||
* </p>
|
||||
*/
|
||||
public class AcquireLockException extends PessimisticLockException {
|
||||
private static final long serialVersionUID = -8585962352965876691L;
|
||||
|
||||
/**
|
||||
* Create with a message and cause.
|
||||
*/
|
||||
public AcquireLockException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Administrative control of AutoTune during runtime.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
@@ -0,0 +1,57 @@
|
||||
package io.ebean;
|
||||
/**
|
||||
* Enum to control the different cache modes for queryCache (and maybe later) beanCache.
|
||||
*
|
||||
* If cache is enabled, you must be careful, what you do with the returned collection.
|
||||
* By default the returned collections are read only and you will get an exception if you try
|
||||
* to change them.
|
||||
* If you add ".setReadOnly(false)" to your query, you'll get a collection that is a clone from the
|
||||
* one in the cache. That means, changing does not affect the cache
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
public enum CacheMode {
|
||||
/**
|
||||
* Do not use cache.
|
||||
*/
|
||||
OFF(false, false),
|
||||
|
||||
/**
|
||||
* Use the cace (query & store the resut).
|
||||
*/
|
||||
ON(true, true),
|
||||
|
||||
/**
|
||||
* Do not read from cache, but write retrived value to cache.
|
||||
* Use this, if you want to get the fresh value from database and a CacheMode.ON query will follow.
|
||||
*/
|
||||
RECACHE(false, true),
|
||||
|
||||
/**
|
||||
* Query the cache for value. If it is there, use it, otherwise hit database but do NOT put the value
|
||||
* into the cache. (this mode is for completeness. There's probably no use case for this)
|
||||
*/
|
||||
QUERY_ONLY(true,false);
|
||||
|
||||
private boolean get;
|
||||
private boolean put;
|
||||
|
||||
private CacheMode(boolean get, boolean put) {
|
||||
this.get = get;
|
||||
this.put = put;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retruns <code>true</code> if value is read from cache.
|
||||
*/
|
||||
public boolean isGet() {
|
||||
return get;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if value (from database) is written to cache.
|
||||
*/
|
||||
public boolean isPut() {
|
||||
return put;
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.SQLException;
|
||||
@@ -73,8 +73,8 @@ import java.sql.SQLException;
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @see com.avaje.ebean.SqlUpdate
|
||||
* @see com.avaje.ebean.Ebean#execute(CallableSql)
|
||||
* @see SqlUpdate
|
||||
* @see Ebean#execute(CallableSql)
|
||||
*/
|
||||
public interface CallableSql {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
/**
|
||||
* Thrown when a foreign key constraint is enforced.
|
||||
*/
|
||||
public class DataIntegrityException extends PersistenceException {
|
||||
private static final long serialVersionUID = -6740171949170180970L;
|
||||
|
||||
/**
|
||||
* Create with a message and cause.
|
||||
*/
|
||||
public DataIntegrityException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Bean holding the details to update the document store.
|
||||
+23
-4
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import com.avaje.ebeanservice.docstore.api.DocQueryRequest;
|
||||
import io.ebeanservice.docstore.api.DocQueryRequest;
|
||||
import io.ebeanservice.docstore.api.RawDoc;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -55,7 +56,7 @@ public interface DocumentStore {
|
||||
* Return the bean by fetching it's content from the document store.
|
||||
* If the document is not found null is returned.
|
||||
* <p>
|
||||
* Typically this is called indirectly by findUnique() on the query.
|
||||
* Typically this is called indirectly by findOne() on the query.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
@@ -63,7 +64,7 @@ public interface DocumentStore {
|
||||
* server.find(Customer.class)
|
||||
* .setUseDocStore(true)
|
||||
* .setId(42)
|
||||
* .findUnique();
|
||||
* .findOne();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@@ -165,6 +166,24 @@ public interface DocumentStore {
|
||||
*/
|
||||
<T> void findEachWhile(DocQueryRequest<T> query, Predicate<T> consumer);
|
||||
|
||||
/**
|
||||
* Find each processing raw documents.
|
||||
*
|
||||
* @param indexNameType The full index name and type
|
||||
* @param rawQuery The query to execute
|
||||
* @param consumer Consumer to process each document
|
||||
*/
|
||||
void findEach(String indexNameType, String rawQuery, Consumer<RawDoc> consumer);
|
||||
|
||||
/**
|
||||
* Find each processing raw documents stopping when the predicate returns false.
|
||||
*
|
||||
* @param indexNameType The full index name and type
|
||||
* @param rawQuery The query to execute
|
||||
* @param consumer Consumer to process each document until false is returned
|
||||
*/
|
||||
void findEachWhile(String indexNameType, String rawQuery, Predicate<RawDoc> consumer);
|
||||
|
||||
/**
|
||||
* Process the queue entries sending updates to the document store or queuing them for later processing.
|
||||
*/
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Thrown when a duplicate is attempted on a unique constraint.
|
||||
*/
|
||||
public class DuplicateKeyException extends DataIntegrityException {
|
||||
private static final long serialVersionUID = -4771932723285724817L;
|
||||
|
||||
/**
|
||||
* Create with a message and cause.
|
||||
*/
|
||||
public DuplicateKeyException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.text.csv.CsvReader;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.text.csv.CsvReader;
|
||||
import io.ebean.text.json.JsonContext;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -14,6 +15,7 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
@@ -154,7 +156,7 @@ public final class Ebean {
|
||||
} else {
|
||||
// look to see if there is a default server defined
|
||||
String defaultName = PrimaryServer.getDefaultServerName();
|
||||
logger.debug("defaultName:" + defaultName);
|
||||
logger.debug("defaultName:{}", defaultName);
|
||||
if (defaultName != null && !defaultName.trim().isEmpty()) {
|
||||
defaultServer = getWithCreate(defaultName.trim());
|
||||
}
|
||||
@@ -289,7 +291,7 @@ public final class Ebean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Backdoor for registering a mock implementation of EbeanServer as the default server.
|
||||
* Backdoor for registering a mock implementation of EbeanServer as the default server.
|
||||
*/
|
||||
protected static EbeanServer mock(String name, EbeanServer server, boolean defaultServer) {
|
||||
EbeanServer originalPrimaryServer = serverMgr.defaultServer;
|
||||
@@ -371,9 +373,10 @@ public final class Ebean {
|
||||
/**
|
||||
* Start a transaction typically specifying REQUIRES_NEW or REQUIRED semantics.
|
||||
* <p>
|
||||
* Note that this provides an try finally alternative to using {@link #execute(TxScope, TxCallable)} or
|
||||
* {@link #execute(TxScope, TxRunnable)}.
|
||||
* Note that this provides an try finally alternative to using {@link #executeCall(TxScope, Callable)} or
|
||||
* {@link #execute(TxScope, Runnable)}.
|
||||
* </p>
|
||||
*
|
||||
* <h3>REQUIRES_NEW example:</h3>
|
||||
* <pre>{@code
|
||||
* // Start a new transaction. If there is a current transaction
|
||||
@@ -428,6 +431,24 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().currentTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* The batch will be flushing automatically but you can use this to explicitly
|
||||
* flush the batch if you like.
|
||||
* <p>
|
||||
* Flushing occurs automatically when:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>the batch size is reached</li>
|
||||
* <li>A query is executed on the same transaction</li>
|
||||
* <li>UpdateSql or CallableSql are mixed with bean save and delete</li>
|
||||
* <li>Transaction commit occurs</li>
|
||||
* <li>A getter method is called on a batched bean</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static void flush() {
|
||||
currentTransaction().flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a TransactionCallback on the currently active transaction.
|
||||
* <p/>
|
||||
@@ -804,7 +825,7 @@ public final class Ebean {
|
||||
* }</pre>
|
||||
* <p>
|
||||
* If you want more control over the query then you can use createQuery() and
|
||||
* Query.findUnique();
|
||||
* Query.findOne();
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
@@ -825,7 +846,8 @@ public final class Ebean {
|
||||
*
|
||||
* // traverse the object graph...
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
* Order order = query.findOne();
|
||||
*
|
||||
* Customer customer = order.getCustomer();
|
||||
* Address shippingAddress = customer.getShippingAddress();
|
||||
* List<OrderDetail> details = order.getDetails();
|
||||
@@ -941,7 +963,7 @@ public final class Ebean {
|
||||
* predicates, order by, limits etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* You then use findList(), findSet(), findMap() and findUnique() to execute
|
||||
* You then use findList(), findSet(), findMap() and findOne() to execute
|
||||
* the query and return the collection or bean.
|
||||
* </p>
|
||||
* <p>
|
||||
@@ -973,7 +995,7 @@ public final class Ebean {
|
||||
* Query<Order> query = Ebean.createQuery(Order.class, eql);
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
* Order order = query.findOne();
|
||||
*
|
||||
* // This is the same as:
|
||||
*
|
||||
@@ -982,7 +1004,7 @@ public final class Ebean {
|
||||
* .fetch("details")
|
||||
* .fetch("detail.product", "name")
|
||||
* .setId(2)
|
||||
* .findUnique();
|
||||
* .findOne();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
@@ -1012,6 +1034,30 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().find(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query using native SQL.
|
||||
* <p>
|
||||
* The native SQL can contain named parameters or positioned parameters.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
|
||||
*
|
||||
* Query<Customer> query = ebeanServer.findNative(Customer.class, sql);
|
||||
* query.setParameter(1, "Rob%");
|
||||
*
|
||||
* List<Customer> customers = query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The type of entity bean to fetch
|
||||
* @param nativeSql The SQL that can contain named or positioned parameters
|
||||
* @return The query to set parameters and execute
|
||||
*/
|
||||
public static <T> Query<T> findNative(Class<T> beanType, String nativeSql) {
|
||||
return serverMgr.getDefaultServer().findNative(beanType, nativeSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Update query to perform a bulk update.
|
||||
* <p>
|
||||
@@ -1139,20 +1185,20 @@ public final class Ebean {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static void execute(TxScope scope, TxRunnable r) {
|
||||
public static void execute(TxScope scope, Runnable r) {
|
||||
serverMgr.getDefaultServer().execute(scope, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a TxRunnable in a Transaction with the default scope.
|
||||
* Execute a Runnable in a Transaction with the default scope.
|
||||
* <p>
|
||||
* The default scope runs with REQUIRED and by default will rollback on any
|
||||
* exception (checked or runtime).
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Ebean.execute(new TxRunnable() {
|
||||
* public void run() {
|
||||
* Ebean.execute(() -> {
|
||||
*
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* User u2 = Ebean.find(User.class, 2);
|
||||
*
|
||||
@@ -1161,17 +1207,17 @@ public final class Ebean {
|
||||
*
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
* }
|
||||
*
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static void execute(TxRunnable r) {
|
||||
public static void execute(Runnable r) {
|
||||
serverMgr.getDefaultServer().execute(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a TxCallable in a Transaction with an explicit scope.
|
||||
* Execute a Callable in a Transaction with an explicit scope.
|
||||
* <p>
|
||||
* The scope can control the transaction type, isolation and rollback
|
||||
* semantics.
|
||||
@@ -1181,7 +1227,7 @@ public final class Ebean {
|
||||
* // set specific transactional scope settings
|
||||
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
|
||||
*
|
||||
* Ebean.execute(scope, new TxCallable<String>() {
|
||||
* Ebean.executeCall(scope, new Callable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* ...
|
||||
@@ -1191,12 +1237,12 @@ public final class Ebean {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static <T> T execute(TxScope scope, TxCallable<T> c) {
|
||||
return serverMgr.getDefaultServer().execute(scope, c);
|
||||
public static <T> T executeCall(TxScope scope, Callable<T> c) {
|
||||
return serverMgr.getDefaultServer().executeCall(scope, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a TxCallable in a Transaction with the default scope.
|
||||
* Execute a Callable in a Transaction with the default scope.
|
||||
* <p>
|
||||
* The default scope runs with REQUIRED and by default will rollback on any
|
||||
* exception (checked or runtime).
|
||||
@@ -1207,8 +1253,8 @@ public final class Ebean {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Ebean.execute(new TxCallable<String>() {
|
||||
* public String call() {
|
||||
* Ebean.executeCall(() -> {
|
||||
*
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* User u2 = Ebean.find(User.class, 2);
|
||||
*
|
||||
@@ -1219,13 +1265,13 @@ public final class Ebean {
|
||||
* Ebean.save(u2);
|
||||
*
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
*
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static <T> T execute(TxCallable<T> c) {
|
||||
return serverMgr.getDefaultServer().execute(c);
|
||||
public static <T> T executeCall(Callable<T> c) {
|
||||
return serverMgr.getDefaultServer().executeCall(c);
|
||||
}
|
||||
|
||||
/**
|
||||
+108
-43
@@ -1,11 +1,12 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.meta.MetaInfoManager;
|
||||
import com.avaje.ebean.plugin.SpiServer;
|
||||
import com.avaje.ebean.text.csv.CsvReader;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.meta.MetaInfoManager;
|
||||
import io.ebean.plugin.SpiServer;
|
||||
import io.ebean.text.csv.CsvReader;
|
||||
import io.ebean.text.json.JsonContext;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
@@ -14,7 +15,9 @@ import javax.persistence.PersistenceException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -232,12 +235,12 @@ public interface EbeanServer {
|
||||
*
|
||||
* // Find order additionally fetching the customer, details and details.product name.
|
||||
*
|
||||
* String eql = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
|
||||
* String ormQuery = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class, eql);
|
||||
* Query<Order> query = Ebean.createQuery(Order.class, ormQuery);
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
* Order order = query.findOne();
|
||||
*
|
||||
* // This is the same as:
|
||||
*
|
||||
@@ -246,16 +249,16 @@ public interface EbeanServer {
|
||||
* .fetch("details")
|
||||
* .fetch("detail.product", "name")
|
||||
* .setId(2)
|
||||
* .findUnique();
|
||||
* .findOne();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The type of bean to fetch
|
||||
* @param eql The Ebean query
|
||||
* @param ormQuery The Ebean ORM query
|
||||
* @param <T> The type of the entity bean
|
||||
* @return The query with expressions defined as per the parsed query statement
|
||||
*/
|
||||
<T> Query<T> createQuery(Class<T> beanType, String eql);
|
||||
<T> Query<T> createQuery(Class<T> beanType, String ormQuery);
|
||||
|
||||
/**
|
||||
* Create a query for a type of entity bean.
|
||||
@@ -264,7 +267,7 @@ public interface EbeanServer {
|
||||
* predicates, order by, limits etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* You then use findList(), findSet(), findMap() and findUnique() to execute
|
||||
* You then use findList(), findSet(), findMap() and findOne() to execute
|
||||
* the query and return the collection or bean.
|
||||
* </p>
|
||||
* <p>
|
||||
@@ -284,7 +287,7 @@ public interface EbeanServer {
|
||||
* .fetch("details")
|
||||
* .fetch("detail.product", "name")
|
||||
* .setId(2)
|
||||
* .findUnique();
|
||||
* .findOne();
|
||||
*
|
||||
* // find some new orders ... with firstRow/maxRows
|
||||
* List<Order> orders =
|
||||
@@ -298,6 +301,28 @@ public interface EbeanServer {
|
||||
*/
|
||||
<T> Query<T> find(Class<T> beanType);
|
||||
|
||||
/**
|
||||
* Create a query using native SQL.
|
||||
* <p>
|
||||
* The native SQL can contain named parameters or positioned parameters.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
|
||||
*
|
||||
* Query<Customer> query = ebeanServer.findNative(Customer.class, sql);
|
||||
* query.setParameter(1, "Rob%");
|
||||
*
|
||||
* List<Customer> customers = query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The type of entity bean to fetch
|
||||
* @param nativeSql The SQL that can contain named or positioned parameters
|
||||
* @return The query to set parameters and execute
|
||||
*/
|
||||
<T> Query<T> findNative(Class<T> beanType, String nativeSql);
|
||||
|
||||
/**
|
||||
* Return the next unique identity value for a given bean type.
|
||||
* <p>
|
||||
@@ -537,8 +562,8 @@ public interface EbeanServer {
|
||||
* Start a transaction typically specifying REQUIRES_NEW or REQUIRED semantics.
|
||||
* <p>
|
||||
* <p>
|
||||
* Note that this provides an try finally alternative to using {@link #execute(TxScope, TxCallable)} or
|
||||
* {@link #execute(TxScope, TxRunnable)}.
|
||||
* Note that this provides an try finally alternative to using {@link #executeCall(TxScope, Callable)} or
|
||||
* {@link #execute(TxScope, Runnable)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* <h3>REQUIRES_NEW example:</h3>
|
||||
@@ -591,6 +616,19 @@ public interface EbeanServer {
|
||||
*/
|
||||
Transaction currentTransaction();
|
||||
|
||||
/**
|
||||
* Flush the JDBC batch on the current transaction.
|
||||
* <p>
|
||||
* This only is useful when JDBC batch is used. Flush occurs automatically when the
|
||||
* transaction commits or batch size is reached. This manually flushes the JDBC batch
|
||||
* buffer.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is the same as <code>currentTransaction().flush()</code>.
|
||||
* </p>
|
||||
*/
|
||||
void flush();
|
||||
|
||||
/**
|
||||
* Commit the current transaction.
|
||||
*/
|
||||
@@ -658,7 +696,7 @@ public interface EbeanServer {
|
||||
* <p>
|
||||
* <p>
|
||||
* If you want more control over the query then you can use createQuery() and
|
||||
* Query.findUnique();
|
||||
* Query.findOne();
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
@@ -678,7 +716,7 @@ public interface EbeanServer {
|
||||
* query.fetch("details.product", "name");
|
||||
*
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
* Order order = query.findOne();
|
||||
*
|
||||
* // traverse the object graph...
|
||||
*
|
||||
@@ -885,7 +923,7 @@ public interface EbeanServer {
|
||||
* @param query the query to execute the row count on
|
||||
* @param transaction the transaction (can be null).
|
||||
* @return a Future object for the row count query
|
||||
* @see com.avaje.ebean.Query#findFutureCount()
|
||||
* @see Query#findFutureCount()
|
||||
*/
|
||||
<T> FutureRowCount<T> findFutureCount(Query<T> query, Transaction transaction);
|
||||
|
||||
@@ -900,7 +938,7 @@ public interface EbeanServer {
|
||||
* @param query the query to execute the fetch Id's on
|
||||
* @param transaction the transaction (can be null).
|
||||
* @return a Future object for the list of Id's
|
||||
* @see com.avaje.ebean.Query#findFutureIds()
|
||||
* @see Query#findFutureIds()
|
||||
*/
|
||||
<T> FutureIds<T> findFutureIds(Query<T> query, Transaction transaction);
|
||||
|
||||
@@ -1031,7 +1069,7 @@ public interface EbeanServer {
|
||||
* This will throw a NonUniqueResultException if the query finds more than one result.
|
||||
* </p>
|
||||
* <p>
|
||||
* Generally you are able to use {@link Query#findUnique()} rather than
|
||||
* Generally you are able to use {@link Query#findOne()} rather than
|
||||
* explicitly calling this method. You could use this method if you wish to
|
||||
* explicitly control the transaction used for the query.
|
||||
* </p>
|
||||
@@ -1041,10 +1079,28 @@ public interface EbeanServer {
|
||||
* @param transaction the transaction to use (can be null).
|
||||
* @return the list of fetched beans.
|
||||
* @throws NonUniqueResultException if more than one result was found
|
||||
* @see Query#findUnique()
|
||||
* @see Query#findOne()
|
||||
*/
|
||||
@Nullable
|
||||
<T> T findUnique(Query<T> query, Transaction transaction);
|
||||
<T> T findOne(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Similar to findOne() but returns an Optional (rather than nullable).
|
||||
*/
|
||||
<T> Optional<T> findOneOrEmpty(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Deprecated - please migrate to findOne().
|
||||
* <p>
|
||||
* This proceeded findOne which was introduced to better match spring data.
|
||||
* This will be deprecated at some future point.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
@Nullable
|
||||
default <T> T findUnique(Query<T> query, Transaction transaction) {
|
||||
return findOne(query, transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute as a delete query deleting the 'root level' beans that match the predicates
|
||||
@@ -1115,7 +1171,7 @@ public interface EbeanServer {
|
||||
* result.
|
||||
* </p>
|
||||
* <p>
|
||||
* Generally you are able to use {@link SqlQuery#findUnique()} rather than
|
||||
* Generally you are able to use {@link SqlQuery#findOne()} rather than
|
||||
* explicitly calling this method. You could use this method if you wish to
|
||||
* explicitly control the transaction used for the query.
|
||||
* </p>
|
||||
@@ -1123,10 +1179,23 @@ public interface EbeanServer {
|
||||
* @param query the query to execute.
|
||||
* @param transaction the transaction to use (can be null).
|
||||
* @return the fetched MapBean or null if none was found.
|
||||
* @see SqlQuery#findUnique()
|
||||
* @see SqlQuery#findOne()
|
||||
*/
|
||||
@Nullable
|
||||
SqlRow findUnique(SqlQuery query, Transaction transaction);
|
||||
SqlRow findOne(SqlQuery query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Deprecated - please migrate to findOne().
|
||||
* <p>
|
||||
* This proceeded findOne which was introduced to better match spring data.
|
||||
* This will be deprecated at some future point.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
@Nullable
|
||||
default SqlRow findUnique(SqlQuery query, Transaction transaction) {
|
||||
return findOne(query, transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Either Insert or Update the bean depending on its state.
|
||||
@@ -1524,7 +1593,7 @@ public interface EbeanServer {
|
||||
int execute(CallableSql callableSql, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute a TxRunnable in a Transaction with an explicit scope.
|
||||
* Execute a Runnable in a Transaction with an explicit scope.
|
||||
* <p>
|
||||
* The scope can control the transaction type, isolation and rollback
|
||||
* semantics.
|
||||
@@ -1535,7 +1604,7 @@ public interface EbeanServer {
|
||||
* // set specific transactional scope settings
|
||||
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
|
||||
*
|
||||
* ebeanServer.execute(scope, new TxRunnable() {
|
||||
* ebeanServer.execute(scope, new Runnable() {
|
||||
* public void run() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* ...
|
||||
@@ -1544,10 +1613,10 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
void execute(TxScope scope, TxRunnable runnable);
|
||||
void execute(TxScope scope, Runnable runnable);
|
||||
|
||||
/**
|
||||
* Execute a TxRunnable in a Transaction with the default scope.
|
||||
* Execute a Runnable in a Transaction with the default scope.
|
||||
* <p>
|
||||
* The default scope runs with REQUIRED and by default will rollback on any
|
||||
* exception (checked or runtime).
|
||||
@@ -1555,8 +1624,8 @@ public interface EbeanServer {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* ebeanServer.execute(new TxRunnable() {
|
||||
* public void run() {
|
||||
* ebeanServer.execute(() -> {
|
||||
*
|
||||
* User u1 = ebeanServer.find(User.class, 1);
|
||||
* User u2 = ebeanServer.find(User.class, 2);
|
||||
*
|
||||
@@ -1565,12 +1634,12 @@ public interface EbeanServer {
|
||||
*
|
||||
* ebeanServer.save(u1);
|
||||
* ebeanServer.save(u2);
|
||||
* }
|
||||
*
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
void execute(TxRunnable runnable);
|
||||
void execute(Runnable runnable);
|
||||
|
||||
/**
|
||||
* Execute a TxCallable in a Transaction with an explicit scope.
|
||||
@@ -1584,7 +1653,7 @@ public interface EbeanServer {
|
||||
* // set specific transactional scope settings
|
||||
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
|
||||
*
|
||||
* ebeanServer.execute(scope, new TxCallable<String>() {
|
||||
* ebeanServer.executeCall(scope, new Callable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = ebeanServer.find(User.class, 1);
|
||||
* ...
|
||||
@@ -1594,7 +1663,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
<T> T execute(TxScope scope, TxCallable<T> callable);
|
||||
<T> T executeCall(TxScope scope, Callable<T> callable);
|
||||
|
||||
/**
|
||||
* Execute a TxCallable in a Transaction with the default scope.
|
||||
@@ -1603,13 +1672,9 @@ public interface EbeanServer {
|
||||
* exception (checked or runtime).
|
||||
* </p>
|
||||
* <p>
|
||||
* This is basically the same as TxRunnable except that it returns an Object
|
||||
* (and you specify the return type via generics).
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* ebeanServer.execute(new TxCallable<String>() {
|
||||
* ebeanServer.executeCall(new Callable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = ebeanServer.find(User.class, 1);
|
||||
* User u2 = ebeanServer.find(User.class, 2);
|
||||
@@ -1626,7 +1691,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
<T> T execute(TxCallable<T> callable);
|
||||
<T> T executeCall(Callable<T> callable);
|
||||
|
||||
/**
|
||||
* Return the manager of the server cache ("L2" cache).
|
||||
+12
-17
@@ -1,13 +1,14 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import com.avaje.ebean.common.SpiContainer;
|
||||
import com.avaje.ebean.config.ContainerConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
|
||||
import io.ebean.config.ContainerConfig;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.service.SpiContainer;
|
||||
import io.ebean.service.SpiContainerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* Creates EbeanServer instances.
|
||||
@@ -30,8 +31,6 @@ import java.util.Properties;
|
||||
public class EbeanServerFactory {
|
||||
|
||||
|
||||
private static final String DEFAULT_CONTAINER = "com.avaje.ebeaninternal.server.core.DefaultContainer";
|
||||
|
||||
private static SpiContainer container;
|
||||
|
||||
/**
|
||||
@@ -99,7 +98,7 @@ public class EbeanServerFactory {
|
||||
* </p>
|
||||
*/
|
||||
public static synchronized void shutdown() {
|
||||
ShutdownManager.shutdown();
|
||||
container.shutdown();
|
||||
}
|
||||
|
||||
|
||||
@@ -135,14 +134,10 @@ public class EbeanServerFactory {
|
||||
*/
|
||||
protected static SpiContainer createContainer(ContainerConfig containerConfig) {
|
||||
|
||||
String implClassName = System.getProperty("ebean.container", DEFAULT_CONTAINER);
|
||||
|
||||
try {
|
||||
Class<?> cls = Class.forName(implClassName);
|
||||
Constructor<?> constructor = cls.getConstructor(ContainerConfig.class);
|
||||
return (SpiContainer) constructor.newInstance(containerConfig);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
Iterator<SpiContainerFactory> factories = ServiceLoader.load(SpiContainerFactory.class).iterator();
|
||||
if (factories.hasNext()) {
|
||||
return factories.next().create(containerConfig);
|
||||
}
|
||||
throw new IllegalStateException("Service loader didn't find a SpiContainerFactory?");
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Query by Example expression.
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* An expression that is part of a WHERE or HAVING clause.
|
||||
+8
-9
@@ -1,13 +1,12 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import com.avaje.ebean.search.Match;
|
||||
import com.avaje.ebean.search.MultiMatch;
|
||||
import com.avaje.ebean.search.TextCommonTerms;
|
||||
import com.avaje.ebean.search.TextQueryString;
|
||||
import com.avaje.ebean.search.TextSimple;
|
||||
import io.ebean.search.Match;
|
||||
import io.ebean.search.MultiMatch;
|
||||
import io.ebean.search.TextCommonTerms;
|
||||
import io.ebean.search.TextQueryString;
|
||||
import io.ebean.search.TextSimple;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -308,9 +307,9 @@ public interface ExpressionFactory {
|
||||
Expression idIn(Object... idValues);
|
||||
|
||||
/**
|
||||
* Id IN a list of Id values.
|
||||
* Id IN a collection of Id values.
|
||||
*/
|
||||
Expression idIn(List<?> idList);
|
||||
Expression idIn(Collection<?> idCollection);
|
||||
|
||||
/**
|
||||
* All Equal - Map containing property names and their values.
|
||||
+91
-12
@@ -1,10 +1,10 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import com.avaje.ebean.search.Match;
|
||||
import com.avaje.ebean.search.MultiMatch;
|
||||
import com.avaje.ebean.search.TextCommonTerms;
|
||||
import com.avaje.ebean.search.TextQueryString;
|
||||
import com.avaje.ebean.search.TextSimple;
|
||||
import io.ebean.search.Match;
|
||||
import io.ebean.search.MultiMatch;
|
||||
import io.ebean.search.TextCommonTerms;
|
||||
import io.ebean.search.TextQueryString;
|
||||
import io.ebean.search.TextSimple;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
@@ -12,6 +12,7 @@ import java.sql.Timestamp;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
@@ -118,6 +119,27 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Query<T> asDraft();
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause which results in the DB locking the record.
|
||||
*/
|
||||
Query<T> forUpdate();
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause with No Wait option.
|
||||
* <p>
|
||||
* This is typically a Postgres and Oracle only option at this stage.
|
||||
* </p>
|
||||
*/
|
||||
Query<T> forUpdateNoWait();
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause with Skip Locked option.
|
||||
* <p>
|
||||
* This is typically a Postgres and Oracle only option at this stage.
|
||||
* </p>
|
||||
*/
|
||||
Query<T> forUpdateSkipLocked();
|
||||
|
||||
/**
|
||||
* Execute the query including soft deleted rows.
|
||||
*/
|
||||
@@ -242,10 +264,28 @@ public interface ExpressionList<T> {
|
||||
* </p>
|
||||
*
|
||||
* @throws NonUniqueResultException if more than one result was found
|
||||
* @see Query#findUnique()
|
||||
* @see Query#findOne()
|
||||
*/
|
||||
@Nullable
|
||||
T findUnique();
|
||||
T findOne();
|
||||
|
||||
/**
|
||||
* Execute the query returning an optional bean.
|
||||
*/
|
||||
Optional<T> findOneOrEmpty();
|
||||
|
||||
/**
|
||||
* Deprecated - please migrate to findOne().
|
||||
* <p>
|
||||
* This proceeded findOne which was introduced to better match spring data.
|
||||
* This will be deprecated at some future point.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
@Nullable
|
||||
default T findUnique() {
|
||||
return findOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute find row count query in a background thread.
|
||||
@@ -405,11 +445,20 @@ public interface ExpressionList<T> {
|
||||
Query<T> setUseCache(boolean useCache);
|
||||
|
||||
/**
|
||||
* Set to true to use the query for executing this query.
|
||||
* Set the {@link CacheMode} to use the query for executing this query.
|
||||
*
|
||||
* @see Query#setUseQueryCache(boolean)
|
||||
*/
|
||||
Query<T> setUseQueryCache(boolean useCache);
|
||||
Query<T> setUseQueryCache(CacheMode useCache);
|
||||
|
||||
/**
|
||||
* Calls {@link #setUseQueryCache(CacheMode)} with <code>ON</code> or <code>OFF</code>.
|
||||
*
|
||||
* @see Query#setUseQueryCache(CacheMode)
|
||||
*/
|
||||
default Query<T> setUseQueryCache(boolean enabled) {
|
||||
return setUseQueryCache(enabled ? CacheMode.ON : CacheMode.OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this query should execute against the doc store.
|
||||
@@ -758,6 +807,36 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> in(String propertyName, Collection<?> values);
|
||||
|
||||
/**
|
||||
* In - using a subQuery.
|
||||
*
|
||||
* This is exactly the same as in() and provided due to "in" being a Kotlin keyword
|
||||
* (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
|
||||
*/
|
||||
default ExpressionList<T> isIn(String propertyName, Query<?> subQuery) {
|
||||
return in(propertyName, subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the array of values.
|
||||
*
|
||||
* This is exactly the same as in() and provided due to "in" being a Kotlin keyword
|
||||
* (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
|
||||
*/
|
||||
default ExpressionList<T> isIn(String propertyName, Object... values) {
|
||||
return in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the collection of values.
|
||||
*
|
||||
* This is exactly the same as in() and provided due to "in" being a Kotlin keyword
|
||||
* (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
|
||||
*/
|
||||
default ExpressionList<T> isIn(String propertyName, Collection<?> values) {
|
||||
return in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not In - property has a value in the array of values.
|
||||
*/
|
||||
@@ -799,9 +878,9 @@ public interface ExpressionList<T> {
|
||||
ExpressionList<T> idIn(Object... idValues);
|
||||
|
||||
/**
|
||||
* Id IN a list of id values.
|
||||
* Id IN a collection of id values.
|
||||
*/
|
||||
ExpressionList<T> idIn(List<?> idValues);
|
||||
ExpressionList<T> idIn(Collection<?> idValues);
|
||||
|
||||
/**
|
||||
* Id Equal to - ID property is equal to the value.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -18,7 +18,7 @@ import java.util.List;
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* public class CustomerFinder extends Finder<Customer> {
|
||||
* public class CustomerFinder extends Finder<Long,Customer> {
|
||||
*
|
||||
* public CustomerFinder() {
|
||||
* super(Customer.class);
|
||||
@@ -27,11 +27,11 @@ import java.util.List;
|
||||
* // Add your customer finder methods ...
|
||||
*
|
||||
* public Customer byName(String name) {
|
||||
* return query().eq("name", name).findUnique();
|
||||
* return query().eq("name", name).findOne();
|
||||
* }
|
||||
*
|
||||
* public List<Customer> findNew() {
|
||||
* return query()
|
||||
* return query().where()
|
||||
* .eq("status", Customer.Status.NEW)
|
||||
* .orderBy("name")
|
||||
* .findList()
|
||||
@@ -92,6 +92,20 @@ public class Finder<I, T> {
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current transaction.
|
||||
*/
|
||||
public Transaction currentTransaction() {
|
||||
return db().currentTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the JDBC batch on the current transaction.
|
||||
*/
|
||||
public void flush() {
|
||||
db().flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' EbeanServer.
|
||||
* <p>
|
||||
@@ -148,6 +162,28 @@ public class Finder<I, T> {
|
||||
return query().findList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an update query.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows =
|
||||
* finder.update()
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#update(Class)}
|
||||
*/
|
||||
public UpdateQuery<T> update() {
|
||||
return db().update(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query.
|
||||
* <p>
|
||||
@@ -157,4 +193,18 @@ public class Finder<I, T> {
|
||||
return db().find(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a native sql query.
|
||||
*/
|
||||
public Query<T> nativeSql(String nativeSql) {
|
||||
return db().findNative(type, nativeSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query using the ORM query language.
|
||||
*/
|
||||
public Query<T> query(String ormQuery) {
|
||||
return db().createQuery(type, ormQuery);
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.List;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Represents a Conjunction or a Disjunction.
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Used to specify the type of like matching used.
|
||||
@@ -6,22 +6,22 @@ package com.avaje.ebean;
|
||||
public enum LikeType {
|
||||
|
||||
/**
|
||||
* You need to put in your own wildcards.
|
||||
* You need to put in your own wildcards - no escaping is performed.
|
||||
*/
|
||||
RAW,
|
||||
|
||||
/**
|
||||
* The % wildcard is added to the end of the search word.
|
||||
* The % wildcard is added to the end of the search word and search word is escaped.
|
||||
*/
|
||||
STARTS_WITH,
|
||||
|
||||
/**
|
||||
* The % wildcard is added to the beginning of the search word.
|
||||
* The % wildcard is added to the beginning of the search word and search word is escaped.
|
||||
*/
|
||||
ENDS_WITH,
|
||||
|
||||
/**
|
||||
* The % wildcard is added to the beginning and end of the search word.
|
||||
* The % wildcard is added to the beginning and end of the search word and search word is escaped.
|
||||
*/
|
||||
CONTAINS,
|
||||
|
||||
@@ -32,4 +32,4 @@ public enum LikeType {
|
||||
* </p>
|
||||
*/
|
||||
EQUAL_TO
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBean;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
@@ -190,6 +190,17 @@ public abstract class Model {
|
||||
db().save(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush any batched changes to the database.
|
||||
* <p>
|
||||
* When using JDBC batch flushing occurs automatically at commit() time or when the batch size
|
||||
* is reached. This provides the ability to manually flush the batch.
|
||||
* </p>
|
||||
*/
|
||||
public void flush() {
|
||||
db().flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this entity.
|
||||
*
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
@@ -162,6 +162,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
list.add(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return list.toString();
|
||||
}
|
||||
@@ -201,6 +202,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Return a hash value for this OrderBy. This can be to determine logical
|
||||
* equality for OrderBy clauses.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return list.hashCode();
|
||||
}
|
||||
@@ -255,9 +257,9 @@ public final class OrderBy<T> implements Serializable {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc = property.hashCode();
|
||||
hc = hc * 31 + (ascending ? 0 : 1);
|
||||
hc = hc * 31 + (nulls == null ? 0 : nulls.hashCode());
|
||||
hc = hc * 31 + (highLow == null ? 0 : highLow.hashCode());
|
||||
hc = hc * 92821 + (ascending ? 0 : 1);
|
||||
hc = hc * 92821 + (nulls == null ? 0 : nulls.hashCode());
|
||||
hc = hc * 92821 + (highLow == null ? 0 : highLow.hashCode());
|
||||
return hc;
|
||||
}
|
||||
|
||||
@@ -276,6 +278,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
return highLow != null ? highLow.equals(e.highLow) : e.highLow == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toStringFormat();
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Defines the scope for PersistenceContext.
|
||||
@@ -6,8 +6,8 @@ package com.avaje.ebean;
|
||||
* Ebean has traditionally used Transaction scope for the PersistenceContext. This is used to change the scope to
|
||||
* use (by default) and explicitly set the scope to use for an individual query.
|
||||
*
|
||||
* @see com.avaje.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)
|
||||
* @see com.avaje.ebean.Query#setPersistenceContextScope(PersistenceContextScope)
|
||||
* @see io.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)
|
||||
* @see Query#setPersistenceContextScope(PersistenceContextScope)
|
||||
*/
|
||||
public enum PersistenceContextScope {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import com.avaje.ebean.config.PropertyMap;
|
||||
import io.ebean.config.PropertyMap;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -6,6 +6,7 @@ import javax.persistence.NonUniqueResultException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
@@ -195,9 +196,24 @@ import java.util.function.Predicate;
|
||||
public interface Query<T> {
|
||||
|
||||
/**
|
||||
* Return the RawSql that was set to use for this query.
|
||||
* For update mode.
|
||||
*/
|
||||
RawSql getRawSql();
|
||||
enum ForUpdate {
|
||||
/**
|
||||
* Standard For update clause.
|
||||
*/
|
||||
BASE,
|
||||
|
||||
/**
|
||||
* For update with No Wait option.
|
||||
*/
|
||||
NOWAIT,
|
||||
|
||||
/**
|
||||
* For update with Skip Locked option.
|
||||
*/
|
||||
SKIPLOCKED
|
||||
}
|
||||
|
||||
/**
|
||||
* Set RawSql to use for this query.
|
||||
@@ -243,7 +259,7 @@ public interface Query<T> {
|
||||
/**
|
||||
* Specify the PersistenceContextScope to use for this query.
|
||||
* <p/>
|
||||
* When this is not set the 'default' configured on {@link com.avaje.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)}
|
||||
* When this is not set the 'default' configured on {@link io.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)}
|
||||
* is used - this value defaults to {@link PersistenceContextScope#TRANSACTION}.
|
||||
* <p/>
|
||||
* Note that the same persistence Context is used for subsequent lazy loading and query join queries.
|
||||
@@ -810,7 +826,7 @@ public interface Query<T> {
|
||||
* Product product =
|
||||
* ebeanServer.find(Product.class)
|
||||
* .where().eq("sku", "aa113")
|
||||
* .findUnique();
|
||||
* .findOne();
|
||||
* ...
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -824,7 +840,7 @@ public interface Query<T> {
|
||||
* ebeanServer.find(Order.class)
|
||||
* .setId(1)
|
||||
* .fetch("details")
|
||||
* .findUnique();
|
||||
* .findOne();
|
||||
*
|
||||
* // the order details were eagerly loaded
|
||||
* List<OrderDetail> details = order.getDetails();
|
||||
@@ -834,7 +850,25 @@ public interface Query<T> {
|
||||
* @throws NonUniqueResultException if more than one result was found
|
||||
*/
|
||||
@Nullable
|
||||
T findUnique();
|
||||
T findOne();
|
||||
|
||||
/**
|
||||
* Execute the query returning an optional bean.
|
||||
*/
|
||||
Optional<T> findOneOrEmpty();
|
||||
|
||||
/**
|
||||
* Deprecated - please migrate to findOne().
|
||||
* <p>
|
||||
* This proceeded findOne which was introduced to better match spring data.
|
||||
* This will be deprecated at some future point.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
@Nullable
|
||||
default T findUnique() {
|
||||
return findOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return versions of a @History entity bean.
|
||||
@@ -992,7 +1026,7 @@ public interface Query<T> {
|
||||
Query<T> setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set the Id value to query. This is used with findUnique().
|
||||
* Set the Id value to query. This is used with findOne().
|
||||
* <p>
|
||||
* You can use this to have further control over the query. For example adding
|
||||
* fetch joins.
|
||||
@@ -1003,7 +1037,7 @@ public interface Query<T> {
|
||||
* ebeanServer.find(Order.class)
|
||||
* .setId(1)
|
||||
* .fetch("details")
|
||||
* .findUnique();
|
||||
* .findOne();
|
||||
*
|
||||
* // the order details were eagerly fetched
|
||||
* List<OrderDetail> details = order.getDetails();
|
||||
@@ -1286,9 +1320,16 @@ public interface Query<T> {
|
||||
Query<T> setUseCache(boolean useCache);
|
||||
|
||||
/**
|
||||
* Set this to true to use the query cache.
|
||||
* Set the {@link CacheMode} to use the query for executing this query.
|
||||
*/
|
||||
Query<T> setUseQueryCache(boolean useQueryCache);
|
||||
Query<T> setUseQueryCache(CacheMode useQueryCache);
|
||||
|
||||
/**
|
||||
* Calls {@link #setUseQueryCache(CacheMode)} with <code>ON</code> or <code>OFF</code>.
|
||||
*/
|
||||
default Query<T> setUseQueryCache(boolean enabled) {
|
||||
return setUseQueryCache(enabled ? CacheMode.ON : CacheMode.OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this query should execute against the doc store.
|
||||
@@ -1355,11 +1396,37 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> setForUpdate(boolean forUpdate);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause which results in the DB locking the record.
|
||||
*/
|
||||
Query<T> forUpdate();
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause with "no wait" option.
|
||||
* <p>
|
||||
* This is typically a Postgres and Oracle only option at this stage.
|
||||
* </p>
|
||||
*/
|
||||
Query<T> forUpdateNoWait();
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause with "skip locked" option.
|
||||
* <p>
|
||||
* This is typically a Postgres and Oracle only option at this stage.
|
||||
* </p>
|
||||
*/
|
||||
Query<T> forUpdateSkipLocked();
|
||||
|
||||
/**
|
||||
* Return true if this query has forUpdate set.
|
||||
*/
|
||||
boolean isForUpdate();
|
||||
|
||||
/**
|
||||
* Return the "for update" mode to use.
|
||||
*/
|
||||
ForUpdate getForUpdateMode();
|
||||
|
||||
/**
|
||||
* Set root table alias.
|
||||
*/
|
||||
+5
-1
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
@@ -61,20 +61,24 @@ public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
|
||||
/**
|
||||
* Returns <tt>true</tt> if the iteration has more elements.
|
||||
*/
|
||||
@Override
|
||||
boolean hasNext();
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
*/
|
||||
@Override
|
||||
T next();
|
||||
|
||||
/**
|
||||
* Remove is not allowed.
|
||||
*/
|
||||
@Override
|
||||
void remove();
|
||||
|
||||
/**
|
||||
* Close the underlying resources held by this iterator.
|
||||
*/
|
||||
@Override
|
||||
void close();
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Used to build object graphs based on a raw SQL statement (rather than
|
||||
* generated by Ebean).
|
||||
* <p>
|
||||
* If you don't want to build object graphs you can use {@link SqlQuery} instead
|
||||
* which returns {@link SqlRow} objects rather than entity beans.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Unparsed RawSql:</b>
|
||||
* </p>
|
||||
* <p>
|
||||
* When RawSql is created via {@link RawSqlBuilder#unparsed(String)} then Ebean can not
|
||||
* modify the SQL at all. It can't add any extra expressions into the SQL.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Parsed RawSql:</b>
|
||||
* </p>
|
||||
* <p>
|
||||
* When RawSql is created via {@link RawSqlBuilder#parse(String)} then Ebean will parse the
|
||||
* SQL and find places in the SQL where it can add extra where expressions, add
|
||||
* extra having expressions or replace the order by clause. If you want to
|
||||
* explicitly tell Ebean where these insertion points are you can place special
|
||||
* strings into your SQL ({@code ${where}} or {@code ${andWhere}} and {@code ${having}} or
|
||||
* {@code ${andHaving})}.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the SQL already includes a WHERE clause put in {@code ${andWhere}} in the location
|
||||
* you want Ebean to add any extra where expressions. If the SQL doesn't have a
|
||||
* WHERE clause put {@code ${where}} in instead. Similarly you can put in {@code ${having}} or
|
||||
* {@code ${andHaving}} where you want Ebean put add extra having expressions.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Aggregates:</b>
|
||||
* </p>
|
||||
* <p>
|
||||
* Often RawSql will be used with Aggregate functions (sum, avg, max etc). The
|
||||
* follow example shows an example based on Total Order Amount -
|
||||
* sum(d.order_qty*d.unit_price).
|
||||
* </p>
|
||||
* <p>
|
||||
* We can use a OrderAggregate bean that has a @Sql to indicate it is based
|
||||
* on RawSql and not based on a real DB Table or DB View. It has some properties
|
||||
* to hold the values for the aggregate functions (sum etc) and a @OneToOne
|
||||
* to Order.
|
||||
* </p>
|
||||
* <p>
|
||||
* <h3>Example OrderAggregate</h3>
|
||||
* <pre>{@code
|
||||
* ...
|
||||
* // @Sql indicates to that this bean
|
||||
* // is based on RawSql rather than a table
|
||||
*
|
||||
* @Entity
|
||||
* @Sql
|
||||
* public class OrderAggregate {
|
||||
*
|
||||
* @OneToOne
|
||||
* Order order;
|
||||
*
|
||||
* Double totalAmount;
|
||||
*
|
||||
* Double totalItems;
|
||||
*
|
||||
* // getters and setters
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Example 1:</h3>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = " select order_id, o.status, c.id, c.name, sum(d.order_qty*d.unit_price) as totalAmount"
|
||||
* + " from o_order o"
|
||||
* + " join o_customer c on c.id = o.kcustomer_id "
|
||||
* + " join o_order_detail d on d.order_id = o.id " + " group by order_id, o.status ";
|
||||
*
|
||||
* RawSql rawSql = RawSqlBuilder.parse(sql)
|
||||
* // map the sql result columns to bean properties
|
||||
* .columnMapping("order_id", "order.id")
|
||||
* .columnMapping("o.status", "order.status")
|
||||
* .columnMapping("c.id", "order.customer.id")
|
||||
* .columnMapping("c.name", "order.customer.name")
|
||||
* // we don't need to map this one due to the sql column alias
|
||||
* // .columnMapping("sum(d.order_qty*d.unit_price)", "totalAmount")
|
||||
* .create();
|
||||
*
|
||||
* List<OrderAggregate> list = Ebean.find(OrderAggregate.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .where().gt("order.id", 0)
|
||||
* .having().gt("totalAmount", 20)
|
||||
* .findList();
|
||||
*
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Example 2:</h3>
|
||||
* <p>
|
||||
* The following example uses a FetchConfig().query() so that after the initial
|
||||
* RawSql query is executed Ebean executes a secondary query to fetch the
|
||||
* associated order status, orderDate along with the customer name.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = " select order_id, 'ignoreMe', sum(d.order_qty*d.unit_price) as totalAmount "
|
||||
* + " from o_order_detail d"
|
||||
* + " group by order_id ";
|
||||
*
|
||||
* RawSql rawSql = RawSqlBuilder.parse(sql)
|
||||
* .columnMapping("order_id", "order.id")
|
||||
* .columnMappingIgnore("'ignoreMe'")
|
||||
* .create();
|
||||
*
|
||||
* List<OrderAggregate> orders = Ebean.find(OrderAggregate.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .fetch("order", "status,orderDate", new FetchConfig().query())
|
||||
* .fetch("order.customer", "name")
|
||||
* .where().gt("order.id", 0)
|
||||
* .having().gt("totalAmount", 20)
|
||||
* .order().desc("totalAmount")
|
||||
* .setMaxRows(10)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Example 3: tableAliasMapping</h3>
|
||||
* <p>
|
||||
* Instead of mapping each column you can map each table alias to a path using tableAliasMapping().
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* String rs = "select o.id, o.status, c.id, c.name, "+
|
||||
* " d.id, d.order_qty, p.id, p.name " +
|
||||
* "from o_order o join o_customer c on c.id = o.kcustomer_id " +
|
||||
* "join o_order_detail d on d.order_id = o.id " +
|
||||
* "join o_product p on p.id = d.product_id " +
|
||||
* "where o.id <= :maxOrderId and p.id = :productId "+
|
||||
* "order by o.id, d.id asc";
|
||||
*
|
||||
* RawSql rawSql = RawSqlBuilder.parse(rs)
|
||||
* .tableAliasMapping("c", "customer")
|
||||
* .tableAliasMapping("d", "details")
|
||||
* .tableAliasMapping("p", "details.product")
|
||||
* .create();
|
||||
*
|
||||
* List<Order> ordersFromRaw = Ebean.find(Order.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .setParameter("maxOrderId", 2)
|
||||
* .setParameter("productId", 1)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <p>
|
||||
* Note that lazy loading also works with object graphs built with RawSql.
|
||||
* </p>
|
||||
*/
|
||||
public interface RawSql {
|
||||
|
||||
}
|
||||
+12
-56
@@ -1,7 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.RawSql.ColumnMapping;
|
||||
import com.avaje.ebean.RawSql.Sql;
|
||||
package io.ebean;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
@@ -14,18 +11,7 @@ import java.sql.ResultSet;
|
||||
*
|
||||
* @see RawSql
|
||||
*/
|
||||
public class RawSqlBuilder {
|
||||
|
||||
/**
|
||||
* Special property name assigned to a DB column that should be ignored.
|
||||
*/
|
||||
public static final String IGNORE_COLUMN = "$$_IGNORE_COLUMN_$$";
|
||||
|
||||
private final ResultSet resultSet;
|
||||
|
||||
private final Sql sql;
|
||||
|
||||
private final ColumnMapping columnMapping;
|
||||
public interface RawSqlBuilder {
|
||||
|
||||
/**
|
||||
* Create and return a RawSql object based on the resultSet and list of properties the columns in
|
||||
@@ -34,8 +20,8 @@ public class RawSqlBuilder {
|
||||
* The properties listed in the propertyNames must be in the same order as the columns in the
|
||||
* resultSet.
|
||||
*/
|
||||
public static RawSql resultSet(ResultSet resultSet, String... propertyNames) {
|
||||
return new RawSql(resultSet, propertyNames);
|
||||
static RawSql resultSet(ResultSet resultSet, String... propertyNames) {
|
||||
return XServiceProvider.get().resultSet(resultSet, propertyNames);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,10 +29,8 @@ public class RawSqlBuilder {
|
||||
* modified - so no additional WHERE or HAVING expressions can be added to
|
||||
* this query.
|
||||
*/
|
||||
public static RawSqlBuilder unparsed(String sql) {
|
||||
|
||||
Sql s = new Sql(sql);
|
||||
return new RawSqlBuilder(s, new ColumnMapping());
|
||||
static RawSqlBuilder unparsed(String sql) {
|
||||
return XServiceProvider.get().unparsed(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,19 +46,8 @@ public class RawSqlBuilder {
|
||||
* correct column names are entered into the mapping.
|
||||
* </p>
|
||||
*/
|
||||
public static RawSqlBuilder parse(String sql) {
|
||||
|
||||
Sql sql2 = DRawSqlParser.parse(sql);
|
||||
String select = sql2.getPreFrom();
|
||||
|
||||
ColumnMapping mapping = DRawSqlColumnsParser.parse(select);
|
||||
return new RawSqlBuilder(sql2, mapping);
|
||||
}
|
||||
|
||||
private RawSqlBuilder(Sql sql, ColumnMapping columnMapping) {
|
||||
this.sql = sql;
|
||||
this.columnMapping = columnMapping;
|
||||
this.resultSet = null;
|
||||
static RawSqlBuilder parse(String sql) {
|
||||
return XServiceProvider.get().parsed(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,17 +60,12 @@ public class RawSqlBuilder {
|
||||
* @param dbColumn the DB column that we are mapping to a bean property
|
||||
* @param propertyName the bean property that we are mapping the DB column to.
|
||||
*/
|
||||
public RawSqlBuilder columnMapping(String dbColumn, String propertyName) {
|
||||
columnMapping.columnMapping(dbColumn, propertyName);
|
||||
return this;
|
||||
}
|
||||
RawSqlBuilder columnMapping(String dbColumn, String propertyName);
|
||||
|
||||
/**
|
||||
* Ignore this DB column. It is not mapped to any bean property.
|
||||
*/
|
||||
public RawSqlBuilder columnMappingIgnore(String dbColumn) {
|
||||
return columnMapping(dbColumn, IGNORE_COLUMN);
|
||||
}
|
||||
RawSqlBuilder columnMappingIgnore(String dbColumn);
|
||||
|
||||
/**
|
||||
* Modify any column mappings with the given table alias to have the path prefix.
|
||||
@@ -108,24 +76,12 @@ public class RawSqlBuilder {
|
||||
* For the "Root type" you don't need to specify a tableAliasMapping.
|
||||
* </p>
|
||||
*/
|
||||
public RawSqlBuilder tableAliasMapping(String tableAlias, String path) {
|
||||
columnMapping.tableAliasMapping(tableAlias, path);
|
||||
return this;
|
||||
}
|
||||
RawSqlBuilder tableAliasMapping(String tableAlias, String path);
|
||||
|
||||
/**
|
||||
* Create the immutable RawSql object. Do this after all the column mapping
|
||||
* has been defined.
|
||||
*/
|
||||
public RawSql create() {
|
||||
return new RawSql(resultSet, sql, columnMapping.createImmutableCopy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the internal parsed Sql object (for testing).
|
||||
*/
|
||||
protected Sql getSql() {
|
||||
return sql;
|
||||
}
|
||||
RawSql create();
|
||||
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -70,7 +71,20 @@ public interface SqlQuery extends Serializable {
|
||||
* PersistenceException.
|
||||
* </p>
|
||||
*/
|
||||
SqlRow findUnique();
|
||||
SqlRow findOne();
|
||||
|
||||
/**
|
||||
* Execute the query returning an optional row.
|
||||
*/
|
||||
Optional<SqlRow> findOneOrEmpty();
|
||||
|
||||
/**
|
||||
* Deprecated - please migrate to findOne().
|
||||
*/
|
||||
@Deprecated
|
||||
default SqlRow findUnique() {
|
||||
return findOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* The same as bind for named parameters.
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebean;
|
||||
package io.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
@@ -39,16 +39,19 @@ public interface SqlRow extends Serializable, Map<String, Object> {
|
||||
/**
|
||||
* Remove a property from the map. Returns the value of the removed property.
|
||||
*/
|
||||
@Override
|
||||
Object remove(Object name);
|
||||
|
||||
/**
|
||||
* Return a property value by its name.
|
||||
*/
|
||||
@Override
|
||||
Object get(Object name);
|
||||
|
||||
/**
|
||||
* Set a value to a property.
|
||||
*/
|
||||
@Override
|
||||
Object put(String name, Object value);
|
||||
|
||||
/**
|
||||
@@ -118,51 +121,61 @@ public interface SqlRow extends Serializable, Map<String, Object> {
|
||||
/**
|
||||
* String description of the underlying map.
|
||||
*/
|
||||
@Override
|
||||
String toString();
|
||||
|
||||
/**
|
||||
* Clear the map.
|
||||
*/
|
||||
@Override
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Returns true if the map contains the property.
|
||||
*/
|
||||
@Override
|
||||
boolean containsKey(Object key);
|
||||
|
||||
/**
|
||||
* Returns true if the map contains the value.
|
||||
*/
|
||||
@Override
|
||||
boolean containsValue(Object value);
|
||||
|
||||
/**
|
||||
* Returns the entrySet of the map.
|
||||
*/
|
||||
@Override
|
||||
Set<Map.Entry<String, Object>> entrySet();
|
||||
|
||||
/**
|
||||
* Returns true if the map is empty.
|
||||
*/
|
||||
@Override
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Returns the key set of the map.
|
||||
*/
|
||||
@Override
|
||||
Set<String> keySet();
|
||||
|
||||
/**
|
||||
* Put all the values from t into this map.
|
||||
*/
|
||||
@Override
|
||||
void putAll(Map<? extends String, ?> t);
|
||||
|
||||
/**
|
||||
* Return the size of the map.
|
||||
*/
|
||||
@Override
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Return the values from this map.
|
||||
*/
|
||||
@Override
|
||||
Collection<Object> values();
|
||||
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user