mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
90
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d92abbbe9c | ||
|
|
39500567c3 | ||
|
|
261b13ef4b | ||
|
|
7639034d7c | ||
|
|
c71971eb5c | ||
|
|
357af58db4 | ||
|
|
0abdb1550a | ||
|
|
c32fc814f6 | ||
|
|
8e035939dc | ||
|
|
edf98ee250 | ||
|
|
5f0a75a130 | ||
|
|
d2f16cbf6a | ||
|
|
04ba81d12f | ||
|
|
f63e7ed5af | ||
|
|
66940c0f14 | ||
|
|
1f48b3a6b3 | ||
|
|
7d368097e9 | ||
|
|
c849e29316 | ||
|
|
c78a3dd6c4 | ||
|
|
a4455ddbf2 | ||
|
|
9787af77e4 | ||
|
|
3786fb09a5 | ||
|
|
f34e7b6003 | ||
|
|
089dd8e364 | ||
|
|
44770382fb | ||
|
|
2a62d413cc | ||
|
|
0046d983cb | ||
|
|
006e33cb3e | ||
|
|
e80e8e027a | ||
|
|
2e1b52d7d4 | ||
|
|
09d5163396 | ||
|
|
a6a38b9a92 | ||
|
|
bd4521b240 | ||
|
|
8a7379879b | ||
|
|
b78dd6f79a | ||
|
|
4ebb5fd112 | ||
|
|
487368976f | ||
|
|
c6defceec9 | ||
|
|
ded6fd71b2 | ||
|
|
cbc4883672 | ||
|
|
64e227117b | ||
|
|
8ed3b765ec | ||
|
|
fcbcc53e27 | ||
|
|
b377e1a618 | ||
|
|
a0f612ed71 | ||
|
|
47e97a77a8 | ||
|
|
e8d3f50bb4 | ||
|
|
716cfaf938 | ||
|
|
7cd9e5ee03 | ||
|
|
f9c9bea623 | ||
|
|
720832122c | ||
|
|
7b635acf56 | ||
|
|
6b7efe65d7 | ||
|
|
03cd4000f0 | ||
|
|
dfd6434b59 | ||
|
|
4e7480237b | ||
|
|
9bfcf07486 | ||
|
|
b1f1344057 | ||
|
|
07201c1519 | ||
|
|
455a9fdffc | ||
|
|
3f67425727 | ||
|
|
3fd9ae06db | ||
|
|
a8ce726e47 | ||
|
|
29cd1a143d | ||
|
|
6a19c6a0ce | ||
|
|
eaec515cc1 | ||
|
|
97709d3493 | ||
|
|
87ad874621 | ||
|
|
dfe95f6fc0 | ||
|
|
05feccfeb6 | ||
|
|
196cb09c66 | ||
|
|
589e198301 | ||
|
|
b2b81677e8 | ||
|
|
f032aad22e | ||
|
|
c48e5428c5 | ||
|
|
cbca940611 | ||
|
|
0da3772ae9 | ||
|
|
496ef36b11 | ||
|
|
a4a2aba56f | ||
|
|
803f1d8642 | ||
|
|
ff1c73e20d | ||
|
|
7afd37cd98 | ||
|
|
24bb364d40 | ||
|
|
5d54a238bd | ||
|
|
b50ce5fc3f | ||
|
|
624e92840c | ||
|
|
b03adc412c | ||
|
|
e794f5e916 | ||
|
|
a2551ce718 | ||
|
|
5b0a3607f6 |
@@ -13,7 +13,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
java_version: [11]
|
java_version: [21]
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -42,13 +42,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-clickhouse</artifactId>
|
<artifactId>ebean-platform-clickhouse</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -42,13 +42,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-postgres</artifactId>
|
<artifactId>ebean-platform-postgres</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -42,13 +42,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-db2</artifactId>
|
<artifactId>ebean-platform-db2</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -42,13 +42,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-h2</artifactId>
|
<artifactId>ebean-platform-h2</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -42,13 +42,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-hana</artifactId>
|
<artifactId>ebean-platform-hana</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -42,13 +42,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-mariadb</artifactId>
|
<artifactId>ebean-platform-mariadb</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -42,13 +42,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-mysql</artifactId>
|
<artifactId>ebean-platform-mysql</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -42,13 +42,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-nuodb</artifactId>
|
<artifactId>ebean-platform-nuodb</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -42,13 +42,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-oracle</artifactId>
|
<artifactId>ebean-platform-oracle</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -22,13 +22,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -47,19 +47,19 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-postgres</artifactId>
|
<artifactId>ebean-platform-postgres</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-postgis-types</artifactId>
|
<artifactId>ebean-postgis-types</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -42,13 +42,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-postgres</artifactId>
|
<artifactId>ebean-platform-postgres</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -42,13 +42,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-sqlite</artifactId>
|
<artifactId>ebean-platform-sqlite</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -42,13 +42,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-sqlserver</artifactId>
|
<artifactId>ebean-platform-sqlserver</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -42,13 +42,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-postgres</artifactId>
|
<artifactId>ebean-platform-postgres</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<relativePath>../..</relativePath>
|
<relativePath>../..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-jackson-mapper</artifactId>
|
<artifactId>ebean-jackson-mapper</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -60,13 +60,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-all</artifactId>
|
<artifactId>ebean-platform-all</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>composites</artifactId>
|
<artifactId>composites</artifactId>
|
||||||
|
|||||||
+49
-2
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<name>ebean api</name>
|
<name>ebean api</name>
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.avaje</groupId>
|
<groupId>io.avaje</groupId>
|
||||||
<artifactId>avaje-config</artifactId>
|
<artifactId>avaje-config</artifactId>
|
||||||
<version>3.9</version>
|
<version>3.10</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -126,6 +126,53 @@
|
|||||||
</excludes>
|
</excludes>
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>compile</id>
|
||||||
|
<goals>
|
||||||
|
<goal>compile</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<release>11</release>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>compile-21</id>
|
||||||
|
<phase>compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>compile</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<release>21</release>
|
||||||
|
<compileSourceRoots>
|
||||||
|
<compileSourceRoot>${project.basedir}/src/main/java21</compileSourceRoot>
|
||||||
|
</compileSourceRoots>
|
||||||
|
<multiReleaseOutput>true</multiReleaseOutput>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<addMavenDescriptor>false</addMavenDescriptor>
|
||||||
|
<manifestEntries>
|
||||||
|
<Multi-Release>true</Multi-Release>
|
||||||
|
</manifestEntries>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
<!-- <manifest>-->
|
||||||
|
<!-- <addDefaultImplementationEntries>true</addDefaultImplementationEntries>-->
|
||||||
|
<!-- </manifest>-->
|
||||||
|
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
package io.ebean;
|
||||||
|
|
||||||
|
final class DInsertOptionsBuilder implements InsertOptions.Builder {
|
||||||
|
|
||||||
|
private Boolean getGeneratedKeys;
|
||||||
|
private boolean onConflictUpdate;
|
||||||
|
private boolean onConflictNothing;
|
||||||
|
private String constraint;
|
||||||
|
private String uniqueColumns;
|
||||||
|
private String updateSet;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InsertOptions.Builder onConflictNothing() {
|
||||||
|
this.onConflictNothing = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InsertOptions.Builder onConflictUpdate() {
|
||||||
|
this.onConflictUpdate = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InsertOptions.Builder constraint(String constraint) {
|
||||||
|
this.constraint = constraint;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InsertOptions.Builder uniqueColumns(String uniqueColumns) {
|
||||||
|
this.uniqueColumns = uniqueColumns;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InsertOptions.Builder updateSet(String updateSet) {
|
||||||
|
this.updateSet = updateSet;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InsertOptions.Builder getGeneratedKeys(boolean getGeneratedKeys) {
|
||||||
|
this.getGeneratedKeys = getGeneratedKeys;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InsertOptions build() {
|
||||||
|
return new Options(constraint, uniqueColumns, updateSet, onConflictUpdate, onConflictNothing, getGeneratedKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class Options implements InsertOptions {
|
||||||
|
|
||||||
|
private static final String UPDATE = "U";
|
||||||
|
private static final String NOTHING = "N";
|
||||||
|
private static final String NORMAL = "_";
|
||||||
|
private final String key;
|
||||||
|
private final Boolean getGeneratedKeys;
|
||||||
|
private final String constraint;
|
||||||
|
private final String uniqueColumns;
|
||||||
|
private final String updateSet;
|
||||||
|
|
||||||
|
Options(String constraint, String uniqueColumns, String updateSet, boolean onConflictUpdate, boolean onConflictNothing, Boolean getGeneratedKeys) {
|
||||||
|
this.constraint = constraint;
|
||||||
|
this.uniqueColumns = uniqueColumns;
|
||||||
|
this.updateSet = updateSet;
|
||||||
|
this.getGeneratedKeys = getGeneratedKeys;
|
||||||
|
this.key = (onConflictUpdate ? UPDATE : onConflictNothing ? NOTHING : NORMAL)
|
||||||
|
+ '+' + plus(constraint)
|
||||||
|
+ '+' + plus(uniqueColumns)
|
||||||
|
+ '+' + plus(updateSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String plus(String val) {
|
||||||
|
return val == null ? "" : val;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String key() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String constraint() {
|
||||||
|
return constraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String uniqueColumns() {
|
||||||
|
return uniqueColumns;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String updateSet() {
|
||||||
|
return updateSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean getGetGeneratedKeys() {
|
||||||
|
return getGeneratedKeys;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1227,22 +1227,53 @@ public interface Database {
|
|||||||
*/
|
*/
|
||||||
void insert(Object bean);
|
void insert(Object bean);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert the bean with options (ON CONFLICT DO UPDATE | DO NOTHING).
|
||||||
|
* <p>
|
||||||
|
* Currently, this is limited to use with Postgres only,
|
||||||
|
* <p>
|
||||||
|
* When using this ebean will look to determine the unique columns by looking at
|
||||||
|
* the mapping like {@code @Column(unique=true} and {@code @Index(unique=true}.
|
||||||
|
*/
|
||||||
|
void insert(Object bean, InsertOptions insertOptions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert the bean with a transaction.
|
* Insert the bean with a transaction.
|
||||||
*/
|
*/
|
||||||
void insert(Object bean, Transaction transaction);
|
void insert(Object bean, Transaction transaction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert the beans with options (ON CONFLICT DO UPDATE | DO NOTHING) and transaction.
|
||||||
|
* <p>
|
||||||
|
* Currently, this is limited to use with Postgres only,
|
||||||
|
*/
|
||||||
|
void insert(Object bean, InsertOptions insertOptions, Transaction transaction);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a collection of beans. If there is no current transaction one is created and used to
|
* Insert a collection of beans. If there is no current transaction one is created and used to
|
||||||
* insert all the beans in the collection.
|
* insert all the beans in the collection.
|
||||||
*/
|
*/
|
||||||
void insertAll(Collection<?> beans);
|
void insertAll(Collection<?> beans);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert the beans with options - typically ON CONFLICT DO UPDATE | DO NOTHING.
|
||||||
|
* <p>
|
||||||
|
* Currently, this is limited to use with Postgres only,
|
||||||
|
*/
|
||||||
|
void insertAll(Collection<?> beans, InsertOptions options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a collection of beans with an explicit transaction.
|
* Insert a collection of beans with an explicit transaction.
|
||||||
*/
|
*/
|
||||||
void insertAll(Collection<?> beans, Transaction transaction);
|
void insertAll(Collection<?> beans, Transaction transaction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert the beans with options (ON CONFLICT DO UPDATE | DO NOTHING) and transaction.
|
||||||
|
* <p>
|
||||||
|
* Currently, this is limited to use with Postgres only,
|
||||||
|
*/
|
||||||
|
void insertAll(Collection<?> beans, InsertOptions options, Transaction transaction);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute explicitly passing a transaction.
|
* Execute explicitly passing a transaction.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,10 +20,16 @@ import jakarta.persistence.EnumType;
|
|||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import java.time.Clock;
|
import java.time.Clock;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a Database instance.
|
* Build a Database instance.
|
||||||
|
* <p>
|
||||||
|
* Note that {@link #settings()} provides access to read the builder configuration
|
||||||
|
* (the getters). The DatabaseBuilder only has the methods to set builder configuration
|
||||||
|
* (the setters) so use {@link #settings()} to access to everything.
|
||||||
*
|
*
|
||||||
* <pre>{@code
|
* <pre>{@code
|
||||||
*
|
*
|
||||||
@@ -64,6 +70,23 @@ public interface DatabaseBuilder {
|
|||||||
*/
|
*/
|
||||||
Settings settings();
|
Settings settings();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply configuration to this builder using a lambda.
|
||||||
|
*/
|
||||||
|
DatabaseBuilder apply(Consumer<DatabaseBuilder.Settings> applyConfiguration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conditionally apply configuration to this builder via a lambda.
|
||||||
|
*
|
||||||
|
* @param predicate The condition to apply configuration when true.
|
||||||
|
* @param apply The configuration to apply to this builder.
|
||||||
|
*/
|
||||||
|
default DatabaseBuilder alsoIf(BooleanSupplier predicate, Consumer<DatabaseBuilder.Settings> apply) {
|
||||||
|
if (predicate.getAsBoolean()) {
|
||||||
|
apply(apply);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Set the name of the Database.
|
* Set the name of the Database.
|
||||||
*/
|
*/
|
||||||
@@ -1030,6 +1053,14 @@ public interface DatabaseBuilder {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
DatabaseBuilder setSkipDataSourceCheck(boolean skipDataSourceCheck);
|
DatabaseBuilder setSkipDataSourceCheck(boolean skipDataSourceCheck);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to true if this database is used in a read only way.
|
||||||
|
* <p>
|
||||||
|
* The DataSource and read-only DataSource are expected to be the same
|
||||||
|
* and use readOnly=true and autoCommit=true.
|
||||||
|
*/
|
||||||
|
DatabaseBuilder readOnlyDatabase(boolean readOnlyDatabase);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a DataSource.
|
* Set a DataSource.
|
||||||
*/
|
*/
|
||||||
@@ -2584,6 +2615,14 @@ public interface DatabaseBuilder {
|
|||||||
*/
|
*/
|
||||||
boolean skipDataSourceCheck();
|
boolean skipDataSourceCheck();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if this database is used in a read only way.
|
||||||
|
* <p>
|
||||||
|
* The DataSource and read-only DataSource are expected to be the same
|
||||||
|
* and use readOnly=true and autoCommit=true.
|
||||||
|
*/
|
||||||
|
boolean readOnlyDatabase();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the DataSource.
|
* Return the DataSource.
|
||||||
*/
|
*/
|
||||||
@@ -2598,7 +2637,7 @@ public interface DatabaseBuilder {
|
|||||||
* Return the configuration to build a DataSource using Ebean's own DataSource
|
* Return the configuration to build a DataSource using Ebean's own DataSource
|
||||||
* implementation.
|
* implementation.
|
||||||
*/
|
*/
|
||||||
DataSourceBuilder getDataSourceConfig();
|
DataSourceBuilder.Settings getDataSourceConfig();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if Ebean should create a DataSource for use with implicit read only transactions.
|
* Return true if Ebean should create a DataSource for use with implicit read only transactions.
|
||||||
@@ -2614,7 +2653,7 @@ public interface DatabaseBuilder {
|
|||||||
* set on this configuration. This means there is actually no need to set any configuration here and we only
|
* set on this configuration. This means there is actually no need to set any configuration here and we only
|
||||||
* set configuration for url, username and password etc if it is different from the main DataSource.
|
* set configuration for url, username and password etc if it is different from the main DataSource.
|
||||||
*/
|
*/
|
||||||
DataSourceBuilder getReadOnlyDataSourceConfig();
|
DataSourceBuilder.Settings getReadOnlyDataSourceConfig();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a value used to represent TRUE in the database.
|
* Return a value used to represent TRUE in the database.
|
||||||
|
|||||||
@@ -3,10 +3,9 @@ package io.ebean;
|
|||||||
import io.ebean.config.ContainerConfig;
|
import io.ebean.config.ContainerConfig;
|
||||||
import io.ebean.service.SpiContainer;
|
import io.ebean.service.SpiContainer;
|
||||||
import io.ebean.service.SpiContainerFactory;
|
import io.ebean.service.SpiContainerFactory;
|
||||||
|
|
||||||
import jakarta.persistence.PersistenceException;
|
import jakarta.persistence.PersistenceException;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
@@ -146,12 +145,9 @@ public final class DatabaseFactory {
|
|||||||
if (container != null) {
|
if (container != null) {
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (containerConfig == null) {
|
if (containerConfig == null) {
|
||||||
// effectively load configuration from ebean.properties
|
// effectively load configuration from ebean.properties
|
||||||
Properties properties = DbPrimary.getProperties();
|
|
||||||
containerConfig = new ContainerConfig();
|
containerConfig = new ContainerConfig();
|
||||||
containerConfig.loadFromProperties(properties);
|
|
||||||
}
|
}
|
||||||
container = createContainer(containerConfig);
|
container = createContainer(containerConfig);
|
||||||
return container;
|
return container;
|
||||||
@@ -160,7 +156,7 @@ public final class DatabaseFactory {
|
|||||||
/**
|
/**
|
||||||
* Create the container instance using the configuration.
|
* Create the container instance using the configuration.
|
||||||
*/
|
*/
|
||||||
protected static SpiContainer createContainer(ContainerConfig containerConfig) {
|
private static SpiContainer createContainer(ContainerConfig containerConfig) {
|
||||||
Iterator<SpiContainerFactory> factories = ServiceLoader.load(SpiContainerFactory.class).iterator();
|
Iterator<SpiContainerFactory> factories = ServiceLoader.load(SpiContainerFactory.class).iterator();
|
||||||
if (factories.hasNext()) {
|
if (factories.hasNext()) {
|
||||||
return factories.next().create(containerConfig);
|
return factories.next().create(containerConfig);
|
||||||
|
|||||||
@@ -44,25 +44,12 @@ final class DbPrimary {
|
|||||||
* Return the default database name.
|
* Return the default database name.
|
||||||
*/
|
*/
|
||||||
static String getDefaultServerName() {
|
static String getDefaultServerName() {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
getProperties();
|
|
||||||
return defaultServerName;
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the default configuration Properties.
|
|
||||||
*/
|
|
||||||
static Properties getProperties() {
|
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
if (defaultServerName == null) {
|
if (defaultServerName == null) {
|
||||||
defaultServerName = determineDefaultServerName();
|
defaultServerName = determineDefaultServerName();
|
||||||
}
|
}
|
||||||
return Config.asProperties();
|
return defaultServerName;
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package io.ebean;
|
|||||||
import io.avaje.lang.NonNullApi;
|
import io.avaje.lang.NonNullApi;
|
||||||
import io.avaje.lang.Nullable;
|
import io.avaje.lang.Nullable;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.sql.Connection;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -206,14 +208,19 @@ public interface DtoQuery<T> extends CancelableQuery {
|
|||||||
*/
|
*/
|
||||||
DtoQuery<T> usingTransaction(Transaction transaction);
|
DtoQuery<T> usingTransaction(Transaction transaction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the query using the given connection.
|
||||||
|
*/
|
||||||
|
DtoQuery<T> usingConnection(Connection connection);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that the master DataSource is used if there is a read only data source
|
* Ensure that the master DataSource is used if there is a read only data source
|
||||||
* being used (that is using a read replica database potentially with replication lag).
|
* being used (that is using a read replica database potentially with replication lag).
|
||||||
* <p>
|
* <p>
|
||||||
* When the database is configured with a read-only DataSource via
|
* When the database is configured with a read-only DataSource via
|
||||||
* say {@link io.ebean.config.DatabaseConfig#setReadOnlyDataSource(DataSource)} then
|
* say {@link io.ebean.DatabaseBuilder#readOnlyDataSource(DataSource)} then
|
||||||
* by default when a query is run without an active transaction, it uses the read-only data
|
* by default when a query is run without an active transaction, it uses the read-only data
|
||||||
* source. We we use {@code usingMaster()} to instead ensure that the query is executed
|
* source. We use {@code usingMaster()} to instead ensure that the query is executed
|
||||||
* against the master data source.
|
* against the master data source.
|
||||||
*/
|
*/
|
||||||
DtoQuery<T> usingMaster();
|
DtoQuery<T> usingMaster();
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package io.ebean;
|
||||||
|
|
||||||
|
import io.avaje.lang.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options to be used with insert such as ON CONFLICT DO UPDATE | NOTHING.
|
||||||
|
*/
|
||||||
|
public interface InsertOptions {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use ON CONFLICT UPDATE with automatic determination of the unique columns to conflict on.
|
||||||
|
* <p>
|
||||||
|
* Uses mapping to determine the unique columns - {@code @Column(unique=true)} and {@code @Index(unique=true)} .
|
||||||
|
*/
|
||||||
|
InsertOptions ON_CONFLICT_UPDATE = InsertOptions.builder()
|
||||||
|
.onConflictUpdate()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use ON CONFLICT DO NOTHING with automatic determination of the unique columns to conflict on.
|
||||||
|
* <p>
|
||||||
|
* Uses mapping to determine the unique columns - {@code @Column(unique=true)} and {@code @Index(unique=true)} .
|
||||||
|
*/
|
||||||
|
InsertOptions ON_CONFLICT_NOTHING = InsertOptions.builder()
|
||||||
|
.onConflictNothing()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a builder for InsertOptions.
|
||||||
|
*/
|
||||||
|
static Builder builder() {
|
||||||
|
return new DInsertOptionsBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the constraint name that is used for ON CONFLICT.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
String constraint();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the unique columns that is used for ON CONFLICT.
|
||||||
|
* <p>
|
||||||
|
* When not explicitly set will use mapping like {@code @Column(unique=true)} to determine the
|
||||||
|
* non-unique columns.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
String uniqueColumns();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the ON CONFLICT UPDATE SET clause.
|
||||||
|
* <p>
|
||||||
|
* When not set will use the non-unique columns.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
String updateSet();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return if GetGeneratedKeys should be used to fetch the generated keys after insert.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
Boolean getGetGeneratedKeys();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the key for these build options.
|
||||||
|
*/
|
||||||
|
String key();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The builder for InsertOptions.
|
||||||
|
*/
|
||||||
|
interface Builder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use a ON CONFLICT UPDATE automatically determining the unique columns.
|
||||||
|
*/
|
||||||
|
Builder onConflictUpdate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use a ON CONFLICT DO NOTHING automatically determining the unique columns.
|
||||||
|
*/
|
||||||
|
Builder onConflictNothing();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify an explicit conflict constraint name.
|
||||||
|
* <p>
|
||||||
|
* When this is used then unique columns will not be used.
|
||||||
|
*/
|
||||||
|
Builder constraint(String constraint);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the unique columns for the conflict target.
|
||||||
|
* <p>
|
||||||
|
* When not specified and constraint is also not specified then
|
||||||
|
* it will automatically determine the unique columns
|
||||||
|
* based on mapping like {@code @Column(unique=true)} and
|
||||||
|
* {@code @Index(unique=true)} .
|
||||||
|
*/
|
||||||
|
Builder uniqueColumns(String uniqueColumns);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the ON CONFLICT DO UPDATE SET clause.
|
||||||
|
* <p>
|
||||||
|
* When not specified ebean will include all the non-unique columns.
|
||||||
|
*/
|
||||||
|
Builder updateSet(String updateSet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify if GetGeneratedKeys should be used to return generated keys.
|
||||||
|
*/
|
||||||
|
Builder getGeneratedKeys(boolean getGeneratedKeys);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build and return the insert options.
|
||||||
|
*/
|
||||||
|
InsertOptions build();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -702,9 +702,9 @@ public interface Query<T> extends CancelableQuery {
|
|||||||
* being used (that is using a read replica database potentially with replication lag).
|
* being used (that is using a read replica database potentially with replication lag).
|
||||||
* <p>
|
* <p>
|
||||||
* When the database is configured with a read-only DataSource via
|
* When the database is configured with a read-only DataSource via
|
||||||
* say {@link io.ebean.config.DatabaseConfig#setReadOnlyDataSource(DataSource)} then
|
* say {@link io.ebean.DatabaseBuilder#readOnlyDataSource(DataSource)} then
|
||||||
* by default when a query is run without an active transaction, it uses the read-only data
|
* by default when a query is run without an active transaction, it uses the read-only data
|
||||||
* source. We we use {@code usingMaster()} to instead ensure that the query is executed
|
* source. We use {@code usingMaster()} to instead ensure that the query is executed
|
||||||
* against the master data source.
|
* against the master data source.
|
||||||
*/
|
*/
|
||||||
Query<T> usingMaster();
|
Query<T> usingMaster();
|
||||||
@@ -970,6 +970,25 @@ public interface Query<T> extends CancelableQuery {
|
|||||||
@Nullable
|
@Nullable
|
||||||
<A> A findSingleAttribute();
|
<A> A findSingleAttribute();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the query returning a single optional attribute value.
|
||||||
|
* <p>
|
||||||
|
* <h3>Example</h3>
|
||||||
|
* <pre>{@code
|
||||||
|
*
|
||||||
|
* Optional<String> maybeName =
|
||||||
|
* new QCustomer()
|
||||||
|
* .select(name)
|
||||||
|
* .id.eq(42)
|
||||||
|
* .status.eq(NEW)
|
||||||
|
* .findSingleAttributeOrEmpty();
|
||||||
|
*
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @return an optional value for the selected property
|
||||||
|
*/
|
||||||
|
<A> Optional<A> findSingleAttributeOrEmpty();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if this is countDistinct query.
|
* Return true if this is countDistinct query.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package io.ebean;
|
|||||||
import io.avaje.lang.NonNullApi;
|
import io.avaje.lang.NonNullApi;
|
||||||
import io.avaje.lang.Nullable;
|
import io.avaje.lang.Nullable;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.sql.Connection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@@ -45,14 +47,19 @@ public interface SqlQuery extends Serializable, CancelableQuery {
|
|||||||
*/
|
*/
|
||||||
SqlQuery usingTransaction(Transaction transaction);
|
SqlQuery usingTransaction(Transaction transaction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the query using the given connection.
|
||||||
|
*/
|
||||||
|
SqlQuery usingConnection(Connection connection);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that the master DataSource is used if there is a read only data source
|
* Ensure that the master DataSource is used if there is a read only data source
|
||||||
* being used (that is using a read replica database potentially with replication lag).
|
* being used (that is using a read replica database potentially with replication lag).
|
||||||
* <p>
|
* <p>
|
||||||
* When the database is configured with a read-only DataSource via
|
* When the database is configured with a read-only DataSource via
|
||||||
* say {@link io.ebean.config.DatabaseConfig#setReadOnlyDataSource(DataSource)} then
|
* say {@link io.ebean.DatabaseBuilder#readOnlyDataSource(DataSource)}then
|
||||||
* by default when a query is run without an active transaction, it uses the read-only data
|
* by default when a query is run without an active transaction, it uses the read-only data
|
||||||
* source. We we use {@code usingMaster()} to instead ensure that the query is executed
|
* source. We use {@code usingMaster()} to instead ensure that the query is executed
|
||||||
* against the master data source.
|
* against the master data source.
|
||||||
*/
|
*/
|
||||||
SqlQuery usingMaster();
|
SqlQuery usingMaster();
|
||||||
|
|||||||
@@ -141,14 +141,16 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public BeanCollectionAdd collectionAdd() {
|
||||||
* Set the actual underlying list.
|
if (list == null) {
|
||||||
* <p>
|
list = new ArrayList<>();
|
||||||
* This is primarily for the deferred fetching function.
|
}
|
||||||
*/
|
return this;
|
||||||
@SuppressWarnings("unchecked")
|
}
|
||||||
public void setActualList(List<?> list) {
|
|
||||||
this.list = (List<E>) list;
|
public void refresh(ModifyListenMode modifyListenMode, BeanList<E> newList) {
|
||||||
|
setModifyListening(modifyListenMode);
|
||||||
|
this.list = newList.actualList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
package io.ebean.common;
|
package io.ebean.common;
|
||||||
|
|
||||||
import io.ebean.bean.BeanCollection;
|
import io.ebean.bean.*;
|
||||||
import io.ebean.bean.BeanCollectionLoader;
|
|
||||||
import io.ebean.bean.EntityBean;
|
|
||||||
import io.ebean.bean.ToStringBuilder;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -17,12 +14,12 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
|||||||
/**
|
/**
|
||||||
* The underlying map implementation.
|
* The underlying map implementation.
|
||||||
*/
|
*/
|
||||||
private Map<K, E> map;
|
private LinkedHashMap<K, E> map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create with a given Map.
|
* Create with a given Map.
|
||||||
*/
|
*/
|
||||||
public BeanMap(Map<K, E> map) {
|
public BeanMap(LinkedHashMap<K, E> map) {
|
||||||
this.map = map;
|
this.map = map;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,18 +157,23 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public LinkedHashMap<K, E> collectionAdd() {
|
||||||
* Set the actual underlying map. Used for performing lazy fetch.
|
if (map == null) {
|
||||||
*/
|
map = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void setActualMap(Map<?, ?> map) {
|
public void refresh(ModifyListenMode modifyListenMode, BeanMap<?, ?> newMap) {
|
||||||
this.map = (Map<K, E>) map;
|
setModifyListening(modifyListenMode);
|
||||||
|
this.map = (LinkedHashMap<K, E>) newMap.actualMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the actual underlying map.
|
* Return the actual underlying map.
|
||||||
*/
|
*/
|
||||||
public Map<K, E> actualMap() {
|
public LinkedHashMap<K, E> actualMap() {
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ package io.ebean.common;
|
|||||||
import io.ebean.bean.*;
|
import io.ebean.bean.*;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set capable of lazy loading and modification aware.
|
* Set capable of lazy loading and modification aware.
|
||||||
@@ -18,12 +15,12 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
|||||||
/**
|
/**
|
||||||
* The underlying Set implementation.
|
* The underlying Set implementation.
|
||||||
*/
|
*/
|
||||||
private Set<E> set;
|
private LinkedHashSet<E> set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create with a specific Set implementation.
|
* Create with a specific Set implementation.
|
||||||
*/
|
*/
|
||||||
public BeanSet(Set<E> set) {
|
public BeanSet(LinkedHashSet<E> set) {
|
||||||
this.set = set;
|
this.set = set;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,18 +141,22 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public BeanCollectionAdd collectionAdd() {
|
||||||
* Set the underlying set (used for lazy fetch).
|
if (set == null) {
|
||||||
*/
|
set = new LinkedHashSet<>();
|
||||||
@SuppressWarnings("unchecked")
|
}
|
||||||
public void setActualSet(Set<?> set) {
|
return this;
|
||||||
this.set = (Set<E>) set;
|
}
|
||||||
|
|
||||||
|
public void refresh(ModifyListenMode modifyListenMode, BeanSet<E> newSet) {
|
||||||
|
setModifyListening(modifyListenMode);
|
||||||
|
this.set = newSet.actualSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the actual underlying set.
|
* Return the actual underlying set.
|
||||||
*/
|
*/
|
||||||
public Set<E> actualSet() {
|
public LinkedHashSet<E> actualSet() {
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package io.ebean.config;
|
package io.ebean.config;
|
||||||
|
|
||||||
|
import io.avaje.config.Config;
|
||||||
|
import io.avaje.config.Configuration;
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,8 +18,17 @@ public class ContainerConfig {
|
|||||||
private String namespace;
|
private String namespace;
|
||||||
private String podName;
|
private String podName;
|
||||||
private int port;
|
private int port;
|
||||||
|
|
||||||
private Properties properties;
|
private Properties properties;
|
||||||
|
private Configuration configuration;
|
||||||
|
|
||||||
|
public ContainerConfig() {
|
||||||
|
this.configuration = Config.asConfiguration();
|
||||||
|
this.active = configuration.getBool("ebean.cluster.active", active);
|
||||||
|
this.serviceName = configuration.getNullable("ebean.cluster.serviceName", serviceName);
|
||||||
|
this.namespace = configuration.getNullable("ebean.cluster.namespace", namespace);
|
||||||
|
this.podName = configuration.getNullable("ebean.cluster.podName", podName);
|
||||||
|
this.port = configuration.getInt("ebean.cluster.port", 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the service name.
|
* Return the service name.
|
||||||
@@ -92,7 +104,7 @@ public class ContainerConfig {
|
|||||||
* Return the deployment properties.
|
* Return the deployment properties.
|
||||||
*/
|
*/
|
||||||
public Properties getProperties() {
|
public Properties getProperties() {
|
||||||
return properties;
|
return properties != null ? properties : configuration.asProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,26 +114,4 @@ public class ContainerConfig {
|
|||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the settings from properties.
|
|
||||||
*/
|
|
||||||
public void loadFromProperties(Properties properties) {
|
|
||||||
this.properties = properties;
|
|
||||||
this.active = getProperty(properties, "ebean.cluster.active", active);
|
|
||||||
this.serviceName = properties.getProperty("ebean.cluster.serviceName", serviceName);
|
|
||||||
this.namespace = properties.getProperty("ebean.cluster.namespace", namespace);
|
|
||||||
this.podName = properties.getProperty("ebean.cluster.podName", podName);
|
|
||||||
String portParam = properties.getProperty("ebean.cluster.port");
|
|
||||||
if (portParam != null) {
|
|
||||||
this.port = Integer.parseInt(portParam);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the boolean property setting.
|
|
||||||
*/
|
|
||||||
protected boolean getProperty(Properties properties, String key, boolean defaultValue) {
|
|
||||||
return "true".equalsIgnoreCase(properties.getProperty(key, Boolean.toString(defaultValue)));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import java.time.Clock;
|
|||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -303,6 +304,8 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
|
|||||||
|
|
||||||
private boolean skipDataSourceCheck;
|
private boolean skipDataSourceCheck;
|
||||||
|
|
||||||
|
private boolean readOnlyDatabase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data source (if programmatically provided).
|
* The data source (if programmatically provided).
|
||||||
*/
|
*/
|
||||||
@@ -316,7 +319,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
|
|||||||
/**
|
/**
|
||||||
* The data source config.
|
* The data source config.
|
||||||
*/
|
*/
|
||||||
private DataSourceBuilder dataSourceConfig = DataSourceBuilder.create();
|
private DataSourceBuilder.Settings dataSourceConfig = DataSourceBuilder.create().settings();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When true create a read only DataSource using readOnlyDataSourceConfig defaulting values from dataSourceConfig.
|
* When true create a read only DataSource using readOnlyDataSourceConfig defaulting values from dataSourceConfig.
|
||||||
@@ -329,7 +332,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
|
|||||||
/**
|
/**
|
||||||
* Optional configuration for a read only data source.
|
* Optional configuration for a read only data source.
|
||||||
*/
|
*/
|
||||||
private DataSourceBuilder readOnlyDataSourceConfig = DataSourceBuilder.create();
|
private DataSourceBuilder.Settings readOnlyDataSourceConfig = DataSourceBuilder.create().settings();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional - the database schema that should be used to own the tables etc.
|
* Optional - the database schema that should be used to own the tables etc.
|
||||||
@@ -560,6 +563,12 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DatabaseBuilder apply(Consumer<DatabaseBuilder.Settings> applyConfiguration) {
|
||||||
|
applyConfiguration.accept(this);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Clock getClock() {
|
public Clock getClock() {
|
||||||
return clock;
|
return clock;
|
||||||
@@ -1327,7 +1336,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean skipDataSourceCheck() {
|
public boolean skipDataSourceCheck() {
|
||||||
return skipDataSourceCheck;
|
return skipDataSourceCheck || readOnlyDatabase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1336,6 +1345,17 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DatabaseBuilder readOnlyDatabase(boolean readOnlyDatabase) {
|
||||||
|
this.readOnlyDatabase = readOnlyDatabase;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean readOnlyDatabase() {
|
||||||
|
return readOnlyDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataSource getDataSource() {
|
public DataSource getDataSource() {
|
||||||
return dataSource;
|
return dataSource;
|
||||||
@@ -1359,13 +1379,13 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataSourceBuilder getDataSourceConfig() {
|
public DataSourceBuilder.Settings getDataSourceConfig() {
|
||||||
return dataSourceConfig;
|
return dataSourceConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DatabaseConfig setDataSourceConfig(DataSourceBuilder dataSourceConfig) {
|
public DatabaseConfig setDataSourceConfig(DataSourceBuilder dataSourceConfig) {
|
||||||
this.dataSourceConfig = dataSourceConfig;
|
this.dataSourceConfig = dataSourceConfig.settings();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1381,13 +1401,13 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataSourceBuilder getReadOnlyDataSourceConfig() {
|
public DataSourceBuilder.Settings getReadOnlyDataSourceConfig() {
|
||||||
return readOnlyDataSourceConfig;
|
return readOnlyDataSourceConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DatabaseConfig setReadOnlyDataSourceConfig(DataSourceBuilder readOnlyDataSourceConfig) {
|
public DatabaseConfig setReadOnlyDataSourceConfig(DataSourceBuilder readOnly) {
|
||||||
this.readOnlyDataSourceConfig = readOnlyDataSourceConfig;
|
this.readOnlyDataSourceConfig = readOnly == null ? null : readOnly.settings();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2098,7 +2118,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
|
|||||||
loadAutoTuneSettings(p);
|
loadAutoTuneSettings(p);
|
||||||
|
|
||||||
if (dataSourceConfig == null) {
|
if (dataSourceConfig == null) {
|
||||||
dataSourceConfig = DataSourceBuilder.create();
|
dataSourceConfig = DataSourceBuilder.create().settings();
|
||||||
}
|
}
|
||||||
loadDataSourceSettings(p);
|
loadDataSourceSettings(p);
|
||||||
|
|
||||||
@@ -2108,6 +2128,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
|
|||||||
loadDocStoreSettings(p);
|
loadDocStoreSettings(p);
|
||||||
|
|
||||||
defaultServer = p.getBoolean("defaultServer", defaultServer);
|
defaultServer = p.getBoolean("defaultServer", defaultServer);
|
||||||
|
readOnlyDatabase = p.getBoolean("readOnlyDatabase", readOnlyDatabase);
|
||||||
autoPersistUpdates = p.getBoolean("autoPersistUpdates", autoPersistUpdates);
|
autoPersistUpdates = p.getBoolean("autoPersistUpdates", autoPersistUpdates);
|
||||||
loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo);
|
loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo);
|
||||||
maxCallStack = p.getInt("maxCallStack", maxCallStack);
|
maxCallStack = p.getInt("maxCallStack", maxCallStack);
|
||||||
|
|||||||
@@ -0,0 +1,450 @@
|
|||||||
|
package io.ebean.common;
|
||||||
|
|
||||||
|
import io.ebean.bean.BeanCollection;
|
||||||
|
import io.ebean.bean.BeanCollectionLoader;
|
||||||
|
import io.ebean.bean.EntityBean;
|
||||||
|
import io.ebean.bean.ToStringBuilder;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map capable of lazy loading and modification aware.
|
||||||
|
*/
|
||||||
|
public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements SequencedMap<K, E> {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The underlying map implementation.
|
||||||
|
*/
|
||||||
|
private LinkedHashMap<K, E> map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create with a given Map.
|
||||||
|
*/
|
||||||
|
public BeanMap(LinkedHashMap<K, E> map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create using a underlying LinkedHashMap.
|
||||||
|
*/
|
||||||
|
public BeanMap() {
|
||||||
|
this(new LinkedHashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeanMap(BeanCollectionLoader ebeanServer, EntityBean ownerBean, String propertyName) {
|
||||||
|
super(ebeanServer, ownerBean, propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toString(ToStringBuilder builder) {
|
||||||
|
if (map == null || map.isEmpty()) {
|
||||||
|
builder.addRaw("{}");
|
||||||
|
} else {
|
||||||
|
builder.addRaw("{");
|
||||||
|
for (Entry<K, E> entry : map.entrySet()) {
|
||||||
|
builder.add(String.valueOf(entry.getKey()), entry.getValue());
|
||||||
|
}
|
||||||
|
builder.addRaw("}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset(EntityBean ownerBean, String propertyName) {
|
||||||
|
this.ownerBean = ownerBean;
|
||||||
|
this.propertyName = propertyName;
|
||||||
|
this.map = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSkipSave() {
|
||||||
|
return map == null || (map.isEmpty() && !holdsModifications());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void loadFrom(BeanCollection<?> other) {
|
||||||
|
BeanMap<K, E> otherMap = (BeanMap<K, E>) other;
|
||||||
|
internalPutNull();
|
||||||
|
map.putAll(otherMap.actualMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void internalPutNull() {
|
||||||
|
if (map == null) {
|
||||||
|
map = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void internalPut(Object key, Object bean) {
|
||||||
|
if (map == null) {
|
||||||
|
map = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
if (key != null) {
|
||||||
|
map.put((K) key, (E) bean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void internalPutWithCheck(Object key, Object bean) {
|
||||||
|
if (map == null || key == null || !map.containsKey(key)) {
|
||||||
|
internalPut(key, bean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void internalAddWithCheck(Object bean) {
|
||||||
|
throw new RuntimeException("Not allowed for map");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void internalAdd(Object bean) {
|
||||||
|
throw new RuntimeException("Not allowed for map");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the underlying map has been populated. Returns false if it
|
||||||
|
* has a deferred fetch pending.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isPopulated() {
|
||||||
|
return map != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if this is a reference (lazy loading) bean collection. This is
|
||||||
|
* the same as !isPopulated();
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isReference() {
|
||||||
|
return map == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkEmptyLazyLoad() {
|
||||||
|
if (map == null) {
|
||||||
|
map = new LinkedHashMap<>();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initClear() {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
if (map == null) {
|
||||||
|
if (!disableLazyLoad && modifyListening) {
|
||||||
|
lazyLoadCollection(true);
|
||||||
|
} else {
|
||||||
|
map = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
if (map == null) {
|
||||||
|
if (disableLazyLoad) {
|
||||||
|
map = new LinkedHashMap<>();
|
||||||
|
} else {
|
||||||
|
lazyLoadCollection(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LinkedHashMap<K, E> collectionAdd() {
|
||||||
|
if (map == null) {
|
||||||
|
map = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void refresh(ModifyListenMode modifyListenMode, BeanMap<?, ?> newMap) {
|
||||||
|
setModifyListening(modifyListenMode);
|
||||||
|
this.map = (LinkedHashMap<K, E>) newMap.actualMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the actual underlying map.
|
||||||
|
*/
|
||||||
|
public LinkedHashMap<K, E> actualMap() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the collection of beans (map values).
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Collection<E> actualDetails() {
|
||||||
|
return map.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the map entrySet.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Collection<?> actualEntries() {
|
||||||
|
return map.entrySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (map == null) {
|
||||||
|
return "BeanMap<deferred>";
|
||||||
|
} else {
|
||||||
|
return map.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equal if object is a Map and equal in a Map sense.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
init();
|
||||||
|
return map.equals(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
init();
|
||||||
|
return map.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
checkReadOnly();
|
||||||
|
initClear();
|
||||||
|
if (modifyListening) {
|
||||||
|
// add all beans to the removal list
|
||||||
|
for (E bean : map.values()) {
|
||||||
|
modifyRemoval(bean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsKey(Object key) {
|
||||||
|
init();
|
||||||
|
return map.containsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsValue(Object value) {
|
||||||
|
init();
|
||||||
|
return map.containsValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Entry<K, E>> entrySet() {
|
||||||
|
init();
|
||||||
|
if (readOnly) {
|
||||||
|
return Collections.unmodifiableSet(map.entrySet());
|
||||||
|
}
|
||||||
|
return modifyListening ? new ModifyEntrySet<>(this, map.entrySet()) : map.entrySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public E get(Object key) {
|
||||||
|
init();
|
||||||
|
return map.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
init();
|
||||||
|
return map.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<K> keySet() {
|
||||||
|
init();
|
||||||
|
if (readOnly) {
|
||||||
|
return Collections.unmodifiableSet(map.keySet());
|
||||||
|
}
|
||||||
|
return modifyListening ? new ModifyKeySet<>(this, map.keySet()) : map.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public E put(K key, E value) {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
E oldBean = map.put(key, value);
|
||||||
|
if (value != oldBean) {
|
||||||
|
// register the add of the new and the removal of the old
|
||||||
|
modifyAddition(value);
|
||||||
|
modifyRemoval(oldBean);
|
||||||
|
}
|
||||||
|
return oldBean;
|
||||||
|
} else {
|
||||||
|
return map.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putAll(Map<? extends K, ? extends E> puts) {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
for (Entry<? extends K, ? extends E> entry : puts.entrySet()) {
|
||||||
|
Object oldBean = map.put(entry.getKey(), entry.getValue());
|
||||||
|
if (entry.getValue() != oldBean) {
|
||||||
|
modifyAddition(entry.getValue());
|
||||||
|
modifyRemoval(oldBean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
map.putAll(puts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addBean(E bean) {
|
||||||
|
throw new IllegalStateException("Method not allowed on Map. Please use List instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeBean(E bean) {
|
||||||
|
throw new IllegalStateException("Method not allowed on Map. Please use List instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public E remove(Object key) {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
E o = map.remove(key);
|
||||||
|
modifyRemoval(o);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
return map.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
init();
|
||||||
|
return map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<E> values() {
|
||||||
|
init();
|
||||||
|
if (readOnly) {
|
||||||
|
return Collections.unmodifiableCollection(map.values());
|
||||||
|
}
|
||||||
|
return modifyListening ? new ModifyCollection<>(this, map.values()) : map.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BeanCollection<E> shallowCopy() {
|
||||||
|
BeanMap<K, E> copy = new BeanMap<>(new LinkedHashMap<>(map));
|
||||||
|
copy.setFromOriginal(this);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SequencedMap<K, E> reversed() {
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
throw new UnsupportedOperationException("Not supported on modify listening map");
|
||||||
|
}
|
||||||
|
return map.reversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Entry<K, E> firstEntry() {
|
||||||
|
init();
|
||||||
|
return map.firstEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Entry<K, E> lastEntry() {
|
||||||
|
init();
|
||||||
|
return map.lastEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Entry<K, E> pollFirstEntry() {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
var entry = map.pollFirstEntry();
|
||||||
|
if (modifyListening && entry != null) {
|
||||||
|
modifyRemoval(entry.getValue());
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Entry<K, E> pollLastEntry() {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
var entry = map.pollLastEntry();
|
||||||
|
if (modifyListening && entry != null) {
|
||||||
|
modifyRemoval(entry.getValue());
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public E putFirst(K key, E value) {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
E oldBean = map.putFirst(key, value);
|
||||||
|
if (value != oldBean) {
|
||||||
|
// register the add of the new and the removal of the old
|
||||||
|
modifyAddition(value);
|
||||||
|
modifyRemoval(oldBean);
|
||||||
|
}
|
||||||
|
return oldBean;
|
||||||
|
} else {
|
||||||
|
return map.putFirst(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public E putLast(K key, E value) {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
E oldBean = map.putLast(key, value);
|
||||||
|
if (value != oldBean) {
|
||||||
|
// register the add of the new and the removal of the old
|
||||||
|
modifyAddition(value);
|
||||||
|
modifyRemoval(oldBean);
|
||||||
|
}
|
||||||
|
return oldBean;
|
||||||
|
} else {
|
||||||
|
return map.putLast(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SequencedSet<K> sequencedKeySet() {
|
||||||
|
init();
|
||||||
|
return map.sequencedKeySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SequencedCollection<E> sequencedValues() {
|
||||||
|
init();
|
||||||
|
return map.sequencedValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SequencedSet<Entry<K, E>> sequencedEntrySet() {
|
||||||
|
init();
|
||||||
|
return map.sequencedEntrySet();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,460 @@
|
|||||||
|
package io.ebean.common;
|
||||||
|
|
||||||
|
import io.ebean.bean.*;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.SequencedSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set capable of lazy loading and modification aware.
|
||||||
|
*/
|
||||||
|
public final class BeanSet<E> extends AbstractBeanCollection<E> implements SequencedSet<E>, BeanCollectionAdd {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The underlying Set implementation.
|
||||||
|
*/
|
||||||
|
private LinkedHashSet<E> set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create with a specific Set implementation.
|
||||||
|
*/
|
||||||
|
public BeanSet(LinkedHashSet<E> set) {
|
||||||
|
this.set = set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create using an underlying LinkedHashSet.
|
||||||
|
*/
|
||||||
|
public BeanSet() {
|
||||||
|
this(new LinkedHashSet<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeanSet(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
|
||||||
|
super(loader, ownerBean, propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toString(ToStringBuilder builder) {
|
||||||
|
builder.addCollection(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset(EntityBean ownerBean, String propertyName) {
|
||||||
|
this.ownerBean = ownerBean;
|
||||||
|
this.propertyName = propertyName;
|
||||||
|
this.set = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSkipSave() {
|
||||||
|
return set == null || (set.isEmpty() && !holdsModifications());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void addEntityBean(EntityBean bean) {
|
||||||
|
set.add((E) bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void loadFrom(BeanCollection<?> other) {
|
||||||
|
if (set == null) {
|
||||||
|
set = new LinkedHashSet<>();
|
||||||
|
}
|
||||||
|
set.addAll((Collection<? extends E>) other.actualDetails());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void internalAddWithCheck(Object bean) {
|
||||||
|
// set add() already de-dups so just add it
|
||||||
|
internalAdd(bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void internalAdd(Object bean) {
|
||||||
|
if (set == null) {
|
||||||
|
set = new LinkedHashSet<>();
|
||||||
|
}
|
||||||
|
if (bean != null) {
|
||||||
|
set.add((E) bean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the underlying set has its data.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isPopulated() {
|
||||||
|
return set != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if this is a reference (lazy loading) bean collection. This is
|
||||||
|
* the same as !isPopulated();
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isReference() {
|
||||||
|
return set == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkEmptyLazyLoad() {
|
||||||
|
if (set == null) {
|
||||||
|
set = new LinkedHashSet<>();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initClear() {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
if (set == null) {
|
||||||
|
if (!disableLazyLoad && modifyListening) {
|
||||||
|
lazyLoadCollection(false);
|
||||||
|
} else {
|
||||||
|
set = new LinkedHashSet<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
if (set == null) {
|
||||||
|
if (disableLazyLoad) {
|
||||||
|
set = new LinkedHashSet<>();
|
||||||
|
} else {
|
||||||
|
lazyLoadCollection(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeanCollectionAdd collectionAdd() {
|
||||||
|
if (set == null) {
|
||||||
|
set = new LinkedHashSet<>();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refresh(ModifyListenMode modifyListenMode, BeanSet<E> newSet) {
|
||||||
|
setModifyListening(modifyListenMode);
|
||||||
|
this.set = newSet.actualSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the actual underlying set.
|
||||||
|
*/
|
||||||
|
public LinkedHashSet<E> actualSet() {
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<E> actualDetails() {
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<?> actualEntries() {
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (set == null) {
|
||||||
|
return "BeanSet<deferred>";
|
||||||
|
} else {
|
||||||
|
return set.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equal if obj is a Set and equal in a Set sense.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
init();
|
||||||
|
return set.equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
init();
|
||||||
|
return set.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addBean(E bean) {
|
||||||
|
add(bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeBean(E bean) {
|
||||||
|
if (set.remove(bean)) {
|
||||||
|
getModifyHolder().modifyRemoval(bean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------//
|
||||||
|
// proxy method for map
|
||||||
|
// -----------------------------------------------------//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean add(E bean) {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
if (set.add(bean)) {
|
||||||
|
modifyAddition(bean);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return set.add(bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addAll(Collection<? extends E> beans) {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
boolean changed = false;
|
||||||
|
for (E bean : beans) {
|
||||||
|
if (set.add(bean)) {
|
||||||
|
// register the addition of the bean
|
||||||
|
modifyAddition(bean);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
return set.addAll(beans);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
checkReadOnly();
|
||||||
|
initClear();
|
||||||
|
if (modifyListening) {
|
||||||
|
for (E bean : set) {
|
||||||
|
modifyRemoval(bean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Object bean) {
|
||||||
|
init();
|
||||||
|
return set.contains(bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsAll(Collection<?> beans) {
|
||||||
|
init();
|
||||||
|
return set.containsAll(beans);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
init();
|
||||||
|
return set.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<E> iterator() {
|
||||||
|
init();
|
||||||
|
if (readOnly) {
|
||||||
|
return new ReadOnlyIterator<>(set.iterator());
|
||||||
|
}
|
||||||
|
if (modifyListening) {
|
||||||
|
return new ModifyIterator<>(this, set.iterator());
|
||||||
|
}
|
||||||
|
return set.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(Object bean) {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
if (set.remove(bean)) {
|
||||||
|
modifyRemoval(bean);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return set.remove(bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeAll(Collection<?> beans) {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
boolean changed = false;
|
||||||
|
for (Object bean : beans) {
|
||||||
|
if (set.remove(bean)) {
|
||||||
|
modifyRemoval(bean);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
return set.removeAll(beans);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean retainAll(Collection<?> beans) {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
boolean changed = false;
|
||||||
|
Iterator<?> it = set.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Object bean = it.next();
|
||||||
|
if (!beans.contains(bean)) {
|
||||||
|
// not retaining this bean so add it to the removal list
|
||||||
|
it.remove();
|
||||||
|
modifyRemoval(bean);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
return set.retainAll(beans);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
init();
|
||||||
|
return set.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] toArray() {
|
||||||
|
init();
|
||||||
|
return set.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T[] toArray(T[] array) {
|
||||||
|
init();
|
||||||
|
//noinspection SuspiciousToArrayCall
|
||||||
|
return set.toArray(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SequencedSet<E> reversed() {
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
throw new UnsupportedOperationException("Not supported on modify listening set");
|
||||||
|
}
|
||||||
|
return set.reversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addFirst(E bean) {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
modifyAddition(bean);
|
||||||
|
}
|
||||||
|
set.addFirst(bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addLast(E bean) {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
modifyAddition(bean);
|
||||||
|
}
|
||||||
|
set.addLast(bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public E getFirst() {
|
||||||
|
init();
|
||||||
|
return set.getFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public E getLast() {
|
||||||
|
init();
|
||||||
|
return set.getLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public E removeFirst() {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
var bean = set.removeFirst();
|
||||||
|
modifyRemoval(bean);
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
return set.removeFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public E removeLast() {
|
||||||
|
checkReadOnly();
|
||||||
|
init();
|
||||||
|
if (modifyListening) {
|
||||||
|
var bean = set.removeLast();
|
||||||
|
modifyRemoval(bean);
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
return set.removeLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class ReadOnlyIterator<E> implements Iterator<E>, Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 2577697326745352605L;
|
||||||
|
|
||||||
|
private final Iterator<E> it;
|
||||||
|
|
||||||
|
ReadOnlyIterator(Iterator<E> it) {
|
||||||
|
this.it = it;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return it.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public E next() {
|
||||||
|
return it.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
throw new IllegalStateException("This collection is in ReadOnly mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BeanCollection<E> shallowCopy() {
|
||||||
|
BeanSet<E> copy = new BeanSet<>(new LinkedHashSet<>(set));
|
||||||
|
copy.setFromOriginal(this);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,9 +21,4 @@ class DbPrimaryTest {
|
|||||||
assertEquals("h2", DbPrimary.getDefaultServerName());
|
assertEquals("h2", DbPrimary.getDefaultServerName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void testLoadProperties() {
|
|
||||||
Properties properties = DbPrimary.getProperties();
|
|
||||||
assertFalse(properties.isEmpty());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,13 +136,13 @@ class ToStringBuilderTest {
|
|||||||
@Test
|
@Test
|
||||||
void beanSet_null_empty() {
|
void beanSet_null_empty() {
|
||||||
assertThat(toStringFor(new BeanSet<String>(null))).isEqualTo("[]");
|
assertThat(toStringFor(new BeanSet<String>(null))).isEqualTo("[]");
|
||||||
assertThat(toStringFor(new BeanSet<String>(Collections.emptySet()))).isEqualTo("[]");
|
assertThat(toStringFor(new BeanSet<String>(new LinkedHashSet<>()))).isEqualTo("[]");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void beanMap_null_empty() {
|
void beanMap_null_empty() {
|
||||||
assertThat(toStringFor(new BeanMap<String, String>(null))).isEqualTo("{}");
|
assertThat(toStringFor(new BeanMap<String, String>(null))).isEqualTo("{}");
|
||||||
assertThat(toStringFor(new BeanMap<String, String>(Collections.emptyMap()))).isEqualTo("{}");
|
assertThat(toStringFor(new BeanMap<String, String>(new LinkedHashMap<>()))).isEqualTo("{}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -159,7 +159,7 @@ class ToStringBuilderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void beanMap_some() {
|
void beanMap_some() {
|
||||||
Map<String, Recurse> under = new LinkedHashMap<>();
|
var under = new LinkedHashMap<String, Recurse>();
|
||||||
under.put("a", new Recurse(1, "a"));
|
under.put("a", new Recurse(1, "a"));
|
||||||
under.put("b", new Recurse(2, "b"));
|
under.put("b", new Recurse(2, "b"));
|
||||||
BeanMap<String, Recurse> list = new BeanMap<>(under);
|
BeanMap<String, Recurse> list = new BeanMap<>(under);
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ class DatabaseConfigTest {
|
|||||||
props.setProperty("forUpdateNoKey", "true");
|
props.setProperty("forUpdateNoKey", "true");
|
||||||
props.setProperty("defaultServer", "false");
|
props.setProperty("defaultServer", "false");
|
||||||
props.setProperty("skipDataSourceCheck", "true");
|
props.setProperty("skipDataSourceCheck", "true");
|
||||||
|
props.setProperty("readOnlyDatabase", "true");
|
||||||
|
|
||||||
props.setProperty("queryPlan.enable", "true");
|
props.setProperty("queryPlan.enable", "true");
|
||||||
props.setProperty("queryPlan.thresholdMicros", "10000");
|
props.setProperty("queryPlan.thresholdMicros", "10000");
|
||||||
@@ -93,6 +94,7 @@ class DatabaseConfigTest {
|
|||||||
assertTrue(settings.isAutoLoadModuleInfo());
|
assertTrue(settings.isAutoLoadModuleInfo());
|
||||||
assertTrue(settings.isLoadModuleInfo());
|
assertTrue(settings.isLoadModuleInfo());
|
||||||
assertTrue(settings.skipDataSourceCheck());
|
assertTrue(settings.skipDataSourceCheck());
|
||||||
|
assertTrue(settings.readOnlyDatabase());
|
||||||
|
|
||||||
assertTrue(settings.isIdGeneratorAutomatic());
|
assertTrue(settings.isIdGeneratorAutomatic());
|
||||||
assertFalse(settings.getPlatformConfig().isCaseSensitiveCollation());
|
assertFalse(settings.getPlatformConfig().isCaseSensitiveCollation());
|
||||||
|
|||||||
+26
-26
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<name>ebean bom</name>
|
<name>ebean bom</name>
|
||||||
@@ -89,25 +89,25 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean</artifactId>
|
<artifactId>ebean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core-type</artifactId>
|
<artifactId>ebean-core-type</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -125,13 +125,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-jackson-mapper</artifactId>
|
<artifactId>ebean-jackson-mapper</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-ddl-generator</artifactId>
|
<artifactId>ebean-ddl-generator</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -155,37 +155,37 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-querybean</artifactId>
|
<artifactId>ebean-querybean</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>querybean-generator</artifactId>
|
<artifactId>querybean-generator</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>kotlin-querybean-generator</artifactId>
|
<artifactId>kotlin-querybean-generator</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-test</artifactId>
|
<artifactId>ebean-test</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-redis</artifactId>
|
<artifactId>ebean-redis</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-spring-txn</artifactId>
|
<artifactId>ebean-spring-txn</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- platforms -->
|
<!-- platforms -->
|
||||||
@@ -193,79 +193,79 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-clickhouse</artifactId>
|
<artifactId>ebean-clickhouse</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-db2</artifactId>
|
<artifactId>ebean-db2</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-h2</artifactId>
|
<artifactId>ebean-h2</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-hana</artifactId>
|
<artifactId>ebean-hana</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-mariadb</artifactId>
|
<artifactId>ebean-mariadb</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-mysql</artifactId>
|
<artifactId>ebean-mysql</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-nuodb</artifactId>
|
<artifactId>ebean-nuodb</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-oracle</artifactId>
|
<artifactId>ebean-oracle</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-postgres</artifactId>
|
<artifactId>ebean-postgres</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-postgis</artifactId>
|
<artifactId>ebean-postgis</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-postgis-types</artifactId>
|
<artifactId>ebean-postgis-types</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-sqlite</artifactId>
|
<artifactId>ebean-sqlite</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-sqlserver</artifactId>
|
<artifactId>ebean-sqlserver</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>ebean-core-type</artifactId>
|
<artifactId>ebean-core-type</artifactId>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
+6
-6
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-api</artifactId>
|
<artifactId>ebean-api</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core-type</artifactId>
|
<artifactId>ebean-core-type</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -159,21 +159,21 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-h2</artifactId>
|
<artifactId>ebean-platform-h2</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-postgres</artifactId>
|
<artifactId>ebean-platform-postgres</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-sqlserver</artifactId>
|
<artifactId>ebean-platform-sqlserver</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|||||||
@@ -654,6 +654,16 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
|
|||||||
*/
|
*/
|
||||||
ObjectGraphNode parentNode();
|
ObjectGraphNode parentNode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set that this is a future query that will execute in the background.
|
||||||
|
*/
|
||||||
|
void usingFuture();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if this is a future query.
|
||||||
|
*/
|
||||||
|
boolean isUsingFuture();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return false when this is a lazy load or refresh query for a bean.
|
* Return false when this is a lazy load or refresh query for a bean.
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import io.ebean.Database;
|
|||||||
import io.ebean.config.ContainerConfig;
|
import io.ebean.config.ContainerConfig;
|
||||||
import io.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
import io.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
@@ -20,38 +19,22 @@ public class ClusterManager implements ServerLookup {
|
|||||||
private static final System.Logger clusterLogger = AppLog.getLogger("io.ebean.Cluster");
|
private static final System.Logger clusterLogger = AppLog.getLogger("io.ebean.Cluster");
|
||||||
|
|
||||||
private final ReentrantLock lock = new ReentrantLock();
|
private final ReentrantLock lock = new ReentrantLock();
|
||||||
|
|
||||||
private final ConcurrentHashMap<String, Database> serverMap = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, Database> serverMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final Object monitor = new Object();
|
|
||||||
|
|
||||||
private final ClusterBroadcast broadcast;
|
private final ClusterBroadcast broadcast;
|
||||||
|
|
||||||
private boolean started;
|
private boolean started;
|
||||||
|
|
||||||
private boolean shutdown;
|
private boolean shutdown;
|
||||||
|
|
||||||
public ClusterManager(ContainerConfig config) {
|
public ClusterManager(ContainerConfig config) {
|
||||||
ClusterBroadcastFactory factory = createFactory();
|
if (config.isActive()) {
|
||||||
if (factory != null && config.isActive()) {
|
ClusterBroadcastFactory factory = createFactory();
|
||||||
broadcast = factory.create(this, config);
|
broadcast = factory != null ? factory.create(this, config) : null;
|
||||||
} else {
|
} else {
|
||||||
broadcast = null;
|
broadcast = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the ClusterTransportFactory via ServiceLoader.
|
|
||||||
*/
|
|
||||||
private ClusterBroadcastFactory createFactory() {
|
private ClusterBroadcastFactory createFactory() {
|
||||||
|
return ServiceLoader.load(ClusterBroadcastFactory.class).findFirst().orElse(null);
|
||||||
ServiceLoader<ClusterBroadcastFactory> load = ServiceLoader.load(ClusterBroadcastFactory.class);
|
|
||||||
ClusterBroadcastFactory factory = null;
|
|
||||||
Iterator<ClusterBroadcastFactory> iterator = load.iterator();
|
|
||||||
if (iterator.hasNext()) {
|
|
||||||
factory = iterator.next();
|
|
||||||
}
|
|
||||||
return factory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerServer(Database server) {
|
public void registerServer(Database server) {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class DatabasePlatformFactory {
|
|||||||
// choose based on dbName
|
// choose based on dbName
|
||||||
return byDatabaseName(config.getDatabasePlatformName());
|
return byDatabaseName(config.getDatabasePlatformName());
|
||||||
}
|
}
|
||||||
if (config.getDataSourceConfig().settings().isOffline()) {
|
if (config.getDataSourceConfig().isOffline()) {
|
||||||
throw new PersistenceException("DatabasePlatformName must be specified with offline mode");
|
throw new PersistenceException("DatabasePlatformName must be specified with offline mode");
|
||||||
}
|
}
|
||||||
// guess using meta data from driver
|
// guess using meta data from driver
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package io.ebeaninternal.server.core;
|
package io.ebeaninternal.server.core;
|
||||||
|
|
||||||
|
import io.ebean.Database;
|
||||||
import io.ebean.DatabaseBuilder;
|
import io.ebean.DatabaseBuilder;
|
||||||
import io.ebean.config.*;
|
import io.ebean.config.*;
|
||||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||||
@@ -13,11 +14,13 @@ import io.ebeaninternal.server.cluster.ClusterManager;
|
|||||||
import io.ebeaninternal.server.core.bootup.BootupClassPathSearch;
|
import io.ebeaninternal.server.core.bootup.BootupClassPathSearch;
|
||||||
import io.ebeaninternal.server.core.bootup.BootupClasses;
|
import io.ebeaninternal.server.core.bootup.BootupClasses;
|
||||||
import io.ebeaninternal.server.executor.DefaultBackgroundExecutor;
|
import io.ebeaninternal.server.executor.DefaultBackgroundExecutor;
|
||||||
|
|
||||||
import jakarta.persistence.PersistenceException;
|
import jakarta.persistence.PersistenceException;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
@@ -33,12 +36,22 @@ public final class DefaultContainer implements SpiContainer {
|
|||||||
|
|
||||||
private final ReentrantLock lock = new ReentrantLock();
|
private final ReentrantLock lock = new ReentrantLock();
|
||||||
private final ClusterManager clusterManager;
|
private final ClusterManager clusterManager;
|
||||||
|
private final List<EntityClassRegister> entityClassRegisters;
|
||||||
|
|
||||||
public DefaultContainer(ContainerConfig containerConfig) {
|
public DefaultContainer(ContainerConfig containerConfig) {
|
||||||
this.clusterManager = new ClusterManager(containerConfig);
|
this.clusterManager = new ClusterManager(containerConfig);
|
||||||
// register so that we can shutdown any Ebean wide
|
// register so that we can shutdown any Ebean wide
|
||||||
// resources such as clustering
|
// resources such as clustering
|
||||||
ShutdownManager.registerContainer(this);
|
ShutdownManager.registerContainer(this);
|
||||||
|
entityClassRegisters = initEntityRegisters();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<EntityClassRegister> initEntityRegisters() {
|
||||||
|
var entityClassRegisters = new ArrayList<EntityClassRegister>();
|
||||||
|
for (EntityClassRegister entityClassRegister : ServiceLoader.load(EntityClassRegister.class)) {
|
||||||
|
entityClassRegisters.add(entityClassRegister);
|
||||||
|
}
|
||||||
|
return entityClassRegisters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -52,10 +65,8 @@ public final class DefaultContainer implements SpiContainer {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public SpiEbeanServer createServer(String name) {
|
public SpiEbeanServer createServer(String name) {
|
||||||
DatabaseBuilder config = new DatabaseConfig();
|
var builder = Database.builder().name(name).loadFromProperties();
|
||||||
config.setName(name);
|
return createServer(builder);
|
||||||
config.loadFromProperties();
|
|
||||||
return createServer(config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SpiBackgroundExecutor createBackgroundExecutor(DatabaseBuilder builder) {
|
private SpiBackgroundExecutor createBackgroundExecutor(DatabaseBuilder builder) {
|
||||||
@@ -82,7 +93,7 @@ public final class DefaultContainer implements SpiContainer {
|
|||||||
|
|
||||||
boolean online = true;
|
boolean online = true;
|
||||||
if (config.isDocStoreOnly()) {
|
if (config.isDocStoreOnly()) {
|
||||||
config.setDatabasePlatform(new DatabasePlatform());
|
config.databasePlatform(new DatabasePlatform());
|
||||||
} else {
|
} else {
|
||||||
TenantMode tenantMode = config.getTenantMode();
|
TenantMode tenantMode = config.getTenantMode();
|
||||||
if (TenantMode.DB != tenantMode) {
|
if (TenantMode.DB != tenantMode) {
|
||||||
@@ -126,12 +137,10 @@ public final class DefaultContainer implements SpiContainer {
|
|||||||
}
|
}
|
||||||
if (config.isLoadModuleInfo()) {
|
if (config.isLoadModuleInfo()) {
|
||||||
// auto register entity classes
|
// auto register entity classes
|
||||||
boolean found = false;
|
for (EntityClassRegister loader : entityClassRegisters) {
|
||||||
for (EntityClassRegister loader : ServiceLoader.load(EntityClassRegister.class)) {
|
|
||||||
config.addAll(loader.classesFor(config.getName(), config.isDefaultServer()));
|
config.addAll(loader.classesFor(config.getName(), config.isDefaultServer()));
|
||||||
found = true;
|
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (entityClassRegisters.isEmpty()) {
|
||||||
checkMissingModulePathProvides();
|
checkMissingModulePathProvides();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,7 +202,7 @@ public final class DefaultContainer implements SpiContainer {
|
|||||||
*/
|
*/
|
||||||
private void setNamingConvention(DatabaseBuilder.Settings config) {
|
private void setNamingConvention(DatabaseBuilder.Settings config) {
|
||||||
if (config.getNamingConvention() == null) {
|
if (config.getNamingConvention() == null) {
|
||||||
config.setNamingConvention(new UnderscoreNamingConvention());
|
config.namingConvention(new UnderscoreNamingConvention());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +217,7 @@ public final class DefaultContainer implements SpiContainer {
|
|||||||
}
|
}
|
||||||
// automatically determine the platform
|
// automatically determine the platform
|
||||||
platform = new DatabasePlatformFactory().create(config);
|
platform = new DatabasePlatformFactory().create(config);
|
||||||
config.setDatabasePlatform(platform);
|
config.databasePlatform(platform);
|
||||||
}
|
}
|
||||||
platform.configure(config.getPlatformConfig());
|
platform.configure(config.getPlatformConfig());
|
||||||
}
|
}
|
||||||
@@ -232,18 +241,16 @@ public final class DefaultContainer implements SpiContainer {
|
|||||||
* Check the autoCommit and Transaction Isolation levels of the DataSource.
|
* Check the autoCommit and Transaction Isolation levels of the DataSource.
|
||||||
* <p>
|
* <p>
|
||||||
* If autoCommit is true this could be a real problem.
|
* If autoCommit is true this could be a real problem.
|
||||||
* </p>
|
|
||||||
* <p>
|
* <p>
|
||||||
* If the Isolation level is not READ_COMMITTED then optimistic concurrency
|
* If the Isolation level is not READ_COMMITTED then optimistic concurrency
|
||||||
* checking may not work as expected.
|
* checking may not work as expected.
|
||||||
* </p>
|
|
||||||
*/
|
*/
|
||||||
private boolean checkDataSource(DatabaseBuilder.Settings config) {
|
private boolean checkDataSource(DatabaseBuilder.Settings config) {
|
||||||
if (isOfflineMode(config)) {
|
if (isOfflineMode(config)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (config.getDataSource() == null) {
|
if (config.getDataSource() == null) {
|
||||||
if (config.getDataSourceConfig().settings().isOffline()) {
|
if (config.getDataSourceConfig().isOffline()) {
|
||||||
// this is ok - offline DDL generation etc
|
// this is ok - offline DDL generation etc
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -961,7 +961,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
|||||||
}
|
}
|
||||||
if (!query.isRawSql()) {
|
if (!query.isRawSql()) {
|
||||||
query.setDefaultRawSqlIfRequired();
|
query.setDefaultRawSqlIfRequired();
|
||||||
if (query.isAutoTunable() && !autoTuneService.tuneQuery(query)) {
|
if (!query.isAutoTunable() || !autoTuneService.tuneQuery(query)) {
|
||||||
// use deployment FetchType.LAZY/EAGER annotations
|
// use deployment FetchType.LAZY/EAGER annotations
|
||||||
// to define the 'default' select clause
|
// to define the 'default' select clause
|
||||||
query.setDefaultSelectClause();
|
query.setDefaultSelectClause();
|
||||||
@@ -1273,6 +1273,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
|||||||
@Override
|
@Override
|
||||||
public <T> FutureRowCount<T> findFutureCount(SpiQuery<T> query) {
|
public <T> FutureRowCount<T> findFutureCount(SpiQuery<T> query) {
|
||||||
SpiQuery<T> copy = query.copy();
|
SpiQuery<T> copy = query.copy();
|
||||||
|
copy.usingFuture();
|
||||||
boolean createdTransaction = false;
|
boolean createdTransaction = false;
|
||||||
SpiTransaction transaction = query.transaction();
|
SpiTransaction transaction = query.transaction();
|
||||||
if (transaction == null) {
|
if (transaction == null) {
|
||||||
@@ -1291,6 +1292,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
|||||||
@Override
|
@Override
|
||||||
public <T> FutureIds<T> findFutureIds(SpiQuery<T> query) {
|
public <T> FutureIds<T> findFutureIds(SpiQuery<T> query) {
|
||||||
SpiQuery<T> copy = query.copy();
|
SpiQuery<T> copy = query.copy();
|
||||||
|
copy.usingFuture();
|
||||||
boolean createdTransaction = false;
|
boolean createdTransaction = false;
|
||||||
SpiTransaction transaction = query.transaction();
|
SpiTransaction transaction = query.transaction();
|
||||||
if (transaction == null) {
|
if (transaction == null) {
|
||||||
@@ -1309,6 +1311,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
|||||||
@Override
|
@Override
|
||||||
public <T> FutureList<T> findFutureList(SpiQuery<T> query) {
|
public <T> FutureList<T> findFutureList(SpiQuery<T> query) {
|
||||||
SpiQuery<T> spiQuery = query.copy();
|
SpiQuery<T> spiQuery = query.copy();
|
||||||
|
spiQuery.usingFuture();
|
||||||
// FutureList query always run in it's own persistence content
|
// FutureList query always run in it's own persistence content
|
||||||
spiQuery.setPersistenceContext(new DefaultPersistenceContext());
|
spiQuery.setPersistenceContext(new DefaultPersistenceContext());
|
||||||
if (!spiQuery.isDisableReadAudit()) {
|
if (!spiQuery.isDisableReadAudit()) {
|
||||||
@@ -1651,41 +1654,50 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
|||||||
}, transaction);
|
}, transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert the bean.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void insert(Object bean) {
|
public void insert(Object bean) {
|
||||||
insert(bean, null);
|
persister.insert(checkEntityBean(bean), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insert(Object bean, @Nullable InsertOptions insertOptions) {
|
||||||
|
persister.insert(checkEntityBean(bean), insertOptions, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert the bean with a transaction.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void insert(Object bean, @Nullable Transaction transaction) {
|
public void insert(Object bean, @Nullable Transaction transaction) {
|
||||||
persister.insert(checkEntityBean(bean), transaction);
|
persister.insert(checkEntityBean(bean), null, transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insert(Object bean, InsertOptions insertOptions, Transaction transaction) {
|
||||||
|
persister.insert(checkEntityBean(bean), insertOptions, transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert all beans in the collection.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void insertAll(Collection<?> beans) {
|
public void insertAll(Collection<?> beans) {
|
||||||
insertAll(beans, null);
|
insertAll(beans, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertAll(Collection<?> beans, InsertOptions options) {
|
||||||
|
insertAll(beans, options, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert all beans in the collection with a transaction.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void insertAll(@Nullable Collection<?> beans, @Nullable Transaction transaction) {
|
public void insertAll(@Nullable Collection<?> beans, @Nullable Transaction transaction) {
|
||||||
|
insertAll(beans, null, transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertAll(@Nullable Collection<?> beans, InsertOptions options, @Nullable Transaction transaction) {
|
||||||
if (beans == null || beans.isEmpty()) {
|
if (beans == null || beans.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
executeInTrans((txn) -> {
|
executeInTrans((txn) -> {
|
||||||
|
txn.checkBatchEscalationOnCollection();
|
||||||
for (Object bean : beans) {
|
for (Object bean : beans) {
|
||||||
persister.insert(checkEntityBean(bean), txn);
|
persister.insert(checkEntityBean(bean), options, txn);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}, transaction);
|
}, transaction);
|
||||||
|
|||||||
@@ -38,29 +38,32 @@ final class InitDataSource {
|
|||||||
* Initialise the "main" read write DataSource from configuration.
|
* Initialise the "main" read write DataSource from configuration.
|
||||||
*/
|
*/
|
||||||
private DataSource initDataSource() {
|
private DataSource initDataSource() {
|
||||||
return createFromConfig(config.getDataSourceConfig(), false);
|
return createFromConfig(config.getDataSourceConfig(), config.readOnlyDatabase(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise the "read only" DataSource from configuration.
|
* Initialise the "read only" DataSource from configuration.
|
||||||
*/
|
*/
|
||||||
private DataSource initReadOnlyDataSource() {
|
private DataSource initReadOnlyDataSource() {
|
||||||
|
if (config.readOnlyDatabase()) {
|
||||||
|
// using the same DataSource instance
|
||||||
|
return config.getDataSource();
|
||||||
|
}
|
||||||
var roConfig = readOnlyConfig();
|
var roConfig = readOnlyConfig();
|
||||||
return roConfig == null ? null : createFromConfig(roConfig, true);
|
return roConfig == null ? null : createFromConfig(roConfig, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
DataSourceBuilder readOnlyConfig() {
|
DataSourceBuilder.Settings readOnlyConfig() {
|
||||||
var roConfig = config.getReadOnlyDataSourceConfig();
|
var roConfig = config.getReadOnlyDataSourceConfig();
|
||||||
if (roConfig == null) {
|
if (roConfig == null) {
|
||||||
// it has explicitly been set to null, not expected but ok
|
// it has explicitly been set to null, not expected but ok
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var roSettings = roConfig.settings();
|
if (urlSet(roConfig.getUrl())) {
|
||||||
if (urlSet(roSettings.getUrl())) {
|
|
||||||
return roConfig;
|
return roConfig;
|
||||||
}
|
}
|
||||||
// convenient alternate place to set the read-only url
|
// convenient alternate place to set the read-only url
|
||||||
final String readOnlyUrl = config.getDataSourceConfig().settings().getReadOnlyUrl();
|
final String readOnlyUrl = config.getDataSourceConfig().getReadOnlyUrl();
|
||||||
if (urlSet(readOnlyUrl)) {
|
if (urlSet(readOnlyUrl)) {
|
||||||
roConfig.url(readOnlyUrl);
|
roConfig.url(readOnlyUrl);
|
||||||
return roConfig;
|
return roConfig;
|
||||||
@@ -77,23 +80,23 @@ final class InitDataSource {
|
|||||||
return url != null && !"none".equalsIgnoreCase(url) && !url.trim().isEmpty();
|
return url != null && !"none".equalsIgnoreCase(url) && !url.trim().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataSource createFromConfig(DataSourceBuilder dsConfig, boolean readOnly) {
|
private DataSource createFromConfig(DataSourceBuilder.Settings dsConfig, boolean readOnlyDB, boolean readOnly) {
|
||||||
if (dsConfig == null) {
|
if (dsConfig == null) {
|
||||||
throw new PersistenceException("No DataSourceBuilder defined for " + config.getName());
|
throw new PersistenceException("No DataSourceBuilder defined for " + config.getName());
|
||||||
}
|
}
|
||||||
var dsSettings = dsConfig.settings();
|
if (dsConfig.isOffline() && config.getDatabasePlatformName() == null) {
|
||||||
if (dsSettings.isOffline()) {
|
throw new PersistenceException("You MUST specify a DatabasePlatformName on DatabaseConfig when offline");
|
||||||
if (config.getDatabasePlatformName() == null) {
|
|
||||||
throw new PersistenceException("You MUST specify a DatabasePlatformName on DatabaseConfig when offline");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attachAlert(dsSettings);
|
attachAlert(dsConfig);
|
||||||
attachListener(dsSettings);
|
attachListener(dsConfig);
|
||||||
|
|
||||||
if (readOnly) {
|
if (readOnlyDB) {
|
||||||
|
dsConfig.autoCommit(true);
|
||||||
|
dsConfig.readOnly(true);
|
||||||
|
} else if (readOnly) {
|
||||||
// setup to use AutoCommit such that we skip explicit commit
|
// setup to use AutoCommit such that we skip explicit commit
|
||||||
var mainSettings = config.getDataSourceConfig().settings();
|
var mainSettings = config.getDataSourceConfig();
|
||||||
dsConfig.autoCommit(true);
|
dsConfig.autoCommit(true);
|
||||||
dsConfig.readOnly(true);
|
dsConfig.readOnly(true);
|
||||||
dsConfig.setDefaults(mainSettings);
|
dsConfig.setDefaults(mainSettings);
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
|
|||||||
private final OrmQueryEngine queryEngine;
|
private final OrmQueryEngine queryEngine;
|
||||||
private final SpiQuery<T> query;
|
private final SpiQuery<T> query;
|
||||||
private final BeanFindController finder;
|
private final BeanFindController finder;
|
||||||
private final Boolean readOnly;
|
|
||||||
private LoadContext loadContext;
|
private LoadContext loadContext;
|
||||||
private PersistenceContext persistenceContext;
|
private PersistenceContext persistenceContext;
|
||||||
private HashQuery cacheKey;
|
private HashQuery cacheKey;
|
||||||
@@ -52,7 +51,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
|
|||||||
this.finder = beanDescriptor.beanFinder();
|
this.finder = beanDescriptor.beanFinder();
|
||||||
this.queryEngine = queryEngine;
|
this.queryEngine = queryEngine;
|
||||||
this.query = query;
|
this.query = query;
|
||||||
this.readOnly = query.isReadOnly();
|
|
||||||
this.persistenceContext = query.persistenceContext();
|
this.persistenceContext = query.persistenceContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,13 +133,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
|
|||||||
return loadContext.secondaryQueriesMinBatchSize();
|
return loadContext.secondaryQueriesMinBatchSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the Normal, sharedInstance, ReadOnly state of this query.
|
|
||||||
*/
|
|
||||||
public Boolean isReadOnly() {
|
|
||||||
return readOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the BeanDescriptor for the associated bean.
|
* Return the BeanDescriptor for the associated bean.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package io.ebeaninternal.server.core;
|
package io.ebeaninternal.server.core;
|
||||||
|
|
||||||
|
import io.ebean.InsertOptions;
|
||||||
import io.ebean.ValuePair;
|
import io.ebean.ValuePair;
|
||||||
import io.ebean.annotation.DocStoreMode;
|
import io.ebean.annotation.DocStoreMode;
|
||||||
import io.ebean.bean.EntityBean;
|
import io.ebean.bean.EntityBean;
|
||||||
@@ -124,6 +125,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
|||||||
* Many-to-many intersection table changes that are held for later batch processing.
|
* Many-to-many intersection table changes that are held for later batch processing.
|
||||||
*/
|
*/
|
||||||
private List<SaveMany> saveMany;
|
private List<SaveMany> saveMany;
|
||||||
|
private InsertOptions insertOptions;
|
||||||
|
|
||||||
public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager<T> mgr, SpiTransaction t,
|
public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager<T> mgr, SpiTransaction t,
|
||||||
PersistExecute persistExecute, PersistRequest.Type type, int flags) {
|
PersistExecute persistExecute, PersistRequest.Type type, int flags) {
|
||||||
@@ -380,6 +382,14 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
|||||||
return intercept.dirtyPropertyNames();
|
return intercept.dirtyPropertyNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isChangedProperty(int propertyIndex) {
|
||||||
|
if (dirtyProperties == null) {
|
||||||
|
return intercept.isChangedProperty(propertyIndex);
|
||||||
|
} else {
|
||||||
|
return dirtyProperties[propertyIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the dirty properties on this request.
|
* Return the dirty properties on this request.
|
||||||
*/
|
*/
|
||||||
@@ -865,8 +875,8 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
|||||||
}
|
}
|
||||||
setNotifyCache();
|
setNotifyCache();
|
||||||
boolean isChangeLog = beanDescriptor.isChangeLog();
|
boolean isChangeLog = beanDescriptor.isChangeLog();
|
||||||
if (type == Type.UPDATE && (isChangeLog || notifyCache || docStoreMode == DocStoreMode.UPDATE)) {
|
if (type == Type.UPDATE) {
|
||||||
// get the dirty properties for update notification to the doc store
|
// get the dirty properties for notify cache & orphanRemoval of vanilla collection detection
|
||||||
dirtyProperties = intercept.dirtyProperties();
|
dirtyProperties = intercept.dirtyProperties();
|
||||||
}
|
}
|
||||||
if (isChangeLog) {
|
if (isChangeLog) {
|
||||||
@@ -1408,4 +1418,12 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
|||||||
private void setGeneratedId() {
|
private void setGeneratedId() {
|
||||||
beanDescriptor.setGeneratedId(entityBean, transaction);
|
beanDescriptor.setGeneratedId(entityBean, transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setInsertOptions(InsertOptions insertOptions) {
|
||||||
|
this.insertOptions = insertOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InsertOptions insertOptions() {
|
||||||
|
return insertOptions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
package io.ebeaninternal.server.core;
|
package io.ebeaninternal.server.core;
|
||||||
|
|
||||||
import io.ebean.CallableSql;
|
import io.avaje.lang.Nullable;
|
||||||
import io.ebean.MergeOptions;
|
import io.ebean.*;
|
||||||
import io.ebean.Query;
|
|
||||||
import io.ebean.SqlUpdate;
|
|
||||||
import io.ebean.Transaction;
|
|
||||||
import io.ebean.Update;
|
|
||||||
import io.ebean.bean.EntityBean;
|
import io.ebean.bean.EntityBean;
|
||||||
import io.ebean.meta.MetricVisitor;
|
import io.ebean.meta.MetricVisitor;
|
||||||
import io.ebeaninternal.api.SpiSqlUpdate;
|
import io.ebeaninternal.api.SpiSqlUpdate;
|
||||||
@@ -31,9 +27,9 @@ public interface Persister {
|
|||||||
void update(EntityBean entityBean, Transaction t);
|
void update(EntityBean entityBean, Transaction t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force an Insert using the given bean.
|
* Perform an Insert using the given bean.
|
||||||
*/
|
*/
|
||||||
void insert(EntityBean entityBean, Transaction t);
|
void insert(EntityBean entityBean, @Nullable InsertOptions insertOptions, @Nullable Transaction t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert or update the bean depending on its state.
|
* Insert or update the bean depending on its state.
|
||||||
@@ -44,7 +40,6 @@ public interface Persister {
|
|||||||
* Delete a bean given it's type and id value.
|
* Delete a bean given it's type and id value.
|
||||||
* <p>
|
* <p>
|
||||||
* This will also cascade delete one level of children.
|
* This will also cascade delete one level of children.
|
||||||
* </p>
|
|
||||||
*/
|
*/
|
||||||
int delete(Class<?> beanType, Object id, Transaction transaction, boolean permanent);
|
int delete(Class<?> beanType, Object id, Transaction transaction, boolean permanent);
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
package io.ebeaninternal.server.deploy;
|
package io.ebeaninternal.server.deploy;
|
||||||
|
|
||||||
import io.ebean.Transaction;
|
|
||||||
import io.ebean.bean.BeanCollection;
|
import io.ebean.bean.BeanCollection;
|
||||||
import io.ebean.bean.BeanCollectionAdd;
|
import io.ebean.bean.BeanCollectionAdd;
|
||||||
import io.ebean.bean.BeanCollectionLoader;
|
import io.ebean.bean.BeanCollectionLoader;
|
||||||
import io.ebean.bean.EntityBean;
|
import io.ebean.bean.EntityBean;
|
||||||
import io.ebeaninternal.api.SpiEbeanServer;
|
|
||||||
import io.ebeaninternal.api.SpiQuery;
|
|
||||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||||
import io.ebeaninternal.server.query.CQueryCollectionAdd;
|
import io.ebeaninternal.server.query.CQueryCollectionAdd;
|
||||||
|
|
||||||
@@ -34,7 +31,7 @@ public interface BeanCollectionHelp<T> extends CQueryCollectionAdd<T> {
|
|||||||
* For Map's this needs to take the mapKey.
|
* For Map's this needs to take the mapKey.
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey);
|
BeanCollectionAdd collectionAdd(Object bc, String mapKey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an empty collection of the correct type without a parent bean.
|
* Create an empty collection of the correct type without a parent bean.
|
||||||
|
|||||||
@@ -278,7 +278,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
|
|||||||
this.partitionMeta = deploy.getPartitionMeta();
|
this.partitionMeta = deploy.getPartitionMeta();
|
||||||
this.tablespaceMeta = deploy.getTablespaceMeta();
|
this.tablespaceMeta = deploy.getTablespaceMeta();
|
||||||
this.storageEngine = deploy.getStorageEngine();
|
this.storageEngine = deploy.getStorageEngine();
|
||||||
this.autoTunable = beanFinder == null && (entityType == EntityType.ORM || entityType == EntityType.VIEW);
|
this.autoTunable = entityType == EntityType.ORM || entityType == EntityType.VIEW;
|
||||||
// helper object used to derive lists of properties
|
// helper object used to derive lists of properties
|
||||||
DeployBeanPropertyLists listHelper = new DeployBeanPropertyLists(owner, this, deploy);
|
DeployBeanPropertyLists listHelper = new DeployBeanPropertyLists(owner, this, deploy);
|
||||||
this.softDeleteProperty = listHelper.getSoftDeleteProperty();
|
this.softDeleteProperty = listHelper.getSoftDeleteProperty();
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
package io.ebeaninternal.server.deploy;
|
package io.ebeaninternal.server.deploy;
|
||||||
|
|
||||||
import io.ebean.Transaction;
|
|
||||||
import io.ebean.bean.BeanCollection;
|
import io.ebean.bean.BeanCollection;
|
||||||
import io.ebean.bean.BeanCollectionAdd;
|
import io.ebean.bean.BeanCollectionAdd;
|
||||||
import io.ebean.bean.EntityBean;
|
import io.ebean.bean.EntityBean;
|
||||||
import io.ebean.common.BeanList;
|
import io.ebean.common.BeanList;
|
||||||
import io.ebeaninternal.api.SpiEbeanServer;
|
|
||||||
import io.ebeaninternal.api.SpiQuery;
|
|
||||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -23,19 +19,11 @@ public class BeanListHelp<T> extends BaseCollectionHelp<T> {
|
|||||||
super(many);
|
super(many);
|
||||||
}
|
}
|
||||||
|
|
||||||
BeanListHelp() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
public final BeanCollectionAdd collectionAdd(Object bc, String mapKey) {
|
||||||
if (bc instanceof BeanList<?>) {
|
if (bc instanceof BeanList<?>) {
|
||||||
BeanList<?> bl = (BeanList<?>) bc;
|
BeanList<?> bl = (BeanList<?>) bc;
|
||||||
if (bl.actualList() == null) {
|
return bl.collectionAdd();
|
||||||
bl.setActualList(new ArrayList<>());
|
|
||||||
}
|
|
||||||
return bl;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Unhandled type " + bc);
|
throw new RuntimeException("Unhandled type " + bc);
|
||||||
}
|
}
|
||||||
@@ -67,20 +55,20 @@ public class BeanListHelp<T> extends BaseCollectionHelp<T> {
|
|||||||
return beanList;
|
return beanList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public final void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
public final void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
||||||
BeanList<?> newBeanList = (BeanList<?>) bc;
|
BeanList<T> newBeanList = (BeanList<T>) bc;
|
||||||
List<?> currentList = (List<?>) many.getValue(parentBean);
|
List<?> currentList = (List<?>) many.getValue(parentBean);
|
||||||
newBeanList.setModifyListening(many.modifyListenMode());
|
newBeanList.setModifyListening(many.modifyListenMode());
|
||||||
if (currentList == null) {
|
if (currentList == null) {
|
||||||
// the currentList is null? Not really expecting this...
|
// the currentList is null? Not really expecting this...
|
||||||
many.setValue(parentBean, newBeanList);
|
many.setValue(parentBean, newBeanList);
|
||||||
|
|
||||||
} else if (currentList instanceof BeanList<?>) {
|
} else if (currentList instanceof BeanList) {
|
||||||
// normally this case, replace just the underlying list
|
// normally this case, replace just the underlying list
|
||||||
BeanList<?> currentBeanList = (BeanList<?>) currentList;
|
BeanList<T> currentBeanList = (BeanList<T>) currentList;
|
||||||
currentBeanList.setActualList(newBeanList.actualList());
|
currentBeanList.refresh(many.modifyListenMode(), newBeanList);
|
||||||
currentBeanList.setModifyListening(many.modifyListenMode());
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// replace the entire list with the BeanList
|
// replace the entire list with the BeanList
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
package io.ebeaninternal.server.deploy;
|
package io.ebeaninternal.server.deploy;
|
||||||
|
|
||||||
import io.ebean.Transaction;
|
|
||||||
import io.ebean.bean.BeanCollection;
|
import io.ebean.bean.BeanCollection;
|
||||||
import io.ebean.bean.BeanCollectionAdd;
|
import io.ebean.bean.BeanCollectionAdd;
|
||||||
import io.ebean.bean.EntityBean;
|
import io.ebean.bean.EntityBean;
|
||||||
import io.ebean.common.BeanMap;
|
import io.ebean.common.BeanMap;
|
||||||
import io.ebeaninternal.api.SpiEbeanServer;
|
|
||||||
import io.ebeaninternal.api.SpiQuery;
|
|
||||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
@@ -37,20 +33,14 @@ public class BeanMapHelp<T> extends BaseCollectionHelp<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
public final BeanCollectionAdd collectionAdd(Object bc, String mapKey) {
|
||||||
if (mapKey == null) {
|
if (mapKey == null) {
|
||||||
mapKey = many.mapKey();
|
mapKey = many.mapKey();
|
||||||
}
|
}
|
||||||
BeanProperty beanProp = targetDescriptor.beanProperty(mapKey);
|
BeanProperty beanProp = targetDescriptor.beanProperty(mapKey);
|
||||||
if (bc instanceof BeanMap<?, ?>) {
|
if (bc instanceof BeanMap<?, ?>) {
|
||||||
BeanMap<Object, Object> bm = (BeanMap<Object, Object>) bc;
|
BeanMap<Object, Object> bm = (BeanMap<Object, Object>) bc;
|
||||||
Map<Object, Object> actualMap = bm.actualMap();
|
return new Adder(beanProp, bm.collectionAdd());
|
||||||
if (actualMap == null) {
|
|
||||||
actualMap = new LinkedHashMap<>();
|
|
||||||
bm.setActualMap(actualMap);
|
|
||||||
}
|
|
||||||
return new Adder(beanProp, actualMap);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Unhandled type " + bc);
|
throw new RuntimeException("Unhandled type " + bc);
|
||||||
}
|
}
|
||||||
@@ -126,8 +116,7 @@ public class BeanMapHelp<T> extends BaseCollectionHelp<T> {
|
|||||||
} else if (current instanceof BeanMap<?, ?>) {
|
} else if (current instanceof BeanMap<?, ?>) {
|
||||||
// normally this case, replace just the underlying list
|
// normally this case, replace just the underlying list
|
||||||
BeanMap<?, ?> currentBeanMap = (BeanMap<?, ?>) current;
|
BeanMap<?, ?> currentBeanMap = (BeanMap<?, ?>) current;
|
||||||
currentBeanMap.setActualMap(newBeanMap.actualMap());
|
currentBeanMap.refresh(many.modifyListenMode(), newBeanMap);
|
||||||
currentBeanMap.setModifyListening(many.modifyListenMode());
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// replace the entire set
|
// replace the entire set
|
||||||
|
|||||||
@@ -655,7 +655,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BeanCollectionAdd beanCollectionAdd(Object bc) {
|
private BeanCollectionAdd beanCollectionAdd(Object bc) {
|
||||||
return help.getBeanCollectionAdd(bc, null);
|
return help.collectionAdd(bc, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object parentId(EntityBean parentBean) {
|
public Object parentId(EntityBean parentBean) {
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
package io.ebeaninternal.server.deploy;
|
package io.ebeaninternal.server.deploy;
|
||||||
|
|
||||||
import io.ebean.Transaction;
|
|
||||||
import io.ebean.bean.BeanCollection;
|
import io.ebean.bean.BeanCollection;
|
||||||
import io.ebean.bean.BeanCollectionAdd;
|
import io.ebean.bean.BeanCollectionAdd;
|
||||||
import io.ebean.bean.EntityBean;
|
import io.ebean.bean.EntityBean;
|
||||||
import io.ebean.common.BeanSet;
|
import io.ebean.common.BeanSet;
|
||||||
import io.ebeaninternal.api.SpiEbeanServer;
|
|
||||||
import io.ebeaninternal.api.SpiQuery;
|
|
||||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,21 +22,11 @@ public class BeanSetHelp<T> extends BaseCollectionHelp<T> {
|
|||||||
super(many);
|
super(many);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* For a query that returns a set.
|
|
||||||
*/
|
|
||||||
BeanSetHelp() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
public final BeanCollectionAdd collectionAdd(Object bc, String mapKey) {
|
||||||
if (bc instanceof BeanSet<?>) {
|
if (bc instanceof BeanSet<?>) {
|
||||||
BeanSet<?> beanSet = (BeanSet<?>) bc;
|
BeanSet<?> beanSet = (BeanSet<?>) bc;
|
||||||
if (beanSet.actualSet() == null) {
|
return beanSet.collectionAdd();
|
||||||
beanSet.setActualSet(new LinkedHashSet<>());
|
|
||||||
}
|
|
||||||
return beanSet;
|
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Unhandled type " + bc);
|
throw new RuntimeException("Unhandled type " + bc);
|
||||||
}
|
}
|
||||||
@@ -72,9 +58,10 @@ public class BeanSetHelp<T> extends BaseCollectionHelp<T> {
|
|||||||
return beanSet;
|
return beanSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public final void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
public final void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
||||||
BeanSet<?> newBeanSet = (BeanSet<?>) bc;
|
BeanSet<T> newBeanSet = (BeanSet<T>) bc;
|
||||||
Set<?> current = (Set<?>) many.getValue(parentBean);
|
Set<?> current = (Set<?>) many.getValue(parentBean);
|
||||||
newBeanSet.setModifyListening(many.modifyListenMode());
|
newBeanSet.setModifyListening(many.modifyListenMode());
|
||||||
if (current == null) {
|
if (current == null) {
|
||||||
@@ -83,9 +70,8 @@ public class BeanSetHelp<T> extends BaseCollectionHelp<T> {
|
|||||||
|
|
||||||
} else if (current instanceof BeanSet<?>) {
|
} else if (current instanceof BeanSet<?>) {
|
||||||
// normally this case, replace just the underlying list
|
// normally this case, replace just the underlying list
|
||||||
BeanSet<?> currentBeanSet = (BeanSet<?>) current;
|
BeanSet<T> currentBeanSet = (BeanSet<T>) current;
|
||||||
currentBeanSet.setActualSet(newBeanSet.actualSet());
|
currentBeanSet.refresh(many.modifyListenMode(), newBeanSet);
|
||||||
currentBeanSet.setModifyListening(many.modifyListenMode());
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// replace the entire set
|
// replace the entire set
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import io.ebean.bean.BeanCollection;
|
|||||||
import io.ebean.common.BeanMap;
|
import io.ebean.common.BeanMap;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
final class ElementHelpMap implements ElementHelp {
|
final class ElementHelpMap implements ElementHelp {
|
||||||
|
|
||||||
@@ -15,7 +14,7 @@ final class ElementHelpMap implements ElementHelp {
|
|||||||
|
|
||||||
private static class Collector implements ElementCollector {
|
private static class Collector implements ElementCollector {
|
||||||
|
|
||||||
private final Map<Object, Object> map = new LinkedHashMap<>();
|
private final LinkedHashMap<Object, Object> map = new LinkedHashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addElement(Object element) {
|
public void addElement(Object element) {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import io.ebean.bean.BeanCollection;
|
|||||||
import io.ebean.common.BeanSet;
|
import io.ebean.common.BeanSet;
|
||||||
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
final class ElementHelpSet implements ElementHelp {
|
final class ElementHelpSet implements ElementHelp {
|
||||||
|
|
||||||
@@ -15,7 +14,7 @@ final class ElementHelpSet implements ElementHelp {
|
|||||||
|
|
||||||
private static class Collector implements ElementCollector {
|
private static class Collector implements ElementCollector {
|
||||||
|
|
||||||
private final Set<Object> set = new LinkedHashSet<>();
|
private final LinkedHashSet<Object> set = new LinkedHashSet<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addElement(Object element) {
|
public void addElement(Object element) {
|
||||||
|
|||||||
@@ -99,6 +99,10 @@ final class AnnotationFields extends AnnotationParser {
|
|||||||
if (formula != null) {
|
if (formula != null) {
|
||||||
prop.setSqlFormula(processFormula(formula.select()), processFormula(formula.join()));
|
prop.setSqlFormula(processFormula(formula.select()), processFormula(formula.join()));
|
||||||
}
|
}
|
||||||
|
DbComment comment = get(prop, DbComment.class);
|
||||||
|
if (comment != null) {
|
||||||
|
prop.setDbComment(comment.value());
|
||||||
|
}
|
||||||
initWhoProperties(prop);
|
initWhoProperties(prop);
|
||||||
initDbMigration(prop);
|
initDbMigration(prop);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -122,7 +122,7 @@ public final class DeployCreateProperties {
|
|||||||
return new DeployBeanProperty(desc, propertyType, field.getGenericType());
|
return new DeployBeanProperty(desc, propertyType, field.getGenericType());
|
||||||
}
|
}
|
||||||
// check for Collection type (list, set or map)
|
// check for Collection type (list, set or map)
|
||||||
ManyType manyType = determineManyType.getManyType(propertyType);
|
ManyType manyType = determineManyType.manyType(propertyType);
|
||||||
if (manyType != null) {
|
if (manyType != null) {
|
||||||
// List, Set or Map based object
|
// List, Set or Map based object
|
||||||
Class<?> targetType = determineTargetType(field);
|
Class<?> targetType = determineTargetType(field);
|
||||||
|
|||||||
+3
-3
@@ -11,14 +11,14 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
final class DetermineManyType {
|
final class DetermineManyType {
|
||||||
|
|
||||||
ManyType getManyType(Class<?> type) {
|
ManyType manyType(Class<?> type) {
|
||||||
if (type.equals(List.class)) {
|
if (type.equals(List.class)) {
|
||||||
return ManyType.LIST;
|
return ManyType.LIST;
|
||||||
}
|
}
|
||||||
if (type.equals(Set.class)) {
|
if (type.equals(Set.class) || type.getCanonicalName().equals("java.util.SequencedSet")) {
|
||||||
return ManyType.SET;
|
return ManyType.SET;
|
||||||
}
|
}
|
||||||
if (type.equals(Map.class)) {
|
if (type.equals(Map.class) || type.getCanonicalName().equals("java.util.SequencedMap")) {
|
||||||
return ManyType.MAP;
|
return ManyType.MAP;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+1
-1
@@ -81,7 +81,7 @@ final class BetweenPropertyExpression extends NonPrepareExpression {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addSql(SpiExpressionRequest request) {
|
public void addSql(SpiExpressionRequest request) {
|
||||||
request.append(" ?").append(BETWEEN).property(name(lowProperty)).append(" and ").property(name(highProperty));
|
request.append("?").append(BETWEEN).property(name(lowProperty)).append(" and ").property(name(highProperty));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -119,7 +119,11 @@ public final class Binder {
|
|||||||
if (param.isEncryptionKey()) {
|
if (param.isEncryptionKey()) {
|
||||||
bindLog.append("****");
|
bindLog.append("****");
|
||||||
} else {
|
} else {
|
||||||
bindLog.append(value);
|
String sv = String.valueOf(value);
|
||||||
|
if (sv.length() > 50) {
|
||||||
|
sv = sv.substring(0, 47) + "...";
|
||||||
|
}
|
||||||
|
bindLog.append(sv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (value instanceof Collection) {
|
if (value instanceof Collection) {
|
||||||
|
|||||||
@@ -411,7 +411,7 @@ public final class DefaultPersister implements Persister {
|
|||||||
if (bean._ebean_getIntercept().isUpdate()) {
|
if (bean._ebean_getIntercept().isUpdate()) {
|
||||||
update(bean, t);
|
update(bean, t);
|
||||||
} else {
|
} else {
|
||||||
insert(bean, t);
|
insert(bean, null, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,12 +419,15 @@ public final class DefaultPersister implements Persister {
|
|||||||
* Insert this bean.
|
* Insert this bean.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void insert(EntityBean bean, Transaction t) {
|
public void insert(EntityBean bean, InsertOptions insertOptions, Transaction t) {
|
||||||
PersistRequestBean<?> req = createRequest(bean, t, PersistRequest.Type.INSERT);
|
PersistRequestBean<?> req = createRequest(bean, t, PersistRequest.Type.INSERT);
|
||||||
if (req.isSkipReference()) {
|
if (req.isSkipReference()) {
|
||||||
// skip insert on reference bean
|
// skip insert on reference bean
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (insertOptions != null) {
|
||||||
|
req.setInsertOptions(insertOptions);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
req.initTransIfRequiredWithBatchCascade();
|
req.initTransIfRequiredWithBatchCascade();
|
||||||
insert(req);
|
insert(req);
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ final class SaveManyBeans extends SaveManyBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isChangedProperty() {
|
private boolean isChangedProperty() {
|
||||||
return parentBean._ebean_getIntercept().isChangedProperty(many.propertyIndex());
|
return request.isChangedProperty(many.propertyIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeAssocManyOrphans() {
|
private void removeAssocManyOrphans() {
|
||||||
|
|||||||
+9
-1
@@ -1,11 +1,15 @@
|
|||||||
package io.ebeaninternal.server.persist.dml;
|
package io.ebeaninternal.server.persist.dml;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to support the generation of DML statements.
|
* Helper to support the generation of DML statements.
|
||||||
*/
|
*/
|
||||||
public final class GenerateDmlRequest {
|
public final class GenerateDmlRequest {
|
||||||
|
|
||||||
private final StringBuilder sb = new StringBuilder(100);
|
private final StringBuilder sb = new StringBuilder(100);
|
||||||
|
private final List<String> columns = new ArrayList<>();
|
||||||
private StringBuilder insertBindBuffer;
|
private StringBuilder insertBindBuffer;
|
||||||
private String prefix;
|
private String prefix;
|
||||||
private String prefix2;
|
private String prefix2;
|
||||||
@@ -26,7 +30,7 @@ public final class GenerateDmlRequest {
|
|||||||
++bindColumnCount;
|
++bindColumnCount;
|
||||||
sb.append(prefix);
|
sb.append(prefix);
|
||||||
sb.append(column);
|
sb.append(column);
|
||||||
//sb.append(expr);
|
columns.add(column);
|
||||||
if (insertMode > 0) {
|
if (insertMode > 0) {
|
||||||
if (insertMode++ > 1) {
|
if (insertMode++ > 1) {
|
||||||
insertBindBuffer.append(',');
|
insertBindBuffer.append(',');
|
||||||
@@ -75,4 +79,8 @@ public final class GenerateDmlRequest {
|
|||||||
public boolean isUpdate() {
|
public boolean isUpdate() {
|
||||||
return insertMode == 0;
|
return insertMode == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> columns() {
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public final class InsertHandler extends DmlHandler {
|
|||||||
|
|
||||||
SpiTransaction t = persistRequest.transaction();
|
SpiTransaction t = persistRequest.transaction();
|
||||||
// get the appropriate sql
|
// get the appropriate sql
|
||||||
sql = meta.getSql(withId, persistRequest.isPublish());
|
sql = meta.sql(withId, persistRequest.isPublish(), persistRequest.insertOptions());
|
||||||
PreparedStatement pstmt;
|
PreparedStatement pstmt;
|
||||||
if (persistRequest.isBatched()) {
|
if (persistRequest.isBatched()) {
|
||||||
pstmt = pstmtBatch(t, sql, persistRequest, useGeneratedKeys);
|
pstmt = pstmtBatch(t, sql, persistRequest, useGeneratedKeys);
|
||||||
@@ -134,7 +134,8 @@ public final class InsertHandler extends DmlHandler {
|
|||||||
if (idValue != null) {
|
if (idValue != null) {
|
||||||
persistRequest.setGeneratedKey(idValue);
|
persistRequest.setGeneratedKey(idValue);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (persistRequest.insertOptions() == null) {
|
||||||
|
// insert on conflict do nothing can not return generated key
|
||||||
throw new PersistenceException("Autoincrement getGeneratedKeys() returned no rows?");
|
throw new PersistenceException("Autoincrement getGeneratedKeys() returned no rows?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package io.ebeaninternal.server.persist.dml;
|
package io.ebeaninternal.server.persist.dml;
|
||||||
|
|
||||||
|
import io.ebean.InsertOptions;
|
||||||
import io.ebean.annotation.Platform;
|
import io.ebean.annotation.Platform;
|
||||||
import io.ebean.bean.EntityBean;
|
import io.ebean.bean.EntityBean;
|
||||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||||
@@ -36,9 +37,11 @@ final class InsertMeta {
|
|||||||
private final Bindable shadowFKey;
|
private final Bindable shadowFKey;
|
||||||
private final String[] identityDbColumns;
|
private final String[] identityDbColumns;
|
||||||
private final Platform platform;
|
private final Platform platform;
|
||||||
|
private final InsertMetaOptions options;
|
||||||
|
|
||||||
InsertMeta(DatabasePlatform dbPlatform, BeanDescriptor<?> desc, Bindable shadowFKey, BindableId id, BindableList all) {
|
InsertMeta(DatabasePlatform dbPlatform, BeanDescriptor<?> desc, Bindable shadowFKey, BindableId id, BindableList all) {
|
||||||
this.platform = dbPlatform.platform();
|
this.platform = dbPlatform.platform();
|
||||||
|
this.options = InsertMetaPlatform.create(platform, desc, this);
|
||||||
this.discriminator = discriminator(desc);
|
this.discriminator = discriminator(desc);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.all = all;
|
this.all = all;
|
||||||
@@ -47,8 +50,8 @@ final class InsertMeta {
|
|||||||
|
|
||||||
String tableName = desc.baseTable();
|
String tableName = desc.baseTable();
|
||||||
String draftTableName = desc.draftTable();
|
String draftTableName = desc.draftTable();
|
||||||
this.sqlWithId = genSql(false, tableName, false);
|
this.sqlWithId = sql(false, tableName, false);
|
||||||
this.sqlDraftWithId = desc.isDraftable() ? genSql(false, draftTableName, true) : sqlWithId;
|
this.sqlDraftWithId = desc.isDraftable() ? sql(false, draftTableName, true) : sqlWithId;
|
||||||
|
|
||||||
// only available for single Id property
|
// only available for single Id property
|
||||||
if (id.isConcatenated()) {
|
if (id.isConcatenated()) {
|
||||||
@@ -72,8 +75,8 @@ final class InsertMeta {
|
|||||||
this.supportsGetGeneratedKeys = dbPlatform.dbIdentity().isSupportsGetGeneratedKeys();
|
this.supportsGetGeneratedKeys = dbPlatform.dbIdentity().isSupportsGetGeneratedKeys();
|
||||||
this.supportsSelectLastInsertedId = desc.supportsSelectLastInsertedId();
|
this.supportsSelectLastInsertedId = desc.supportsSelectLastInsertedId();
|
||||||
}
|
}
|
||||||
this.sqlNullId = genSql(true, tableName, false);
|
this.sqlNullId = sql(true, tableName, false);
|
||||||
this.sqlDraftNullId = desc.isDraftable() ? genSql(true, draftTableName, true) : sqlNullId;
|
this.sqlDraftNullId = desc.isDraftable() ? sql(true, draftTableName, true) : sqlNullId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,9 +140,20 @@ final class InsertMeta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the sql based whether the id value(s) are null.
|
* Return the sql for the given options.
|
||||||
*/
|
*/
|
||||||
public String getSql(boolean withId, boolean publish) {
|
public String sql(boolean withId, boolean publish, InsertOptions insertOptions) {
|
||||||
|
if (insertOptions == null) {
|
||||||
|
return sql(withId, publish);
|
||||||
|
}
|
||||||
|
return options.sql(withId, insertOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
String sqlFor(boolean withId) {
|
||||||
|
return withId ? sqlWithId : sqlNullId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String sql(boolean withId, boolean publish) {
|
||||||
if (withId) {
|
if (withId) {
|
||||||
return publish ? sqlWithId : sqlDraftWithId;
|
return publish ? sqlWithId : sqlDraftWithId;
|
||||||
} else {
|
} else {
|
||||||
@@ -147,12 +161,18 @@ final class InsertMeta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String genSql(boolean nullId, String table, boolean draftTable) {
|
private String sql(boolean nullId, String table, boolean draftTable) {
|
||||||
GenerateDmlRequest request = new GenerateDmlRequest();
|
GenerateDmlRequest request = new GenerateDmlRequest();
|
||||||
|
sql(request, nullId, table, draftTable);
|
||||||
|
return request.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sql(GenerateDmlRequest request, boolean nullId, String table, boolean draftTable) {
|
||||||
request.setInsertSetMode();
|
request.setInsertSetMode();
|
||||||
request.append("insert into ").append(table);
|
request.append("insert into ").append(table);
|
||||||
if (nullId && noColumnsForInsert(draftTable)) {
|
if (nullId && noColumnsForInsert(draftTable)) {
|
||||||
return request.append(defaultValues()).toString();
|
request.append(defaultValues());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
request.append(" (");
|
request.append(" (");
|
||||||
if (!nullId) {
|
if (!nullId) {
|
||||||
@@ -172,7 +192,6 @@ final class InsertMeta {
|
|||||||
request.append(") values (");
|
request.append(") values (");
|
||||||
request.append(request.insertBindBuffer());
|
request.append(request.insertBindBuffer());
|
||||||
request.append(")");
|
request.append(")");
|
||||||
return request.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String defaultValues() {
|
private String defaultValues() {
|
||||||
@@ -196,5 +215,4 @@ final class InsertMeta {
|
|||||||
&& discriminator == null
|
&& discriminator == null
|
||||||
&& (draftTable ? all.isEmpty() : allExcludeDraftOnly.isEmpty());
|
&& (draftTable ? all.isEmpty() : allExcludeDraftOnly.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package io.ebeaninternal.server.persist.dml;
|
||||||
|
|
||||||
|
import io.ebean.InsertOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generator for insert SQL with options.
|
||||||
|
*/
|
||||||
|
interface InsertMetaOptions {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the SQL for the given insert options.
|
||||||
|
*/
|
||||||
|
String sql(boolean withId, InsertOptions insertOptions);
|
||||||
|
}
|
||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
package io.ebeaninternal.server.persist.dml;
|
||||||
|
|
||||||
|
import io.ebean.InsertOptions;
|
||||||
|
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||||
|
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Postgres specific generation of insert on conflict.
|
||||||
|
*/
|
||||||
|
final class InsertMetaOptionsPostgres implements InsertMetaOptions {
|
||||||
|
|
||||||
|
private final InsertMeta meta;
|
||||||
|
private final BeanDescriptor<?> desc;
|
||||||
|
private final String baseTable;
|
||||||
|
private final Map<String, String> sqlCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
InsertMetaOptionsPostgres(InsertMeta meta, BeanDescriptor<?> desc) {
|
||||||
|
this.meta = meta;
|
||||||
|
this.desc = desc;
|
||||||
|
this.baseTable = desc.baseTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String sql(boolean withId, InsertOptions options) {
|
||||||
|
String key = withId + options.key();
|
||||||
|
return sqlCache.computeIfAbsent(key, k -> generate(withId, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generate(boolean withId, InsertOptions options) {
|
||||||
|
char type = options.key().charAt(0);
|
||||||
|
switch (type) {
|
||||||
|
case 'U':
|
||||||
|
return generate(withId, false, options);
|
||||||
|
case 'N':
|
||||||
|
return generate(withId, true, options);
|
||||||
|
default:
|
||||||
|
return meta.sqlFor(withId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generate(boolean withId, boolean doNothing, InsertOptions options) {
|
||||||
|
GenerateDmlRequest request = new GenerateDmlRequest();
|
||||||
|
meta.sql(request, !withId, baseTable, false);
|
||||||
|
request.append(" on conflict ");
|
||||||
|
|
||||||
|
List<String> uniqueColumns = desc.uniqueProps().stream()
|
||||||
|
.flatMap(Arrays::stream)
|
||||||
|
.map(BeanProperty::dbColumn)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
String constraintName = options.constraint();
|
||||||
|
if (constraintName != null) {
|
||||||
|
request.append("on constraint ").append(constraintName);
|
||||||
|
} else {
|
||||||
|
request.append("(");
|
||||||
|
String cols = options.uniqueColumns();
|
||||||
|
if (cols != null) {
|
||||||
|
request.append(cols);
|
||||||
|
} else {
|
||||||
|
appendUniqueColumns(uniqueColumns, request);
|
||||||
|
}
|
||||||
|
request.append(")");
|
||||||
|
}
|
||||||
|
if (doNothing) {
|
||||||
|
request.append(" do nothing");
|
||||||
|
return request.toString();
|
||||||
|
}
|
||||||
|
request.append(" do update set ");
|
||||||
|
String updateSet = options.updateSet();
|
||||||
|
if (updateSet != null) {
|
||||||
|
request.append(updateSet);
|
||||||
|
} else {
|
||||||
|
setColumns(withId, request, uniqueColumns);
|
||||||
|
}
|
||||||
|
return request.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setColumns(boolean withId, GenerateDmlRequest request, List<String> uniqueColumns) {
|
||||||
|
List<String> columns = request.columns();
|
||||||
|
columns.removeAll(uniqueColumns);
|
||||||
|
if (withId) {
|
||||||
|
BeanProperty idProperty = desc.idProperty();
|
||||||
|
if (idProperty != null && !idProperty.isEmbedded()) {
|
||||||
|
columns.remove(idProperty.dbColumn());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < columns.size(); i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
request.append(", ");
|
||||||
|
}
|
||||||
|
String col = columns.get(i);
|
||||||
|
request.append(col).append("=excluded.").append(col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void appendUniqueColumns(List<String> uniqueColumns, GenerateDmlRequest request) {
|
||||||
|
if (uniqueColumns.isEmpty()) {
|
||||||
|
throw new IllegalStateException("Unable to identify unique columns for INSERT ON CONFLICT - Add mapping like @Column(unique=true) or @Index(unique=true)");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < uniqueColumns.size(); i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
request.append(", ");
|
||||||
|
}
|
||||||
|
request.append(uniqueColumns.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package io.ebeaninternal.server.persist.dml;
|
||||||
|
|
||||||
|
import io.ebean.InsertOptions;
|
||||||
|
import io.ebean.annotation.Platform;
|
||||||
|
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||||
|
|
||||||
|
final class InsertMetaPlatform {
|
||||||
|
|
||||||
|
private static final NotSupported NOT_SUPPORTED = new NotSupported();
|
||||||
|
|
||||||
|
static InsertMetaOptions create(Platform platform, BeanDescriptor<?> desc, InsertMeta meta) {
|
||||||
|
switch (platform.base()) {
|
||||||
|
case POSTGRES:
|
||||||
|
case YUGABYTE:
|
||||||
|
case COCKROACH:
|
||||||
|
return new InsertMetaOptionsPostgres(meta, desc);
|
||||||
|
default:
|
||||||
|
return NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class NotSupported implements InsertMetaOptions {
|
||||||
|
@Override
|
||||||
|
public String sql(boolean withId, InsertOptions insertOptions) {
|
||||||
|
throw new UnsupportedOperationException("InsertOptions not supported on this database platform");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -186,7 +186,7 @@ public final class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfi
|
|||||||
this.queryMode = query.mode();
|
this.queryMode = query.mode();
|
||||||
this.loadContextBean = queryMode.isLoadContextBean() || query.getForUpdateLockType() != null;
|
this.loadContextBean = queryMode.isLoadContextBean() || query.getForUpdateLockType() != null;
|
||||||
this.lazyLoadManyProperty = query.lazyLoadMany();
|
this.lazyLoadManyProperty = query.lazyLoadMany();
|
||||||
this.readOnly = request.isReadOnly();
|
this.readOnly = query.isReadOnly();
|
||||||
this.disableLazyLoading = query.isDisableLazyLoading();
|
this.disableLazyLoading = query.isDisableLazyLoading();
|
||||||
this.objectGraphNode = query.parentNode();
|
this.objectGraphNode = query.parentNode();
|
||||||
this.profilingListener = query.profilingListener();
|
this.profilingListener = query.profilingListener();
|
||||||
|
|||||||
@@ -305,6 +305,11 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
|
|||||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <A> Optional<A> findSingleAttributeOrEmpty() {
|
||||||
|
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCountDistinct() {
|
public boolean isCountDistinct() {
|
||||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||||
|
|||||||
@@ -51,6 +51,10 @@ public final class DefaultOrmQueryEngine implements OrmQueryEngine {
|
|||||||
* Flushes the jdbc batch by default unless explicitly turned off on the transaction.
|
* Flushes the jdbc batch by default unless explicitly turned off on the transaction.
|
||||||
*/
|
*/
|
||||||
private <T> void flushJdbcBatchOnQuery(OrmQueryRequest<T> request) {
|
private <T> void flushJdbcBatchOnQuery(OrmQueryRequest<T> request) {
|
||||||
|
if (request.query().isUsingFuture()) {
|
||||||
|
// future queries never invoke a flush
|
||||||
|
return;
|
||||||
|
}
|
||||||
SpiTransaction t = request.transaction();
|
SpiTransaction t = request.transaction();
|
||||||
if (t.isFlushOnQuery()) {
|
if (t.isFlushOnQuery()) {
|
||||||
// before we perform a query, we need to flush any
|
// before we perform a query, we need to flush any
|
||||||
|
|||||||
@@ -9,8 +9,10 @@ import io.ebeaninternal.api.*;
|
|||||||
import io.ebeaninternal.server.dto.DtoBeanDescriptor;
|
import io.ebeaninternal.server.dto.DtoBeanDescriptor;
|
||||||
import io.ebeaninternal.server.dto.DtoMappingRequest;
|
import io.ebeaninternal.server.dto.DtoMappingRequest;
|
||||||
import io.ebeaninternal.server.dto.DtoQueryPlan;
|
import io.ebeaninternal.server.dto.DtoQueryPlan;
|
||||||
|
import io.ebeaninternal.server.transaction.ExternalJdbcTransaction;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.sql.Connection;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -86,6 +88,12 @@ public final class DefaultDtoQuery<T> extends AbstractQuery implements SpiDtoQue
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DtoQuery<T> usingConnection(Connection connection) {
|
||||||
|
this.transaction = new ExternalJdbcTransaction(connection);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DtoQuery<T> usingMaster() {
|
public DtoQuery<T> usingMaster() {
|
||||||
this.useMaster = true;
|
this.useMaster = true;
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
|
|||||||
private Type type;
|
private Type type;
|
||||||
private String label;
|
private String label;
|
||||||
private Mode mode = Mode.NORMAL;
|
private Mode mode = Mode.NORMAL;
|
||||||
|
private boolean usingFuture;
|
||||||
private Object tenantId;
|
private Object tenantId;
|
||||||
/**
|
/**
|
||||||
* Holds query in structured form.
|
* Holds query in structured form.
|
||||||
@@ -971,6 +972,16 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
|
|||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void usingFuture() {
|
||||||
|
this.usingFuture = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean isUsingFuture() {
|
||||||
|
return usingFuture;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean isUsageProfiling() {
|
public final boolean isUsageProfiling() {
|
||||||
return usageProfiling;
|
return usageProfiling;
|
||||||
@@ -1161,7 +1172,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
|
|||||||
// add the rawSql statement - if any
|
// add the rawSql statement - if any
|
||||||
if (orderByIsEmpty()) {
|
if (orderByIsEmpty()) {
|
||||||
if (rawSql != null && rawSql.getSql() != null) {
|
if (rawSql != null && rawSql.getSql() != null) {
|
||||||
order(rawSql.getSql().getOrderBy());
|
orderBy(rawSql.getSql().getOrderBy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (checkPagingOrderBy()) {
|
if (checkPagingOrderBy()) {
|
||||||
@@ -1517,7 +1528,6 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public final <A> List<A> findSingleAttributeList() {
|
public final <A> List<A> findSingleAttributeList() {
|
||||||
return server.findSingleAttributeList(this);
|
return server.findSingleAttributeList(this);
|
||||||
}
|
}
|
||||||
@@ -1533,6 +1543,11 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
|
|||||||
return !list.isEmpty() ? list.get(0) : null;
|
return !list.isEmpty() ? list.get(0) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final <A> Optional<A> findSingleAttributeOrEmpty() {
|
||||||
|
return Optional.ofNullable(findSingleAttribute());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final T findOne() {
|
public final T findOne() {
|
||||||
return server.findOne(this);
|
return server.findOne(this);
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import io.ebeaninternal.api.BindParams;
|
|||||||
import io.ebeaninternal.api.SpiEbeanServer;
|
import io.ebeaninternal.api.SpiEbeanServer;
|
||||||
import io.ebeaninternal.api.SpiSqlQuery;
|
import io.ebeaninternal.api.SpiSqlQuery;
|
||||||
import io.ebeaninternal.api.SpiTransaction;
|
import io.ebeaninternal.api.SpiTransaction;
|
||||||
|
import io.ebeaninternal.server.transaction.ExternalJdbcTransaction;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@@ -50,6 +52,12 @@ public final class DefaultRelationalQuery extends AbstractQuery implements SpiSq
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqlQuery usingConnection(Connection connection) {
|
||||||
|
this.transaction = new ExternalJdbcTransaction(connection);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqlQuery usingMaster() {
|
public SqlQuery usingMaster() {
|
||||||
this.useMaster = true;
|
this.useMaster = true;
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package io.ebeaninternal.server.type;
|
package io.ebeaninternal.server.type;
|
||||||
|
|
||||||
import io.ebean.core.type.ScalarType;
|
|
||||||
import io.ebean.core.type.BasicTypeConverter;
|
import io.ebean.core.type.BasicTypeConverter;
|
||||||
|
import io.ebean.core.type.ScalarType;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,6 +35,8 @@ interface ArrayElementConverter<T> {
|
|||||||
ArrayElementConverter<Double> DOUBLE = new DoubleConverter();
|
ArrayElementConverter<Double> DOUBLE = new DoubleConverter();
|
||||||
ArrayElementConverter<Float> FLOAT = new FloatConverter();
|
ArrayElementConverter<Float> FLOAT = new FloatConverter();
|
||||||
ArrayElementConverter<BigDecimal> BIG_DECIMAL = new BigDecimalConverter();
|
ArrayElementConverter<BigDecimal> BIG_DECIMAL = new BigDecimalConverter();
|
||||||
|
ArrayElementConverter<Instant> INSTANT = new InstantConverter();
|
||||||
|
ArrayElementConverter<LocalDate> LOCAL_DATE = new LocalDateConverter();
|
||||||
|
|
||||||
class LongConverter implements ArrayElementConverter<Long> {
|
class LongConverter implements ArrayElementConverter<Long> {
|
||||||
|
|
||||||
@@ -101,6 +106,48 @@ interface ArrayElementConverter<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class InstantConverter implements ArrayElementConverter<Instant> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Instant fromSerialized(Object rawValue) {
|
||||||
|
return fromDbArray(rawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Instant fromDbArray(Object rawValue) {
|
||||||
|
if (rawValue instanceof Instant) {
|
||||||
|
return (Instant) rawValue;
|
||||||
|
} else if (rawValue instanceof Timestamp) {
|
||||||
|
return ((Timestamp) rawValue).toInstant();
|
||||||
|
} else if (rawValue instanceof String) {
|
||||||
|
return Instant.parse((String) rawValue);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Instant fromDbArray unsupported for " + rawValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocalDateConverter implements ArrayElementConverter<LocalDate> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LocalDate fromSerialized(Object rawValue) {
|
||||||
|
return fromDbArray(rawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LocalDate fromDbArray(Object rawValue) {
|
||||||
|
if (rawValue instanceof LocalDate) {
|
||||||
|
return (LocalDate) rawValue;
|
||||||
|
} else if (rawValue instanceof java.sql.Date) {
|
||||||
|
return ((java.sql.Date) rawValue).toLocalDate();
|
||||||
|
} else if (rawValue instanceof String) {
|
||||||
|
return LocalDate.parse((String) rawValue);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Instant fromDbArray unsupported for " + rawValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class BigDecimalConverter implements ArrayElementConverter<BigDecimal> {
|
class BigDecimalConverter implements ArrayElementConverter<BigDecimal> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -141,7 +188,7 @@ interface ArrayElementConverter<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public java.util.UUID fromSerialized(Object rawValue) {
|
public java.util.UUID fromSerialized(Object rawValue) {
|
||||||
return java.util.UUID.fromString((String)rawValue);
|
return java.util.UUID.fromString((String) rawValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import java.lang.reflect.Type;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
@@ -63,6 +65,12 @@ class ScalarTypeArrayList extends ScalarTypeArrayBase<List> implements ScalarTyp
|
|||||||
if (valueType.equals(String.class)) {
|
if (valueType.equals(String.class)) {
|
||||||
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING));
|
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING));
|
||||||
}
|
}
|
||||||
|
if (valueType.equals(Instant.class)) {
|
||||||
|
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "timestamptz", DocPropertyType.TEXT, ArrayElementConverter.INSTANT));
|
||||||
|
}
|
||||||
|
if (valueType.equals(LocalDate.class)) {
|
||||||
|
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "date", DocPropertyType.TEXT, ArrayElementConverter.LOCAL_DATE));
|
||||||
|
}
|
||||||
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
|
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import java.lang.reflect.Type;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -58,6 +60,12 @@ final class ScalarTypeArrayListH2 extends ScalarTypeArrayList {
|
|||||||
if (valueType.equals(String.class)) {
|
if (valueType.equals(String.class)) {
|
||||||
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING));
|
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING));
|
||||||
}
|
}
|
||||||
|
if (valueType.equals(Instant.class)) {
|
||||||
|
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "timestamp", DocPropertyType.TEXT, ArrayElementConverter.INSTANT));
|
||||||
|
}
|
||||||
|
if (valueType.equals(LocalDate.class)) {
|
||||||
|
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "date", DocPropertyType.TEXT, ArrayElementConverter.LOCAL_DATE));
|
||||||
|
}
|
||||||
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
|
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ public class InitDataSourceTest {
|
|||||||
@Test
|
@Test
|
||||||
public void readOnlyConfig_when_urlSet_2() {
|
public void readOnlyConfig_when_urlSet_2() {
|
||||||
DatabaseConfig config = new DatabaseConfig();
|
DatabaseConfig config = new DatabaseConfig();
|
||||||
config.settings().getReadOnlyDataSourceConfig().url("foo");
|
config.getReadOnlyDataSourceConfig().url("foo");
|
||||||
|
|
||||||
final DataSourceBuilder roConfig = new InitDataSource(config).readOnlyConfig();
|
final DataSourceBuilder roConfig = new InitDataSource(config).readOnlyConfig();
|
||||||
assertNotNull(roConfig);
|
assertNotNull(roConfig);
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ public class BetweenPropertyExpressionTest extends BaseExpressionTest {
|
|||||||
public void sqlExpression() {
|
public void sqlExpression() {
|
||||||
TDSpiExpressionRequest request = new TDSpiExpressionRequest(null);
|
TDSpiExpressionRequest request = new TDSpiExpressionRequest(null);
|
||||||
exp("a", "b", 10).addSql(request);
|
exp("a", "b", 10).addSql(request);
|
||||||
Assertions.assertThat(request.sql()).isEqualTo(" ? between a and b");
|
Assertions.assertThat(request.sql()).isEqualTo("? between a and b");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<name>ebean ddl generation</name>
|
<name>ebean ddl generation</name>
|
||||||
@@ -28,14 +28,14 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core-type</artifactId>
|
<artifactId>ebean-core-type</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-all</artifactId>
|
<artifactId>ebean-platform-all</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|||||||
+16
-4
@@ -1,5 +1,6 @@
|
|||||||
package io.ebeaninternal.dbmigration.model;
|
package io.ebeaninternal.dbmigration.model;
|
||||||
|
|
||||||
|
import io.ebean.annotation.ConstraintMode;
|
||||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DdlHelp;
|
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DdlHelp;
|
||||||
import io.ebeaninternal.dbmigration.migration.AlterForeignKey;
|
import io.ebeaninternal.dbmigration.migration.AlterForeignKey;
|
||||||
import io.ebeaninternal.dbmigration.migration.ForeignKey;
|
import io.ebeaninternal.dbmigration.migration.ForeignKey;
|
||||||
@@ -22,6 +23,8 @@ public class MCompoundForeignKey {
|
|||||||
private final List<String> columns = new ArrayList<>();
|
private final List<String> columns = new ArrayList<>();
|
||||||
private final List<String> referenceColumns = new ArrayList<>();
|
private final List<String> referenceColumns = new ArrayList<>();
|
||||||
private String indexName;
|
private String indexName;
|
||||||
|
private ConstraintMode fkeyOnDelete;
|
||||||
|
private ConstraintMode fkeyOnUpdate;
|
||||||
|
|
||||||
public MCompoundForeignKey(String name, String referenceTable, String indexName) {
|
public MCompoundForeignKey(String name, String referenceTable, String indexName) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -47,9 +50,15 @@ public class MCompoundForeignKey {
|
|||||||
fk.setColumnNames(toColumnNames(columns));
|
fk.setColumnNames(toColumnNames(columns));
|
||||||
fk.setRefColumnNames(toColumnNames(referenceColumns));
|
fk.setRefColumnNames(toColumnNames(referenceColumns));
|
||||||
fk.setRefTableName(referenceTable);
|
fk.setRefTableName(referenceTable);
|
||||||
|
fk.setOnDelete(fkeyModeOf(fkeyOnDelete));
|
||||||
|
fk.setOnUpdate(fkeyModeOf(fkeyOnUpdate));
|
||||||
return fk;
|
return fk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String fkeyModeOf(ConstraintMode mode) {
|
||||||
|
return (mode == null) ? null : mode.name();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and return an AlterForeignKey migration element.
|
* Create and return an AlterForeignKey migration element.
|
||||||
*/
|
*/
|
||||||
@@ -63,7 +72,7 @@ public class MCompoundForeignKey {
|
|||||||
fk.setTableName(tableName);
|
fk.setTableName(tableName);
|
||||||
return fk;
|
return fk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and return an AlterForeignKey migration element.
|
* Create and return an AlterForeignKey migration element.
|
||||||
*/
|
*/
|
||||||
@@ -117,7 +126,6 @@ public class MCompoundForeignKey {
|
|||||||
* Return as an array of string column names.
|
* Return as an array of string column names.
|
||||||
*/
|
*/
|
||||||
private String toColumnNames(List<String> columns) {
|
private String toColumnNames(List<String> columns) {
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder(40);
|
StringBuilder sb = new StringBuilder(40);
|
||||||
for (int i = 0; i < columns.size(); i++) {
|
for (int i = 0; i < columns.size(); i++) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
@@ -139,7 +147,7 @@ public class MCompoundForeignKey {
|
|||||||
return true;
|
return true;
|
||||||
if (!(obj instanceof MCompoundForeignKey))
|
if (!(obj instanceof MCompoundForeignKey))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MCompoundForeignKey other = (MCompoundForeignKey) obj;
|
MCompoundForeignKey other = (MCompoundForeignKey) obj;
|
||||||
return Objects.equals(columns, other.columns)
|
return Objects.equals(columns, other.columns)
|
||||||
&& Objects.equals(indexName, other.indexName)
|
&& Objects.equals(indexName, other.indexName)
|
||||||
@@ -148,4 +156,8 @@ public class MCompoundForeignKey {
|
|||||||
&& Objects.equals(referenceTable, other.referenceTable);
|
&& Objects.equals(referenceTable, other.referenceTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setForeignKeyModes(ConstraintMode onDelete, ConstraintMode onUpdate) {
|
||||||
|
this.fkeyOnDelete = onDelete;
|
||||||
|
this.fkeyOnUpdate = onUpdate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-21
@@ -91,7 +91,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitEnd() {
|
public void visitEnd() {
|
||||||
|
|
||||||
// set the primary key name
|
// set the primary key name
|
||||||
table.setPkName(primaryKeyName());
|
table.setPkName(primaryKeyName());
|
||||||
|
|
||||||
@@ -169,6 +168,8 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitOneImported(BeanPropertyAssocOne<?> p) {
|
public void visitOneImported(BeanPropertyAssocOne<?> p) {
|
||||||
|
PropertyForeignKey foreignKey = p.foreignKey();
|
||||||
|
boolean addForeignKey = foreignKey == null || !foreignKey.isNoConstraint();
|
||||||
|
|
||||||
TableJoinColumn[] columns = p.tableJoin().columns();
|
TableJoinColumn[] columns = p.tableJoin().columns();
|
||||||
if (columns.length == 0) {
|
if (columns.length == 0) {
|
||||||
@@ -178,17 +179,19 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
|||||||
List<MColumn> modelColumns = new ArrayList<>(columns.length);
|
List<MColumn> modelColumns = new ArrayList<>(columns.length);
|
||||||
|
|
||||||
MCompoundForeignKey compoundKey = null;
|
MCompoundForeignKey compoundKey = null;
|
||||||
if (columns.length > 1) {
|
if (addForeignKey && columns.length > 1) {
|
||||||
// compound foreign key
|
// compound foreign key
|
||||||
String refTable = p.targetDescriptor().baseTable();
|
String refTable = p.targetDescriptor().baseTable();
|
||||||
String fkName = foreignKeyConstraintName(p.name());
|
String fkName = foreignKeyConstraintName(p.name());
|
||||||
String fkIndex = foreignKeyIndexName(p.name());
|
String fkIndex = foreignKeyIndexName(p.name());
|
||||||
compoundKey = new MCompoundForeignKey(fkName, refTable, fkIndex);
|
compoundKey = new MCompoundForeignKey(fkName, refTable, fkIndex);
|
||||||
|
if (foreignKey != null) {
|
||||||
|
compoundKey.setForeignKeyModes(foreignKey.getOnDelete(), foreignKey.getOnUpdate());
|
||||||
|
}
|
||||||
table.addForeignKey(compoundKey);
|
table.addForeignKey(compoundKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TableJoinColumn column : columns) {
|
for (TableJoinColumn column : columns) {
|
||||||
|
|
||||||
String dbCol = column.getLocalDbColumn();
|
String dbCol = column.getLocalDbColumn();
|
||||||
BeanProperty importedProperty = p.findMatchImport(dbCol);
|
BeanProperty importedProperty = p.findMatchImport(dbCol);
|
||||||
if (importedProperty == null) {
|
if (importedProperty == null) {
|
||||||
@@ -200,26 +203,28 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
|||||||
MColumn col = table.addColumn(dbCol, columnDefn, !p.isNullable());
|
MColumn col = table.addColumn(dbCol, columnDefn, !p.isNullable());
|
||||||
col.setDbMigrationInfos(p.dbMigrationInfos());
|
col.setDbMigrationInfos(p.dbMigrationInfos());
|
||||||
col.setDefaultValue(p.dbColumnDefault());
|
col.setDefaultValue(p.dbColumnDefault());
|
||||||
if (columns.length == 1) {
|
col.setComment(p.dbComment());
|
||||||
if (p.hasForeignKeyConstraint() && !importedProperty.descriptor().suppressForeignKey()) {
|
if (addForeignKey) {
|
||||||
// single references column (put it on the column)
|
if (columns.length > 1) {
|
||||||
String refTable = importedProperty.descriptor().baseTable();
|
compoundKey.addColumnPair(dbCol, refColumn);
|
||||||
if (refTable == null) {
|
} else {
|
||||||
// odd case where an EmbeddedId only has 1 property
|
if (p.hasForeignKeyConstraint() && !importedProperty.descriptor().suppressForeignKey()) {
|
||||||
refTable = p.targetDescriptor().baseTable();
|
// single references column (put it on the column)
|
||||||
}
|
String refTable = importedProperty.descriptor().baseTable();
|
||||||
col.setReferences(refTable + "." + refColumn);
|
if (refTable == null) {
|
||||||
col.setForeignKeyName(foreignKeyConstraintName(col.getName()));
|
// odd case where an EmbeddedId only has 1 property
|
||||||
if (p.hasForeignKeyIndex()) {
|
refTable = p.targetDescriptor().baseTable();
|
||||||
col.setForeignKeyIndex(foreignKeyIndexName(col.getName()));
|
}
|
||||||
}
|
col.setReferences(refTable + "." + refColumn);
|
||||||
PropertyForeignKey foreignKey = p.foreignKey();
|
col.setForeignKeyName(foreignKeyConstraintName(col.getName()));
|
||||||
if (foreignKey != null) {
|
if (p.hasForeignKeyIndex()) {
|
||||||
col.setForeignKeyModes(foreignKey.getOnDelete(), foreignKey.getOnUpdate());
|
col.setForeignKeyIndex(foreignKeyIndexName(col.getName()));
|
||||||
|
}
|
||||||
|
if (foreignKey != null) {
|
||||||
|
col.setForeignKeyModes(foreignKey.getOnDelete(), foreignKey.getOnUpdate());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
compoundKey.addColumnPair(dbCol, refColumn);
|
|
||||||
}
|
}
|
||||||
modelColumns.add(col);
|
modelColumns.add(col);
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-3
@@ -1,8 +1,6 @@
|
|||||||
package io.ebeaninternal.dbmigration.model.build;
|
package io.ebeaninternal.dbmigration.model.build;
|
||||||
|
|
||||||
|
|
||||||
import io.ebean.DatabaseBuilder;
|
|
||||||
import io.localtest.BaseTestCase;
|
|
||||||
import io.ebean.DB;
|
import io.ebean.DB;
|
||||||
import io.ebean.DatabaseFactory;
|
import io.ebean.DatabaseFactory;
|
||||||
import io.ebean.config.DatabaseConfig;
|
import io.ebean.config.DatabaseConfig;
|
||||||
@@ -11,11 +9,13 @@ import io.ebean.platform.h2.H2Platform;
|
|||||||
import io.ebean.platform.sqlserver.SqlServer17Platform;
|
import io.ebean.platform.sqlserver.SqlServer17Platform;
|
||||||
import io.ebeaninternal.api.SpiEbeanServer;
|
import io.ebeaninternal.api.SpiEbeanServer;
|
||||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DefaultConstraintMaxLength;
|
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DefaultConstraintMaxLength;
|
||||||
|
import io.ebeaninternal.dbmigration.migration.ForeignKey;
|
||||||
import io.ebeaninternal.dbmigration.model.MColumn;
|
import io.ebeaninternal.dbmigration.model.MColumn;
|
||||||
import io.ebeaninternal.dbmigration.model.MCompoundForeignKey;
|
import io.ebeaninternal.dbmigration.model.MCompoundForeignKey;
|
||||||
import io.ebeaninternal.dbmigration.model.MTable;
|
import io.ebeaninternal.dbmigration.model.MTable;
|
||||||
import io.ebeaninternal.dbmigration.model.ModelContainer;
|
import io.ebeaninternal.dbmigration.model.ModelContainer;
|
||||||
import io.ebeaninternal.dbmigration.model.visitor.VisitAllUsing;
|
import io.ebeaninternal.dbmigration.model.visitor.VisitAllUsing;
|
||||||
|
import io.localtest.BaseTestCase;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.tests.model.basic.CKeyAssoc;
|
import org.tests.model.basic.CKeyAssoc;
|
||||||
import org.tests.model.basic.CKeyDetail;
|
import org.tests.model.basic.CKeyDetail;
|
||||||
@@ -44,10 +44,12 @@ public class ModelBuildBeanVisitorTest extends BaseTestCase {
|
|||||||
new VisitAllUsing(addTable, defaultServer).visitAllBeans();
|
new VisitAllUsing(addTable, defaultServer).visitAllBeans();
|
||||||
|
|
||||||
assert_compound_pk(model);
|
assert_compound_pk(model);
|
||||||
|
assert_compound_fk(model);
|
||||||
|
|
||||||
assert_discriminatorColumn_explicit(model);
|
assert_discriminatorColumn_explicit(model);
|
||||||
assert_discriminatorColumn_implied(model);
|
assert_discriminatorColumn_implied(model);
|
||||||
assert_discriminatorColumn_length(model);
|
assert_discriminatorColumn_length(model);
|
||||||
|
assert_comment_onManyToOne(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -73,7 +75,7 @@ public class ModelBuildBeanVisitorTest extends BaseTestCase {
|
|||||||
config.setDbOffline(true);
|
config.setDbOffline(true);
|
||||||
config.setDatabasePlatform(new SqlServer17Platform());
|
config.setDatabasePlatform(new SqlServer17Platform());
|
||||||
|
|
||||||
final SpiEbeanServer database = (SpiEbeanServer)DatabaseFactory.create(config);
|
final SpiEbeanServer database = (SpiEbeanServer) DatabaseFactory.create(config);
|
||||||
try {
|
try {
|
||||||
ModelBuildContext ctx = new ModelBuildContext(model, config.getDatabasePlatform(), config.getConstraintNaming(), true);
|
ModelBuildContext ctx = new ModelBuildContext(model, config.getDatabasePlatform(), config.getConstraintNaming(), true);
|
||||||
|
|
||||||
@@ -105,6 +107,21 @@ public class ModelBuildBeanVisitorTest extends BaseTestCase {
|
|||||||
assertThat(item.primaryKeyColumns()).hasSize(2);
|
assertThat(item.primaryKeyColumns()).hasSize(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assert_compound_fk(ModelContainer model) {
|
||||||
|
MTable item = model.getTable("item");
|
||||||
|
assertThat(item).isNotNull();
|
||||||
|
List<MCompoundForeignKey> compoundKeys = item.getCompoundKeys();
|
||||||
|
assertThat(compoundKeys).hasSize(1);
|
||||||
|
|
||||||
|
MCompoundForeignKey compoundForeignKey = compoundKeys.get(0);
|
||||||
|
ForeignKey foreignKey = compoundForeignKey.createForeignKey();
|
||||||
|
assertThat(foreignKey.getName()).isEqualTo("fk_item_etype");
|
||||||
|
assertThat(foreignKey.getColumnNames()).isEqualTo("customer,type");
|
||||||
|
assertThat(foreignKey.getRefTableName()).isEqualTo("\"type\"");
|
||||||
|
assertThat(foreignKey.getOnDelete()).isEqualTo("SET_NULL");
|
||||||
|
assertThat(foreignKey.getOnUpdate()).isEqualTo("SET_DEFAULT");
|
||||||
|
}
|
||||||
|
|
||||||
private void assert_discriminatorColumn_explicit(ModelContainer model) {
|
private void assert_discriminatorColumn_explicit(ModelContainer model) {
|
||||||
|
|
||||||
MTable configuration = model.getTable("configuration");
|
MTable configuration = model.getTable("configuration");
|
||||||
@@ -128,4 +145,11 @@ public class ModelBuildBeanVisitorTest extends BaseTestCase {
|
|||||||
assertThat(discTypeColumn.getType()).isEqualTo("varchar(3)");
|
assertThat(discTypeColumn.getType()).isEqualTo("varchar(3)");
|
||||||
assertThat(discTypeColumn.isNotnull()).isTrue();
|
assertThat(discTypeColumn.isNotnull()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assert_comment_onManyToOne(ModelContainer model) {
|
||||||
|
MTable message = model.getTable("c_message");
|
||||||
|
MColumn conversation = message.getColumn("conversation_id");
|
||||||
|
assertThat(conversation.getType()).isEqualTo("bigint");
|
||||||
|
assertThat(conversation.getComment()).isEqualTo("A ManyToOne comment");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.tests.model.compositekeys;
|
package org.tests.model.compositekeys;
|
||||||
|
|
||||||
|
import io.ebean.annotation.ConstraintMode;
|
||||||
|
import io.ebean.annotation.DbForeignKey;
|
||||||
import jakarta.persistence.AttributeOverride;
|
import jakarta.persistence.AttributeOverride;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Embedded;
|
import jakarta.persistence.Embedded;
|
||||||
@@ -32,11 +34,13 @@ public class Item {
|
|||||||
@Version
|
@Version
|
||||||
private Long version;
|
private Long version;
|
||||||
|
|
||||||
|
@DbForeignKey(onDelete = ConstraintMode.SET_NULL, onUpdate = ConstraintMode.SET_DEFAULT)
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "customer", referencedColumnName = "customer", insertable = false, updatable = false)
|
@JoinColumn(name = "customer", referencedColumnName = "customer", insertable = false, updatable = false)
|
||||||
@JoinColumn(name = "type", referencedColumnName = "type", insertable = false, updatable = false)
|
@JoinColumn(name = "type", referencedColumnName = "type", insertable = false, updatable = false)
|
||||||
private Type eType;
|
private Type eType;
|
||||||
|
|
||||||
|
@DbForeignKey(noConstraint = true)
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "customer", referencedColumnName = "customer", insertable = false, updatable = false)
|
@JoinColumn(name = "customer", referencedColumnName = "customer", insertable = false, updatable = false)
|
||||||
@JoinColumn(name = "region", referencedColumnName = "type", insertable = false, updatable = false)
|
@JoinColumn(name = "region", referencedColumnName = "type", insertable = false, updatable = false)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.tests.model.converstation;
|
package org.tests.model.converstation;
|
||||||
|
|
||||||
|
import io.ebean.annotation.DbComment;
|
||||||
import org.tests.model.BaseModel;
|
import org.tests.model.BaseModel;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
@@ -14,6 +15,7 @@ public class Message extends BaseModel {
|
|||||||
|
|
||||||
String body;
|
String body;
|
||||||
|
|
||||||
|
@DbComment("A ManyToOne comment")
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
Conversation conversation;
|
Conversation conversation;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core-type</artifactId>
|
<artifactId>ebean-core-type</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<name>ebean postgis types</name>
|
<name>ebean postgis types</name>
|
||||||
@@ -19,14 +19,14 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-platform-postgres</artifactId>
|
<artifactId>ebean-platform-postgres</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- provided scope -->
|
<!-- provided scope -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-test</artifactId>
|
<artifactId>ebean-test</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>ebean-parent</artifactId>
|
<artifactId>ebean-parent</artifactId>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<name>ebean querybean</name>
|
<name>ebean querybean</name>
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-core</artifactId>
|
<artifactId>ebean-core</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
@@ -63,14 +63,14 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-ddl-generator</artifactId>
|
<artifactId>ebean-ddl-generator</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>ebean-test</artifactId>
|
<artifactId>ebean-test</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.ebean</groupId>
|
<groupId>io.ebean</groupId>
|
||||||
<artifactId>querybean-generator</artifactId>
|
<artifactId>querybean-generator</artifactId>
|
||||||
<version>13.24.0-jakarta</version>
|
<version>13.26.1-jakarta</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|||||||
@@ -304,6 +304,14 @@ public abstract class PBaseComparable<R, T> extends PBaseValueEqual<R, T> {
|
|||||||
return _root;
|
return _root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Between - value between this property and another property
|
||||||
|
*/
|
||||||
|
public final R betweenProperties(Query.Property<T> highProperty, T value) {
|
||||||
|
expr().betweenProperties(_name, highProperty.toString(), value);
|
||||||
|
return _root;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Greater than.
|
* Greater than.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public abstract class PBaseString<R, T> extends PBaseComparable<R, T> {
|
|||||||
* @param value the equal to bind value
|
* @param value the equal to bind value
|
||||||
* @return the root query bean instance
|
* @return the root query bean instance
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated(forRemoval = true)
|
||||||
public final R equalToType(T value) {
|
public final R equalToType(T value) {
|
||||||
expr().eq(_name, value);
|
expr().eq(_name, value);
|
||||||
return _root;
|
return _root;
|
||||||
@@ -46,7 +46,7 @@ public abstract class PBaseString<R, T> extends PBaseComparable<R, T> {
|
|||||||
* @param value the equal to bind value
|
* @param value the equal to bind value
|
||||||
* @return the root query bean instance
|
* @return the root query bean instance
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated(forRemoval = true)
|
||||||
public final R notEqualToType(T value) {
|
public final R notEqualToType(T value) {
|
||||||
expr().ne(_name, value);
|
expr().ne(_name, value);
|
||||||
return _root;
|
return _root;
|
||||||
|
|||||||
@@ -745,7 +745,7 @@ public abstract class TQRootBean<T, R> {
|
|||||||
* Add EXISTS sub-query predicate.
|
* Add EXISTS sub-query predicate.
|
||||||
*/
|
*/
|
||||||
public R exists(Query<?> subQuery) {
|
public R exists(Query<?> subQuery) {
|
||||||
query.where().exists(subQuery);
|
peekExprList().exists(subQuery);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,7 +753,7 @@ public abstract class TQRootBean<T, R> {
|
|||||||
* Add NOT EXISTS sub-query predicate.
|
* Add NOT EXISTS sub-query predicate.
|
||||||
*/
|
*/
|
||||||
public R notExists(Query<?> subQuery) {
|
public R notExists(Query<?> subQuery) {
|
||||||
query.where().notExists(subQuery);
|
peekExprList().notExists(subQuery);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -764,7 +764,7 @@ public abstract class TQRootBean<T, R> {
|
|||||||
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
|
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
|
||||||
*/
|
*/
|
||||||
public final R exists(String sqlSubQuery, Object... bindValues) {
|
public final R exists(String sqlSubQuery, Object... bindValues) {
|
||||||
query().where().exists(sqlSubQuery, bindValues);
|
peekExprList().exists(sqlSubQuery, bindValues);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -775,7 +775,7 @@ public abstract class TQRootBean<T, R> {
|
|||||||
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
|
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
|
||||||
*/
|
*/
|
||||||
public final R notExists(String sqlSubQuery, Object... bindValues) {
|
public final R notExists(String sqlSubQuery, Object... bindValues) {
|
||||||
query().where().notExists(sqlSubQuery, bindValues);
|
peekExprList().notExists(sqlSubQuery, bindValues);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1275,7 +1275,7 @@ public abstract class TQRootBean<T, R> {
|
|||||||
/**
|
/**
|
||||||
* @deprecated migrate to {@link #orderBy()}.
|
* @deprecated migrate to {@link #orderBy()}.
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "13.19")
|
@Deprecated(since = "13.19", forRemoval = true)
|
||||||
public R order() {
|
public R order() {
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
@@ -1295,7 +1295,7 @@ public abstract class TQRootBean<T, R> {
|
|||||||
/**
|
/**
|
||||||
* @deprecated migrate to {@link #orderBy(String)}
|
* @deprecated migrate to {@link #orderBy(String)}
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "13.19")
|
@Deprecated(since = "13.19", forRemoval = true)
|
||||||
public R order(String orderByClause) {
|
public R order(String orderByClause) {
|
||||||
return orderBy(orderByClause);
|
return orderBy(orderByClause);
|
||||||
}
|
}
|
||||||
@@ -1867,6 +1867,28 @@ public abstract class TQRootBean<T, R> {
|
|||||||
return query.findSingleAttribute();
|
return query.findSingleAttribute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the query returning a single optional attribute value.
|
||||||
|
* <p>
|
||||||
|
* <h3>Example</h3>
|
||||||
|
* <pre>{@code
|
||||||
|
*
|
||||||
|
* Optional<String> maybeName =
|
||||||
|
* new QCustomer()
|
||||||
|
* .select(name)
|
||||||
|
* .id.eq(42)
|
||||||
|
* .status.eq(NEW)
|
||||||
|
* .findSingleAttributeOrEmpty();
|
||||||
|
*
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @return an optional value for the selected property
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public <A> Optional<A> findSingleAttributeOrEmpty() {
|
||||||
|
return query.findSingleAttributeOrEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the query processing the beans one at a time.
|
* Execute the query processing the beans one at a time.
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package org.example.domain;
|
package org.example.domain;
|
||||||
|
|
||||||
import io.ebean.annotation.DbArray;
|
import io.ebean.annotation.DbArray;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
|
import org.example.domain.finder.ContactFinder;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import javax.validation.constraints.Size;
|
import javax.validation.constraints.Size;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
@@ -17,6 +18,11 @@ import java.util.Map;
|
|||||||
@Table(name = "be_contact")
|
@Table(name = "be_contact")
|
||||||
public class Contact extends BaseModel {
|
public class Contact extends BaseModel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience Finder for 'active record' style.
|
||||||
|
*/
|
||||||
|
public static final ContactFinder find = new ContactFinder();
|
||||||
|
|
||||||
@DbArray
|
@DbArray
|
||||||
List<@Size(max=20) String> phoneNumbers = new ArrayList<>();
|
List<@Size(max=20) String> phoneNumbers = new ArrayList<>();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.example.domain;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class PFile {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
long id;
|
||||||
|
String name;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.example.domain;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class PLong {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
long id;
|
||||||
|
String name;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.example.domain;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Pinstant {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
long id;
|
||||||
|
String name;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.example.domain.finder;
|
||||||
|
|
||||||
|
import io.ebean.Finder;
|
||||||
|
import org.example.domain.Contact;
|
||||||
|
import org.example.domain.query.QContact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class ContactFinder extends Finder<Long, Contact> {
|
||||||
|
|
||||||
|
public ContactFinder() {
|
||||||
|
super(Contact.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public QContact typed() {
|
||||||
|
return new QContact();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package org.querytest;
|
package org.querytest;
|
||||||
|
|
||||||
|
import org.example.domain.Contact;
|
||||||
import org.example.domain.Customer;
|
import org.example.domain.Customer;
|
||||||
|
import org.example.domain.query.QCustomer;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
@@ -9,6 +11,8 @@ import java.time.ZoneId;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
public class QCustomerAndOrTest {
|
public class QCustomerAndOrTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -55,6 +59,30 @@ public class QCustomerAndOrTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOrWithExists() {
|
||||||
|
QCustomer query = Customer.find.typed()
|
||||||
|
.alias("_cust")
|
||||||
|
.or()
|
||||||
|
.name.eq("Superman")
|
||||||
|
.exists(Contact.find.typed()
|
||||||
|
.alias("contact")
|
||||||
|
.firstName.eq("Superman")
|
||||||
|
.raw("contact.customer_id = _cust.id")
|
||||||
|
.query()
|
||||||
|
)
|
||||||
|
.endOr()
|
||||||
|
.select(QCustomer.alias().id);
|
||||||
|
|
||||||
|
query.findList();
|
||||||
|
|
||||||
|
assertThat(query.getGeneratedSql()).isEqualTo(
|
||||||
|
"select _cust.id from be_customer _cust where (" +
|
||||||
|
"_cust.name = ? or exists (select 1 from be_contact contact where " +
|
||||||
|
"contact.first_name = ? and contact.customer_id = _cust.id))"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private Date fiveDaysAgo() {
|
private Date fiveDaysAgo() {
|
||||||
LocalDateTime fiveDaysAgo = LocalDate.now().atStartOfDay().minusDays(5);
|
LocalDateTime fiveDaysAgo = LocalDate.now().atStartOfDay().minusDays(5);
|
||||||
return new Date(fiveDaysAgo.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
|
return new Date(fiveDaysAgo.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
|
||||||
|
|||||||
@@ -63,6 +63,25 @@ public class QCustomerTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void copy() {
|
||||||
|
var origin = new QCustomer()
|
||||||
|
.setDistinct(true)
|
||||||
|
.status.equalTo(Customer.Status.BAD);
|
||||||
|
|
||||||
|
var copy1 = origin.copy().name.isNotNull();
|
||||||
|
var q1 = copy1.query();
|
||||||
|
copy1.findList();
|
||||||
|
|
||||||
|
assertThat(q1.getGeneratedSql()).contains("from be_customer t0 where t0.status = ? and t0.name is not null");
|
||||||
|
|
||||||
|
var copy2 = origin.copy().version.ge(1L);
|
||||||
|
var q2 = copy2.query();
|
||||||
|
copy2.findList();
|
||||||
|
|
||||||
|
assertThat(q2.getGeneratedSql()).contains("from be_customer t0 where t0.status = ? and t0.version >= ?");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void findSingleAttribute() {
|
public void findSingleAttribute() {
|
||||||
|
|
||||||
@@ -813,6 +832,30 @@ public class QCustomerTest {
|
|||||||
new QContact()
|
new QContact()
|
||||||
.firstName.inRangeWith(lastName, "B")
|
.firstName.inRangeWith(lastName, "B")
|
||||||
.findList();
|
.findList();
|
||||||
|
|
||||||
|
new QContact()
|
||||||
|
.firstName.between("A", "B")
|
||||||
|
.findList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void betweenProperties() {
|
||||||
|
var query = new QContact()
|
||||||
|
.firstName.betweenProperties(lastName, "B");
|
||||||
|
|
||||||
|
query.findList();
|
||||||
|
assertThat(query.getGeneratedSql()).contains(" where ? between t0.first_name and t0.last_name");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void betweenProperties_notFirstPredicate() {
|
||||||
|
var query = new QContact()
|
||||||
|
.lastName.isNotNull()
|
||||||
|
.firstName.betweenProperties(lastName, "B")
|
||||||
|
.email.isNotNull();
|
||||||
|
|
||||||
|
query.findList();
|
||||||
|
assertThat(query.getGeneratedSql()).contains(" where t0.last_name is not null and ? between t0.first_name and t0.last_name and t0.email is not null");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1026,6 +1069,32 @@ public class QCustomerTest {
|
|||||||
assertThat(maxDate).isNotNull();
|
assertThat(maxDate).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findSingleAttributeOrEmpty() {
|
||||||
|
|
||||||
|
Customer cust = new Customer();
|
||||||
|
cust.setName("MaybeIExist yeah");
|
||||||
|
cust.setStatus(Customer.Status.GOOD);
|
||||||
|
cust.setRegistered(new Date());
|
||||||
|
cust.save();
|
||||||
|
|
||||||
|
Optional<String> customerName = new QCustomer()
|
||||||
|
.select(name)
|
||||||
|
.status.eq(Customer.Status.GOOD)
|
||||||
|
.name.startsWith("MaybeIExist")
|
||||||
|
.findSingleAttributeOrEmpty();
|
||||||
|
|
||||||
|
assertThat(customerName).isPresent();
|
||||||
|
|
||||||
|
Optional<String> customerName2 = new QCustomer()
|
||||||
|
.select(name)
|
||||||
|
.status.eq(Customer.Status.GOOD)
|
||||||
|
.name.eq("NahIDoNotExist")
|
||||||
|
.findSingleAttributeOrEmpty();
|
||||||
|
|
||||||
|
assertThat(customerName2).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFetchByScalarValue() {
|
public void testFetchByScalarValue() {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user