mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
826
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db2f8cd811 | ||
|
|
b6e524f879 | ||
|
|
40492f487c | ||
|
|
2cee03bc4b | ||
|
|
e2c6125501 | ||
|
|
b53221fc0e | ||
|
|
b23551ce43 | ||
|
|
3971ccea1a | ||
|
|
35b1f835c5 | ||
|
|
ef5e3a796d | ||
|
|
d3dbde4e79 | ||
|
|
033c579984 | ||
|
|
1a34a56351 | ||
|
|
edfdbd56b1 | ||
|
|
8f94072afd | ||
|
|
d028b200fa | ||
|
|
9af006b15b | ||
|
|
35a6ff7f02 | ||
|
|
cebac8040f | ||
|
|
e8524c5b1a | ||
|
|
3244314424 | ||
|
|
0a4c26965c | ||
|
|
6238243c91 | ||
|
|
c1d7e77d85 | ||
|
|
5b07309f51 | ||
|
|
8ee67410f9 | ||
|
|
dec114028f | ||
|
|
477e7eeeda | ||
|
|
c9c61d9f97 | ||
|
|
d0909ad140 | ||
|
|
13c94ac78d | ||
|
|
f467ca2e10 | ||
|
|
d5c24d327e | ||
|
|
23cd45b5d1 | ||
|
|
a14f7a1766 | ||
|
|
c86a8c2d32 | ||
|
|
e85a471fcf | ||
|
|
57689db291 | ||
|
|
fec87b5281 | ||
|
|
21bd83b417 | ||
|
|
fde5350c43 | ||
|
|
769f6b72ae | ||
|
|
97e9b3c473 | ||
|
|
3550bf61c4 | ||
|
|
0bf8c9eb64 | ||
|
|
01e7ddcffd | ||
|
|
b450227b13 | ||
|
|
d7554cefc7 | ||
|
|
a7a056f041 | ||
|
|
ad0befe90a | ||
|
|
59763777f3 | ||
|
|
1bf9cfde50 | ||
|
|
f51f2269fb | ||
|
|
b38a21f8c4 | ||
|
|
bf62efd220 | ||
|
|
fc54ade8f6 | ||
|
|
aa5ba76707 | ||
|
|
3865fc8ffd | ||
|
|
b262c2e19d | ||
|
|
cf95372f32 | ||
|
|
41bbfb0c9c | ||
|
|
8129376b2a | ||
|
|
d016f479e2 | ||
|
|
aea50b4805 | ||
|
|
864ae2ad9b | ||
|
|
861fc813a7 | ||
|
|
f3b66c555a | ||
|
|
04ab161421 | ||
|
|
7226bb0ea3 | ||
|
|
55bfd56574 | ||
|
|
853a6a5c1d | ||
|
|
0206921eae | ||
|
|
f3dbf216d2 | ||
|
|
38139850de | ||
|
|
37b3ea9e5a | ||
|
|
4064be731f | ||
|
|
beec6b4b13 | ||
|
|
6db44a05fe | ||
|
|
45e235cb64 | ||
|
|
512ba24041 | ||
|
|
1fbfcd393f | ||
|
|
5805c3e995 | ||
|
|
c89255ec72 | ||
|
|
a582db9101 | ||
|
|
12fe54da24 | ||
|
|
a4eeda6449 | ||
|
|
1fecbbb618 | ||
|
|
c363023c80 | ||
|
|
0cfae9a13b | ||
|
|
88f75bc62f | ||
|
|
fece3bb0df | ||
|
|
268a39ae15 | ||
|
|
9324d1cebe | ||
|
|
2733608a72 | ||
|
|
e29e032693 | ||
|
|
9fc2ec044d | ||
|
|
b739326fca | ||
|
|
88fd4f5569 | ||
|
|
4cca3bfa98 | ||
|
|
8f8d031d91 | ||
|
|
7a327cb644 | ||
|
|
1696caadd4 | ||
|
|
e5dceda4b9 | ||
|
|
eab56d323b | ||
|
|
0b00a14fd3 | ||
|
|
c1d57c6b10 | ||
|
|
1049435f86 | ||
|
|
cee879d2f3 | ||
|
|
93ff2ef2e4 | ||
|
|
d389ac680f | ||
|
|
d582e63c25 | ||
|
|
cb9295658c | ||
|
|
dbc1ab7a57 | ||
|
|
bb9532f42e | ||
|
|
632f04c76b | ||
|
|
bc02eeac57 | ||
|
|
d6dc147497 | ||
|
|
a15e1ae0a7 | ||
|
|
8b98335e2e | ||
|
|
01e07dd2be | ||
|
|
3ac8d6e1d3 | ||
|
|
66143280fa | ||
|
|
e95442d8ec | ||
|
|
aafde53b81 | ||
|
|
0887480865 | ||
|
|
4ff8df9538 | ||
|
|
ddb63c1488 | ||
|
|
aab2dff49c | ||
|
|
d017b2ef39 | ||
|
|
70a967a3a7 | ||
|
|
796edae614 | ||
|
|
50bb7086ac | ||
|
|
af8cf9c6c7 | ||
|
|
6227b081cf | ||
|
|
42645f7236 | ||
|
|
eae8bbac82 | ||
|
|
43451c5342 | ||
|
|
a6f27ca19f | ||
|
|
a7462e86c8 | ||
|
|
0ddcfec70d | ||
|
|
bf70470b9a | ||
|
|
23c5bd65cf | ||
|
|
30aa05a243 | ||
|
|
4ce70e401d | ||
|
|
a2f49a544c | ||
|
|
4d4065c54b | ||
|
|
d072dd52cf | ||
|
|
25b9b37ac0 | ||
|
|
5ea5b55882 | ||
|
|
b69c00b01e | ||
|
|
aa53742a07 | ||
|
|
7c2a77081b | ||
|
|
57c0bceb63 | ||
|
|
8cb43788dc | ||
|
|
921ee9f8a1 | ||
|
|
058e16d1a8 | ||
|
|
a5f9beabdf | ||
|
|
0ed6ccf499 | ||
|
|
fe67abce83 | ||
|
|
7fba9adc43 | ||
|
|
4557bdfa6f | ||
|
|
7a7dbae313 | ||
|
|
12c5e9ea5d | ||
|
|
239a444d4c | ||
|
|
f770b66f42 | ||
|
|
6311d0bf4e | ||
|
|
491d6a5461 | ||
|
|
b142319da0 | ||
|
|
ac21fcb5cf | ||
|
|
455914fb52 | ||
|
|
2419c6ab34 | ||
|
|
8a0403ef6b | ||
|
|
e0afeea6c4 | ||
|
|
dd8b4f6416 | ||
|
|
97482c3372 | ||
|
|
d2e36fc1d2 | ||
|
|
99acd6d64f | ||
|
|
6fe6b8ba64 | ||
|
|
c2b947d2e6 | ||
|
|
7d6b25ff59 | ||
|
|
d9cef737e3 | ||
|
|
2f18e97a44 | ||
|
|
bf3c1629f7 | ||
|
|
1062adede4 | ||
|
|
47c9a434bb | ||
|
|
b2bfca7ec6 | ||
|
|
5d84f10110 | ||
|
|
847ce5db88 | ||
|
|
afdfbd6173 | ||
|
|
c0007d3c1a | ||
|
|
aa27aedca9 | ||
|
|
172c1d10a1 | ||
|
|
da6f7d671b | ||
|
|
7a13670594 | ||
|
|
6e10d641b2 | ||
|
|
c5dca69482 | ||
|
|
371a50176e | ||
|
|
35bff7c3e7 | ||
|
|
83f8435000 | ||
|
|
a1b4b1d8ca | ||
|
|
fad3e634d5 | ||
|
|
62712c976f | ||
|
|
56fed3ad87 | ||
|
|
9a65731be9 | ||
|
|
34b011f683 | ||
|
|
69c721b66e | ||
|
|
f2a578cd76 | ||
|
|
1e34d65675 | ||
|
|
60db0b0999 | ||
|
|
3bfb6dbc20 | ||
|
|
d4d9bb204d | ||
|
|
bedb841fa9 | ||
|
|
c4c4663144 | ||
|
|
b392db866c | ||
|
|
3556f9a42b | ||
|
|
0345ca9f18 | ||
|
|
eacc4b907d | ||
|
|
09cb5da3d3 | ||
|
|
b22791c15b | ||
|
|
df3eda411a | ||
|
|
5b10c053de | ||
|
|
bf2d75e55e | ||
|
|
6f7efe6922 | ||
|
|
90e321ddbd | ||
|
|
9649d71082 | ||
|
|
932337d83d | ||
|
|
7e4bde8d34 | ||
|
|
01e8b5f471 | ||
|
|
68a6da22be | ||
|
|
986f3b5bca | ||
|
|
4b1bb9d1ee | ||
|
|
ec340c0abe | ||
|
|
b062ec050c | ||
|
|
965f4c6227 | ||
|
|
bdc4022211 | ||
|
|
7edfe3607d | ||
|
|
e1731b87ec | ||
|
|
ebadc92f63 | ||
|
|
ea56ec7435 | ||
|
|
3b990fb6e1 | ||
|
|
96b4fbea4b | ||
|
|
9161e17476 | ||
|
|
190a2c47e9 | ||
|
|
d096706685 | ||
|
|
7521cb530e | ||
|
|
dde9b507ce | ||
|
|
183416a640 | ||
|
|
826e8518ea | ||
|
|
55587b12aa | ||
|
|
285a94e5fe | ||
|
|
16a05528b7 | ||
|
|
b4f4ef3c1b | ||
|
|
cd407ee467 | ||
|
|
9ee63144e5 | ||
|
|
0413d89a9e | ||
|
|
f33e54d8ba | ||
|
|
a2b19d46e1 | ||
|
|
4163b4dc25 | ||
|
|
12220d4322 | ||
|
|
14262d4c25 | ||
|
|
f3ec4a78c9 | ||
|
|
f7a0ae8b4a | ||
|
|
3c6d17c9a5 | ||
|
|
885ba0fdd2 | ||
|
|
f3b0e34b67 | ||
|
|
4109fab0d8 | ||
|
|
0688061f5c | ||
|
|
82c12b1565 | ||
|
|
ebc0fabbdb | ||
|
|
587b2e3075 | ||
|
|
ec82dd3da9 | ||
|
|
3e190b34f5 | ||
|
|
e059ad9172 | ||
|
|
1297324fa9 | ||
|
|
e2b7434d98 | ||
|
|
ada8df5755 | ||
|
|
843b90cbba | ||
|
|
6b263919d5 | ||
|
|
965c1e803f | ||
|
|
9aa2fc824a | ||
|
|
a13bc481b8 | ||
|
|
fc7379aabc | ||
|
|
531024b8b4 | ||
|
|
a17683c549 | ||
|
|
eeacad0fb9 | ||
|
|
c51140b59a | ||
|
|
f1817a0dbb | ||
|
|
5b05510bb9 | ||
|
|
b676476cd2 | ||
|
|
709f8ed05f | ||
|
|
31282416d8 | ||
|
|
385c84ae6f | ||
|
|
2d24020202 | ||
|
|
1a2aba3f56 | ||
|
|
f50f0192d1 | ||
|
|
12b8b4b955 | ||
|
|
c267366578 | ||
|
|
18e49cc1ce | ||
|
|
1ce4b1a994 | ||
|
|
f3c87e488a | ||
|
|
f24c698cd5 | ||
|
|
144a3b54bb | ||
|
|
ec7c7048db | ||
|
|
fd2e542c0b | ||
|
|
11e8e3696f | ||
|
|
d08f7af1e0 | ||
|
|
60dfaab22c | ||
|
|
75fa7cb7fd | ||
|
|
e47b1737a8 | ||
|
|
e1ad210bb0 | ||
|
|
ac3edbedf4 | ||
|
|
2dc48cf08d | ||
|
|
ede1ad0a4c | ||
|
|
3e8f76cd6d | ||
|
|
cd6df2be39 | ||
|
|
7091e972fc | ||
|
|
c8ae3c5ef6 | ||
|
|
54e8c4df8a | ||
|
|
e18c190905 | ||
|
|
181dc73d39 | ||
|
|
7ed2de9178 | ||
|
|
8c101fd0a4 | ||
|
|
43213ead05 | ||
|
|
0ef5c65c94 | ||
|
|
c610f95b2d | ||
|
|
c4484c758e | ||
|
|
ee615836ba | ||
|
|
fea7de42d5 | ||
|
|
4787303160 | ||
|
|
801d419f51 | ||
|
|
3579557200 | ||
|
|
202d785710 | ||
|
|
7ca72a39b1 | ||
|
|
f34e0f5f2b | ||
|
|
d98a31fa6b | ||
|
|
9a82dbb3e6 | ||
|
|
a76442641b | ||
|
|
2043fdf7e1 | ||
|
|
a06f7bea41 | ||
|
|
db34afe867 | ||
|
|
589ee7a5ea | ||
|
|
4ba26ee7b7 | ||
|
|
71223895ac | ||
|
|
928b90122f | ||
|
|
d601a88d82 | ||
|
|
443e826f61 | ||
|
|
2691221168 | ||
|
|
e62bb3dc6b | ||
|
|
604099429e | ||
|
|
11dc7f64ba | ||
|
|
ceea705a76 | ||
|
|
d9f7531e81 | ||
|
|
7bd7640c63 | ||
|
|
ca1636ff9e | ||
|
|
ea741d0169 | ||
|
|
c43e2e6956 | ||
|
|
03004452ac | ||
|
|
a470877017 | ||
|
|
777d322222 | ||
|
|
4cebb367de | ||
|
|
1f0ac1f1c1 | ||
|
|
1fad6e910c | ||
|
|
822fb7325a | ||
|
|
20e0eb1021 | ||
|
|
20becf951d | ||
|
|
5aa8557168 | ||
|
|
c66d248e96 | ||
|
|
0d8e7c852b | ||
|
|
991c6d6b5c | ||
|
|
2bc5d3d325 | ||
|
|
5ad8e7ead4 | ||
|
|
8832bbc57f | ||
|
|
86483ff947 | ||
|
|
92d7a7562f | ||
|
|
52fe3cf3c8 | ||
|
|
94fb6414fa | ||
|
|
d0270dbc6a | ||
|
|
11a047bf8e | ||
|
|
eb70c7e196 | ||
|
|
b497b8635b | ||
|
|
5e595ec5f8 | ||
|
|
49b86d07d3 | ||
|
|
11eed4cfe9 | ||
|
|
4aef0ad459 | ||
|
|
21cd74d0ca | ||
|
|
6c262f1df5 | ||
|
|
f32ace4e5a | ||
|
|
e54b7052e0 | ||
|
|
b40d448955 | ||
|
|
33bccd3bcb | ||
|
|
705e4f4098 | ||
|
|
1642833fdb | ||
|
|
492bb98e0e | ||
|
|
a8456f90db | ||
|
|
103b75172d | ||
|
|
0baa3a0eac | ||
|
|
f26e4b5381 | ||
|
|
60ef87b269 | ||
|
|
3d4de4dee5 | ||
|
|
c621435a28 | ||
|
|
7408483a43 | ||
|
|
7e265f7bde | ||
|
|
4d15535381 | ||
|
|
787c2f90f2 | ||
|
|
e590a2149d | ||
|
|
8c77740aa7 | ||
|
|
29582b57f7 | ||
|
|
2763f333d4 | ||
|
|
8840628d34 | ||
|
|
6fb28d7ded | ||
|
|
be810aa568 | ||
|
|
8a698bd71e | ||
|
|
baa0594501 | ||
|
|
e82b8c80f0 | ||
|
|
f8e54be9a6 | ||
|
|
d3137be984 | ||
|
|
824cfa27be | ||
|
|
66cb6d5e7d | ||
|
|
8f432aa0a9 | ||
|
|
4aa4137abe | ||
|
|
f4bb4e1b6a | ||
|
|
7af4e166a4 | ||
|
|
1fa488d870 | ||
|
|
37a3a51b6b | ||
|
|
6a6e8f906f | ||
|
|
55bc498f9d | ||
|
|
4ee784c68f | ||
|
|
fc757c087a | ||
|
|
884dd939b7 | ||
|
|
6fd2f556db | ||
|
|
4e088a40d9 | ||
|
|
8ba66af878 | ||
|
|
441f51ed79 | ||
|
|
9ee891dc66 | ||
|
|
87ffcbf23e | ||
|
|
adfc54200f | ||
|
|
3c36b43449 | ||
|
|
9be1dcff6c | ||
|
|
37dff62fa9 | ||
|
|
4fd462b1c8 | ||
|
|
33ac1923ff | ||
|
|
0b87ae5eac | ||
|
|
678743cc10 | ||
|
|
c8345ce093 | ||
|
|
f3af43a9ce | ||
|
|
1df2ccb1c6 | ||
|
|
3add4472ef | ||
|
|
4613f63c66 | ||
|
|
612295fb9d | ||
|
|
64405ade52 | ||
|
|
ce5f1b25f5 | ||
|
|
ae4f50e7b3 | ||
|
|
c9120be347 | ||
|
|
b189e67b4c | ||
|
|
5d5c275c79 | ||
|
|
52f31a7a8e | ||
|
|
6697aecd48 | ||
|
|
348c075a14 | ||
|
|
bf2420702c | ||
|
|
16832ac67a | ||
|
|
47bd2ff03d | ||
|
|
850f1c1469 | ||
|
|
622a90c7d5 | ||
|
|
4c317f11ae | ||
|
|
01bce5cfa6 | ||
|
|
2158925d3c | ||
|
|
2aff6403a2 | ||
|
|
3c4d600187 | ||
|
|
f60ccb9b90 | ||
|
|
2a6108087c | ||
|
|
0da86a82ae | ||
|
|
643b0499c4 | ||
|
|
676bac390e | ||
|
|
79740accfa | ||
|
|
77c6f1cb9f | ||
|
|
538361d5fd | ||
|
|
b17593ba3c | ||
|
|
eb00690b30 | ||
|
|
a772e65d32 | ||
|
|
66f7f69ec7 | ||
|
|
ad52711fe1 | ||
|
|
d6fdb4ee34 | ||
|
|
4977aa2ad1 | ||
|
|
74c7268d2f | ||
|
|
42fc419759 | ||
|
|
4fb3b9cddc | ||
|
|
c60077174e | ||
|
|
5e893dd2ad | ||
|
|
9eb54da2dc | ||
|
|
bb6ff866c7 | ||
|
|
2d719c5b37 | ||
|
|
9d54b264ad | ||
|
|
65b282a056 | ||
|
|
fc174c8988 | ||
|
|
06802896ef | ||
|
|
7f13ac9e5e | ||
|
|
4a1374d22d | ||
|
|
4ee8d647b7 | ||
|
|
59793f3c01 | ||
|
|
f7f383d8f3 | ||
|
|
562a3959b6 | ||
|
|
bb1275f4f9 | ||
|
|
7fde6b9331 | ||
|
|
3e97a4005a | ||
|
|
c271760230 | ||
|
|
f7c1845f0c | ||
|
|
9b04f20ed3 | ||
|
|
62b6b6293b | ||
|
|
6d8a1c9398 | ||
|
|
303039735f | ||
|
|
6bcf5c6881 | ||
|
|
0527f45f5a | ||
|
|
ba397bbb0c | ||
|
|
a617d58902 | ||
|
|
7fc4a229ae | ||
|
|
f53d31aa2e | ||
|
|
b889b6a6b0 | ||
|
|
f9b55a06b8 | ||
|
|
09d772a5e5 | ||
|
|
f7035eb228 | ||
|
|
1bf09ddd38 | ||
|
|
a8bf27da55 | ||
|
|
ee8bb5ef75 | ||
|
|
bcfd9cab1d | ||
|
|
2a5fd7f3a9 | ||
|
|
f8c37772d4 | ||
|
|
d988dbe69d | ||
|
|
bd7499a505 | ||
|
|
5cb9b9b237 | ||
|
|
819d391495 | ||
|
|
1f0ed629a7 | ||
|
|
91044d0a75 | ||
|
|
57736185d0 | ||
|
|
8992980689 | ||
|
|
f341ff0167 | ||
|
|
abfa841ed7 | ||
|
|
e68adf53bc | ||
|
|
562d175de1 | ||
|
|
b5cef354ad | ||
|
|
dd6a473008 | ||
|
|
09a887aeb7 | ||
|
|
53c903fa48 | ||
|
|
548454c90d | ||
|
|
94bab5f83b | ||
|
|
78965c1ac4 | ||
|
|
00b0fcaeb3 | ||
|
|
f7905c8e94 | ||
|
|
7ab7b612f6 | ||
|
|
ce1d2803ce | ||
|
|
9b066e4eac | ||
|
|
e1f9d106f0 | ||
|
|
e40a539406 | ||
|
|
bb73c30bb7 | ||
|
|
2e16f05a70 | ||
|
|
1837c3443d | ||
|
|
bd1060ff28 | ||
|
|
c9968a9662 | ||
|
|
e3001e8bdd | ||
|
|
82bb2b4567 | ||
|
|
f483002e39 | ||
|
|
c2a87a0c88 | ||
|
|
733886c70b | ||
|
|
899fdca995 | ||
|
|
4731ee034e | ||
|
|
e6faf9efd1 | ||
|
|
d75d1fce43 | ||
|
|
ef3980a3ee | ||
|
|
2a1c170aa4 | ||
|
|
d65e769dd7 | ||
|
|
2bb5a85bd6 | ||
|
|
98aee9ca62 | ||
|
|
c86f965d36 | ||
|
|
ef1143bb70 | ||
|
|
81e445e386 | ||
|
|
2cbbbc4419 | ||
|
|
632f43016e | ||
|
|
fe62ad2ea2 | ||
|
|
f416309863 | ||
|
|
dcf5e7a15c | ||
|
|
af4f70e3a7 | ||
|
|
79dde23ec6 | ||
|
|
e4d0341e67 | ||
|
|
907b182931 | ||
|
|
1a26cd717f | ||
|
|
7bfacb095b | ||
|
|
6315edfc21 | ||
|
|
464f48d717 | ||
|
|
eacfaf3403 | ||
|
|
36d8028045 | ||
|
|
297c1d7abb | ||
|
|
5a73c85e6e | ||
|
|
68138bc009 | ||
|
|
8c7df3212a | ||
|
|
5ebad53072 | ||
|
|
640824ae31 | ||
|
|
6acf93c978 | ||
|
|
6897e06dcd | ||
|
|
d036af8d1a | ||
|
|
b77c62e0db | ||
|
|
bbf46bb0ec | ||
|
|
6aa4337b27 | ||
|
|
99d7a4e4b4 | ||
|
|
b7da2cbd97 | ||
|
|
b4ae721998 | ||
|
|
3bb4126e26 | ||
|
|
de439e7695 | ||
|
|
e5ec72df5c | ||
|
|
98a89156bf | ||
|
|
dc65475dbb | ||
|
|
bab637667d | ||
|
|
cc64ff5f10 | ||
|
|
ab87174e5b | ||
|
|
a6fdc42934 | ||
|
|
4c16b85e85 | ||
|
|
9e3d6c6a08 | ||
|
|
d567872813 | ||
|
|
7069d3f600 | ||
|
|
b2f8b7c711 | ||
|
|
4092ea307e | ||
|
|
01f64ef9f9 | ||
|
|
f1a48b182e | ||
|
|
8ac5467856 | ||
|
|
758f84f573 | ||
|
|
2073fefc92 | ||
|
|
5b98d8d9c2 | ||
|
|
8e59e72983 | ||
|
|
b56d68dac7 | ||
|
|
e0c3a92b60 | ||
|
|
213562fcf1 | ||
|
|
d3a09b93c0 | ||
|
|
536ea57369 | ||
|
|
ac1dd4cbab | ||
|
|
bc33e05906 | ||
|
|
8ecc407cb0 | ||
|
|
2672dff512 | ||
|
|
74d907bbce | ||
|
|
53aacabce7 | ||
|
|
ab9cdd8f5b | ||
|
|
b3d439ed11 | ||
|
|
d57657c209 | ||
|
|
dd080c5933 | ||
|
|
0be98d7989 | ||
|
|
fca54dbbe3 | ||
|
|
7ec5fe6a85 | ||
|
|
9ea5505214 | ||
|
|
75d3b566a7 | ||
|
|
e38059f52c | ||
|
|
72331aa945 | ||
|
|
e497c54f82 | ||
|
|
b44091ff3a | ||
|
|
2ab889f889 | ||
|
|
23541e661e | ||
|
|
6778e37652 | ||
|
|
5eac31283d | ||
|
|
38016773d4 | ||
|
|
ad80eb267f | ||
|
|
449e0832e0 | ||
|
|
f28f5c9a01 | ||
|
|
9dd28d8879 | ||
|
|
b47eec99a5 | ||
|
|
99bb55efa0 | ||
|
|
4408eb618a | ||
|
|
9ccd1b1b27 | ||
|
|
0c1657fef5 | ||
|
|
ee393c6485 | ||
|
|
7f68b9d846 | ||
|
|
2035a3344e | ||
|
|
ade36582a0 | ||
|
|
a4b8be61e3 | ||
|
|
b7feb62ecd | ||
|
|
7e48f7c8eb | ||
|
|
501f8111fe | ||
|
|
d8f4503d98 | ||
|
|
0d83978c58 | ||
|
|
69e56be459 | ||
|
|
35a721039d | ||
|
|
98b4ac5029 | ||
|
|
fe874c946d | ||
|
|
53386e9bf4 | ||
|
|
5435055f5c | ||
|
|
583e10f5c6 | ||
|
|
5393d709a3 | ||
|
|
fc1c9392aa | ||
|
|
6b2c48d4f6 | ||
|
|
400ae3cf4b | ||
|
|
f22a322104 | ||
|
|
e98ff952bf | ||
|
|
573e1b553c | ||
|
|
a674d0d696 | ||
|
|
5393161c16 | ||
|
|
1bdc6d8f7f | ||
|
|
e9081a176f | ||
|
|
3e7db2887f | ||
|
|
fcf14ac222 | ||
|
|
55324653a5 | ||
|
|
a132f09b03 | ||
|
|
48eac84930 | ||
|
|
948619a125 | ||
|
|
0cd0741f18 | ||
|
|
01a3455ecb | ||
|
|
610f7db1cb | ||
|
|
373ef6d1eb | ||
|
|
f1b1cee2fd | ||
|
|
a73e4f23ff | ||
|
|
9a5d3498c1 | ||
|
|
0b24d635ad | ||
|
|
b623e19dae | ||
|
|
7389a8b344 | ||
|
|
d68f477e8e | ||
|
|
dbe273bb56 | ||
|
|
1a4377da29 | ||
|
|
c3cdecaa60 | ||
|
|
9d706056c6 | ||
|
|
cb0100f02a | ||
|
|
9c6dd0989a | ||
|
|
a23a179bbf | ||
|
|
365b7c4600 | ||
|
|
ed2455f460 | ||
|
|
046033627a | ||
|
|
786444a6b9 | ||
|
|
9ab26cfb9d | ||
|
|
aa1e3ea1bc | ||
|
|
c66875449b | ||
|
|
f6c4024ae5 | ||
|
|
2c8cc793ab | ||
|
|
40a4546ac6 | ||
|
|
66454d2e61 | ||
|
|
e7b13cf2d9 | ||
|
|
04cd520719 | ||
|
|
838af0478e | ||
|
|
9064e96b90 | ||
|
|
8e91268979 | ||
|
|
cc637d56e1 | ||
|
|
9846ebd65d | ||
|
|
b568e2efc7 | ||
|
|
20fc74219a | ||
|
|
92a4bfb38e | ||
|
|
5c34b0daa5 | ||
|
|
f4ea674d60 | ||
|
|
21f43dc395 | ||
|
|
5082ce4280 | ||
|
|
ed061fb3b1 | ||
|
|
247e96f5db | ||
|
|
ce60eac583 | ||
|
|
c34fcdf7b7 | ||
|
|
dcfada0b52 | ||
|
|
fb3fd439bb | ||
|
|
6226672d27 | ||
|
|
bf72794a4c | ||
|
|
30a00cb092 | ||
|
|
0bfb6895ad | ||
|
|
29345c823e | ||
|
|
e71cb4f2ff | ||
|
|
108a1c7181 | ||
|
|
5ce07afed8 | ||
|
|
d9c4798d4e | ||
|
|
6ecd849499 | ||
|
|
e5b0b31da6 | ||
|
|
1371cb4ff6 | ||
|
|
c788d339fe | ||
|
|
35580fa62b | ||
|
|
b61ae74d3d | ||
|
|
fead4350ce | ||
|
|
04a651c40d | ||
|
|
f394e7f39b | ||
|
|
8f7827d3d9 | ||
|
|
06b54bd824 | ||
|
|
f473e40bfc | ||
|
|
1eb5cf1d22 | ||
|
|
b540d70b2d | ||
|
|
7b5a8aef73 | ||
|
|
3e4daf6947 | ||
|
|
0918cbf221 | ||
|
|
3e078e41ff | ||
|
|
a80ab94479 | ||
|
|
e6f0ab90dc | ||
|
|
53f4739c8f | ||
|
|
c6e33ba3ac | ||
|
|
0e2528e542 | ||
|
|
6ecc10a35c | ||
|
|
59bd2bb251 | ||
|
|
9fa83cdd5a | ||
|
|
f383f3f759 | ||
|
|
c044bc52f7 | ||
|
|
0abcc9e06e | ||
|
|
4a594b32ef | ||
|
|
8b9f760cb2 | ||
|
|
1d1cf76b5e | ||
|
|
194c14b99a | ||
|
|
fa8c6839dd | ||
|
|
f8e4ce6b4c | ||
|
|
cce496016d | ||
|
|
2c4d5dc304 | ||
|
|
1c981130b6 | ||
|
|
1e44b81e87 | ||
|
|
85b21a02e8 | ||
|
|
4313fb6f58 | ||
|
|
ee19fd17fa | ||
|
|
a7c6f9835a | ||
|
|
06b1babed9 | ||
|
|
73ea91d4c9 | ||
|
|
14839f0c0f | ||
|
|
db8f4e141d | ||
|
|
09fa406f84 | ||
|
|
50d22ba357 | ||
|
|
c6f9d193be | ||
|
|
5e1aa47c05 | ||
|
|
21dd8cee37 | ||
|
|
ece82996c2 | ||
|
|
fa520c95ea | ||
|
|
a6685141a4 | ||
|
|
78ab0ad923 | ||
|
|
4fb67a4c8c | ||
|
|
dd94e60d16 | ||
|
|
aa70e17657 | ||
|
|
016cd3fb71 | ||
|
|
17f28ba0aa | ||
|
|
ab88a879e9 | ||
|
|
5b85f3c8dd | ||
|
|
16a5100f35 | ||
|
|
86b2c5d5b5 | ||
|
|
e0c3198ee6 | ||
|
|
12bdd847b5 | ||
|
|
9860816ab7 | ||
|
|
e17283726a | ||
|
|
eff61ae5fc |
@@ -1,9 +1,3 @@
|
||||
|
||||
GITHUB ISSUES ARE STRICTLY CONTROLLED FOR THIS PROJECT.
|
||||
|
||||
Refer to http://ebean-orm.github.io/support for the policies controlling the use of github issues.
|
||||
Please post issues to the Ebean group https://groups.google.com/forum/#!forum/ebean first.
|
||||
|
||||
## Expected behavior
|
||||
|
||||
## Actual behavior
|
||||
|
||||
+1
-4
@@ -1,6 +1,4 @@
|
||||
*.autofetch
|
||||
*create-all.sql
|
||||
*drop-all.sql
|
||||
*.orig
|
||||
.classpath
|
||||
.project
|
||||
@@ -12,7 +10,6 @@ ebean-autotune.xml
|
||||
ebean-profiling*.xml
|
||||
/db
|
||||
/mydb.db
|
||||
!src/test/ddl-review/*.sql
|
||||
profiling/
|
||||
|
||||
# Intellij project files
|
||||
@@ -20,4 +17,4 @@ profiling/
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
*uuid.state
|
||||
*uuid.state
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ env:
|
||||
install: true
|
||||
|
||||
script:
|
||||
- mvn clean test
|
||||
- mvn -T 1C clean test
|
||||
|
||||
after_failure:
|
||||
- ./.travis/print_surefire_reports
|
||||
|
||||
+1
-1
@@ -293,6 +293,6 @@ ebean.tenant.schemaProvider
|
||||
ebean.updateAllPropertiesInBatch
|
||||
ebean.updateChangesOnly
|
||||
ebean.updatesDeleteMissingChildren
|
||||
ebean.useJavaxValidationNotNull
|
||||
ebean.useValidationNotNull
|
||||
ebean.useJtaTransactionManager
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ Post questions or issues to the Ebean google group - https://groups.google.com/f
|
||||
Goto [https://ebean.io/docs/](https://ebean.io/docs/)
|
||||
|
||||
|
||||
## Maven cental links:
|
||||
## Maven central links:
|
||||
[Maven central - ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.ebean%22%20AND%20a%3A%22ebean%22 "maven central ebean")
|
||||
|
||||
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
|
||||
|
||||
+27
-37
@@ -4,16 +4,13 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
<version>12.12.1</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean api</name>
|
||||
<description>ebean api</description>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
|
||||
<properties>
|
||||
<jackson-core.version>2.11.3</jackson-core.version>
|
||||
<jackson-databind.version>2.11.3</jackson-databind.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!--
|
||||
@@ -23,14 +20,14 @@
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.25</version>
|
||||
<version>1.7.30</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>avaje-config</artifactId>
|
||||
<version>1.1</version>
|
||||
<version>1.5</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
@@ -40,45 +37,39 @@
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>avaje-jsr305</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>2.2.4</version>
|
||||
<version>2.2.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>6.13</version>
|
||||
<version>7.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-types</artifactId>
|
||||
<version>2.1</version>
|
||||
<version>2.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-datasource</artifactId>
|
||||
<version>6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>12.1.4</version>
|
||||
<artifactId>ebean-datasource-api</artifactId>
|
||||
<version>${ebean-datasource.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson-core.version}</version>
|
||||
<version>${jackson.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
@@ -86,7 +77,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson-databind.version}</version>
|
||||
<version>${jackson.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
@@ -106,14 +97,6 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope to read validation annotations Size etc -->
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>1.1.0.Final</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
@@ -121,21 +104,28 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<groupId>io.repaint.maven</groupId>
|
||||
<artifactId>tiles-maven-plugin</artifactId>
|
||||
<version>2.24</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
<tiles>
|
||||
<tile>io.avaje.tile:moditech-module:1.0</tile>
|
||||
</tiles>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -1,33 +1,43 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Background thread pool service for executing of tasks asynchronously.
|
||||
* Background executor service for executing of tasks asynchronously.
|
||||
* <p>
|
||||
* This service is used internally by Ebean for executing background tasks such
|
||||
* as the {@link Query#findFutureList()} and also for executing background tasks
|
||||
* periodically.
|
||||
* </p>
|
||||
* This service can be used to execute tasks in the background.
|
||||
* <p>
|
||||
* This service has been made available so you can use it for your application
|
||||
* code if you want. It can be useful for some server caching implementations
|
||||
* (background population and trimming of the cache etc).
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
* This service is managed by Ebean and will perform a clean shutdown
|
||||
* waiting for background tasks to complete with a default 30 second
|
||||
* timeout. Shutdown occurs prior to DataSource shutdown.
|
||||
* <p>
|
||||
* This also propagates MDC context from the current thread to the
|
||||
* background task if defined.
|
||||
*/
|
||||
public interface BackgroundExecutor {
|
||||
|
||||
/**
|
||||
* Execute a task in the background.
|
||||
* Execute a callable task in the background returning the Future.
|
||||
*/
|
||||
void execute(Runnable r);
|
||||
<T> Future<T> submit(Callable<T> task);
|
||||
|
||||
/**
|
||||
* Execute a runnable task in the background returning the Future.
|
||||
*/
|
||||
Future<?> submit(Runnable task);
|
||||
|
||||
/**
|
||||
* Execute a task in the background. Effectively the same as
|
||||
* {@link BackgroundExecutor#submit(Runnable)} but returns void.
|
||||
*/
|
||||
void execute(Runnable task);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to scheduleWithFixedDelay().
|
||||
* Execute a task periodically with a fixed delay between each execution.
|
||||
* <p>
|
||||
* For example, execute a runnable every minute.
|
||||
@@ -36,27 +46,64 @@ public interface BackgroundExecutor {
|
||||
* That is, this method has the same behaviour characteristics as
|
||||
* {@link ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)}
|
||||
*/
|
||||
void executePeriodically(Runnable r, long delay, TimeUnit unit);
|
||||
@Deprecated
|
||||
void executePeriodically(Runnable task, long delay, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to scheduleWithFixedDelay().
|
||||
* Execute a task periodically additionally with an initial delay different from delay.
|
||||
*/
|
||||
void executePeriodically(Runnable r, long initialDelay, long delay, TimeUnit unit);
|
||||
@Deprecated
|
||||
void executePeriodically(Runnable task, long initialDelay, long delay, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Execute a task periodically with a given delay.
|
||||
*
|
||||
* @param task the task to execute
|
||||
* @param initialDelay the time to delay first execution
|
||||
* @param delay the delay between the termination of one
|
||||
* execution and the commencement of the next
|
||||
* @param unit the time unit of the initialDelay and delay parameters
|
||||
* @return a ScheduledFuture representing pending completion of
|
||||
* the series of repeated tasks. The future's {@link
|
||||
* Future#get() get()} method will never return normally,
|
||||
* and will throw an exception upon task cancellation or
|
||||
* abnormal termination of a task execution.
|
||||
*/
|
||||
ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Execute a task periodically with a given period.
|
||||
*
|
||||
* <p>If any execution of this task takes longer than its period, then
|
||||
* subsequent executions may start late, but will not concurrently
|
||||
* execute.
|
||||
*
|
||||
* @param task the task to execute
|
||||
* @param initialDelay the time to delay first execution
|
||||
* @param period the period between successive executions
|
||||
* @param unit the time unit of the initialDelay and period parameters
|
||||
* @return a ScheduledFuture representing pending completion of
|
||||
* the series of repeated tasks. The future's {@link
|
||||
* Future#get() get()} method will never return normally,
|
||||
* and will throw an exception upon task cancellation or
|
||||
* abnormal termination of a task execution.
|
||||
*/
|
||||
ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Schedules a Runnable for one-shot action that becomes enabled after the given delay.
|
||||
*
|
||||
* @return a ScheduledFuture representing pending completion of the task and
|
||||
* whose get() method will return null upon completion
|
||||
* whose get() method will return null upon completion
|
||||
*/
|
||||
ScheduledFuture<?> schedule(Runnable r, long delay, TimeUnit unit);
|
||||
ScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Schedules a Callable for one-shot action that becomes enabled after the given delay.
|
||||
*
|
||||
* @return a ScheduledFuture that can be used to extract result or cancel
|
||||
*/
|
||||
<V> ScheduledFuture<V> schedule(Callable<V> c, long delay, TimeUnit unit);
|
||||
|
||||
<V> ScheduledFuture<V> schedule(Callable<V> task, long delay, TimeUnit unit);
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.Optional;
|
||||
*
|
||||
* public class CustomerFinder extends BeanFinder<Long,Customer> {
|
||||
*
|
||||
* @Inject
|
||||
* @Inject
|
||||
* public CustomerFinder(Database database) {
|
||||
* super(Customer.class, database);
|
||||
* }
|
||||
@@ -79,11 +79,11 @@ public abstract class BeanFinder<I,T> {
|
||||
/**
|
||||
* Creates an entity reference for this ID.
|
||||
* <p>
|
||||
* Equivalent to {@link Database#getReference(Class, Object)}
|
||||
* Equivalent to {@link Database#reference(Class, Object)}
|
||||
*/
|
||||
@Nonnull
|
||||
public T ref(I id) {
|
||||
return db().getReference(type, id);
|
||||
return db().reference(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,10 +9,10 @@ import java.util.Collection;
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Repository
|
||||
* @Repository
|
||||
* public class CustomerRepository extends BeanRepository<Long,Customer> {
|
||||
*
|
||||
* @Inject
|
||||
* @Inject
|
||||
* public CustomerRepository(Database server) {
|
||||
* super(Customer.class, server);
|
||||
* }
|
||||
|
||||
@@ -57,7 +57,7 @@ public interface BeanState {
|
||||
*
|
||||
* // set loaded state on the email property to false so that
|
||||
* // the email property is not included in a stateless update
|
||||
* DB.getBeanState(user).setPropertyLoaded("email", false);
|
||||
* DB.beanState(user).setPropertyLoaded("email", false);
|
||||
*
|
||||
* user.update();
|
||||
*
|
||||
@@ -72,25 +72,47 @@ public interface BeanState {
|
||||
* bean.
|
||||
* <p>
|
||||
* Accessing another property will cause lazy loading to occur.
|
||||
* </p>
|
||||
*/
|
||||
Set<String> getLoadedProps();
|
||||
Set<String> loadedProps();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to loadedProps().
|
||||
*/
|
||||
@Deprecated
|
||||
default Set<String> getLoadedProps() {
|
||||
return loadedProps();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of changed properties.
|
||||
*/
|
||||
Set<String> getChangedProps();
|
||||
Set<String> changedProps();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to changedProps().
|
||||
*/
|
||||
@Deprecated
|
||||
default Set<String> getChangedProps() {
|
||||
return changedProps();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of the updated properties and their new and old values.
|
||||
*/
|
||||
Map<String, ValuePair> getDirtyValues();
|
||||
Map<String, ValuePair> dirtyValues();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to dirtyValues().
|
||||
*/
|
||||
@Deprecated
|
||||
default Map<String, ValuePair> getDirtyValues() {
|
||||
return dirtyValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the bean is readOnly.
|
||||
* <p>
|
||||
* If a setter is called on a readOnly bean it will throw an exception.
|
||||
* </p>
|
||||
*/
|
||||
boolean isReadOnly();
|
||||
|
||||
@@ -114,8 +136,29 @@ public interface BeanState {
|
||||
void resetForInsert();
|
||||
|
||||
/**
|
||||
* Returns a map with load erros.
|
||||
* Returns a map with load errors.
|
||||
*/
|
||||
@Nullable
|
||||
Map<String, Exception> getLoadErrors();
|
||||
Map<String, Exception> loadErrors();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to loadErrors().
|
||||
*/
|
||||
@Deprecated
|
||||
default Map<String, Exception> getLoadErrors() {
|
||||
return loadErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sort order value for an order column.
|
||||
*/
|
||||
int sortOrder();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to sortOrder().
|
||||
*/
|
||||
@Deprecated
|
||||
default int getSortOrder() {
|
||||
return sortOrder();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Defines a cancelable query.
|
||||
* <p>
|
||||
* Typically holds a representation of the PreparedStatement to perform the
|
||||
* actual cancel.
|
||||
* </p>
|
||||
*/
|
||||
public interface CancelableQuery {
|
||||
|
||||
/**
|
||||
* Cancel the query.
|
||||
* <p>
|
||||
* For JDBC this translates to calling cancel on the PreparedStatement.
|
||||
* </p>
|
||||
*/
|
||||
void cancel();
|
||||
}
|
||||
@@ -70,6 +70,13 @@ public final class DB {
|
||||
private DB() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Backdoor for registering a mock implementation of Database as the default database.
|
||||
*/
|
||||
protected static Database mock(String name, Database server, boolean defaultServer) {
|
||||
return context.mock(name, server, defaultServer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default database.
|
||||
*/
|
||||
@@ -119,8 +126,16 @@ public final class DB {
|
||||
* an expression that uses OR like Expression e = Expr.or(..., ...);
|
||||
* </p>
|
||||
*/
|
||||
public static ExpressionFactory expressionFactory() {
|
||||
return getDefault().expressionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated migrate to expressionFactory().
|
||||
*/
|
||||
@Deprecated
|
||||
public static ExpressionFactory getExpressionFactory() {
|
||||
return getDefault().getExpressionFactory();
|
||||
return expressionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -643,8 +658,16 @@ public final class DB {
|
||||
* @param beanType the type of entity bean
|
||||
* @param id the id value
|
||||
*/
|
||||
public static <T> T reference(Class<T> beanType, Object id) {
|
||||
return getDefault().reference(beanType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated migrate to beanId().
|
||||
*/
|
||||
@Deprecated
|
||||
public static <T> T getReference(Class<T> beanType, Object id) {
|
||||
return getDefault().getReference(beanType, id);
|
||||
return reference(beanType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -653,14 +676,12 @@ public final class DB {
|
||||
* <ul>
|
||||
* <li>asc - ascending order (which is the default)</li>
|
||||
* <li>desc - Descending order</li>
|
||||
* <li>nullsHigh - Treat null values as high/large values (which is the
|
||||
* default)</li>
|
||||
* <li>nullsHigh - Treat null values as high/large values (which is the default)</li>
|
||||
* <li>nullsLow- Treat null values as low/very small values</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* If you leave off any keywords the defaults are ascending order and treating
|
||||
* nulls as high values.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that the sorting uses a Comparator and Collections.sort(); and does
|
||||
* not invoke a DB query.
|
||||
@@ -1224,30 +1245,77 @@ public final class DB {
|
||||
* This will return null if the bean is not an enhanced entity bean.
|
||||
* </p>
|
||||
*/
|
||||
public static BeanState beanState(Object bean) {
|
||||
return getDefault().beanState(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated migrate to beanState().
|
||||
*/
|
||||
@Deprecated
|
||||
public static BeanState getBeanState(Object bean) {
|
||||
return getDefault().getBeanState(bean);
|
||||
return beanState(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of the Id property for a given bean.
|
||||
*/
|
||||
public static Object beanId(Object bean) {
|
||||
return getDefault().beanId(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated migrate to beanId().
|
||||
*/
|
||||
@Deprecated
|
||||
public static Object getBeanId(Object bean) {
|
||||
return getDefault().getBeanId(bean);
|
||||
return beanId(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and lock the bean using {@code select for update}.
|
||||
* <p>
|
||||
* This should be executed inside a transaction.
|
||||
* <p>
|
||||
* The bean needs to have an ID property set and can be a reference bean (only has ID)
|
||||
* or partially or fully populated bean. This will load all the properties of the bean
|
||||
* from the database using {@code select for update}.
|
||||
*
|
||||
* @param bean The entity bean that we wish to obtain a database lock on.
|
||||
*/
|
||||
public static void lock(Object bean) {
|
||||
getDefault().lock(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated migrate to cacheManager().
|
||||
*/
|
||||
@Deprecated
|
||||
public static ServerCacheManager getServerCacheManager() {
|
||||
return getDefault().cacheManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the manager of the level 2 cache ("L2" cache).
|
||||
*/
|
||||
public static ServerCacheManager getServerCacheManager() {
|
||||
return getDefault().getServerCacheManager();
|
||||
public static ServerCacheManager cacheManager() {
|
||||
return getDefault().cacheManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BackgroundExecutor service for asynchronous processing of
|
||||
* queries.
|
||||
*/
|
||||
public static BackgroundExecutor backgroundExecutor() {
|
||||
return getDefault().backgroundExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated migrate to backgroundExecutor().
|
||||
*/
|
||||
@Deprecated
|
||||
public static BackgroundExecutor getBackgroundExecutor() {
|
||||
return getDefault().getBackgroundExecutor();
|
||||
return backgroundExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,7 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -119,24 +120,82 @@ public interface Database {
|
||||
/**
|
||||
* Return AutoTune which is used to control the AutoTune service at runtime.
|
||||
*/
|
||||
AutoTune getAutoTune();
|
||||
AutoTune autoTune();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to autoTune().
|
||||
*/
|
||||
@Deprecated
|
||||
default AutoTune getAutoTune() {
|
||||
return autoTune();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated DataSource for this Database instance.
|
||||
*/
|
||||
DataSource dataSource();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to dataSource().
|
||||
*/
|
||||
@Deprecated
|
||||
default DataSource getDataSource() {
|
||||
return dataSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated read only DataSource for this Database instance (can be null).
|
||||
*/
|
||||
DataSource readOnlyDataSource();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to readOnlyDataSource().
|
||||
*/
|
||||
@Deprecated
|
||||
default DataSource getReadOnlyDataSource() {
|
||||
return readOnlyDataSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name. This is used with {@link DB#byName(String)} to get a
|
||||
* Database that was registered with the DB singleton.
|
||||
*/
|
||||
String getName();
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to name().
|
||||
*/
|
||||
@Deprecated
|
||||
default String getName() {
|
||||
return name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ExpressionFactory for this database.
|
||||
*/
|
||||
ExpressionFactory getExpressionFactory();
|
||||
ExpressionFactory expressionFactory();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to expressionFactory().
|
||||
*/
|
||||
@Deprecated
|
||||
default ExpressionFactory getExpressionFactory() {
|
||||
return expressionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MetaInfoManager which is used to get meta data from the Database
|
||||
* such as query execution statistics.
|
||||
*/
|
||||
MetaInfoManager getMetaInfoManager();
|
||||
MetaInfoManager metaInfo();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to metaInfo().
|
||||
*/
|
||||
@Deprecated
|
||||
default MetaInfoManager getMetaInfoManager() {
|
||||
return metaInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the platform used for this database instance.
|
||||
@@ -155,12 +214,28 @@ public interface Database {
|
||||
*
|
||||
* @return platform for this database instance
|
||||
*/
|
||||
Platform getPlatform();
|
||||
Platform platform();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to platform().
|
||||
*/
|
||||
@Deprecated
|
||||
default Platform getPlatform() {
|
||||
return platform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the extended API intended for use by plugins.
|
||||
*/
|
||||
SpiServer getPluginApi();
|
||||
SpiServer pluginApi();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to pluginApi().
|
||||
*/
|
||||
@Deprecated
|
||||
default SpiServer getPluginApi() {
|
||||
return pluginApi();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanState for a given entity bean.
|
||||
@@ -168,12 +243,28 @@ public interface Database {
|
||||
* This will return null if the bean is not an enhanced entity bean.
|
||||
* </p>
|
||||
*/
|
||||
BeanState getBeanState(Object bean);
|
||||
BeanState beanState(Object bean);
|
||||
|
||||
/**
|
||||
* Deprecated migrate to beanState().
|
||||
*/
|
||||
@Deprecated
|
||||
default BeanState getBeanState(Object bean) {
|
||||
return beanState(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of the Id property for a given bean.
|
||||
*/
|
||||
Object getBeanId(Object bean);
|
||||
Object beanId(Object bean);
|
||||
|
||||
/**
|
||||
* Deprecated migrate to beanId().
|
||||
*/
|
||||
@Deprecated
|
||||
default Object getBeanId(Object bean) {
|
||||
return beanId(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Id value onto the bean converting the type of the id value if necessary.
|
||||
@@ -185,7 +276,15 @@ public interface Database {
|
||||
* @param bean The entity bean to set the id value on.
|
||||
* @param id The id value to set.
|
||||
*/
|
||||
Object setBeanId(Object bean, Object id);
|
||||
Object beanId(Object bean, Object id);
|
||||
|
||||
/**
|
||||
* Deprecated migrate to beanId().
|
||||
*/
|
||||
@Deprecated
|
||||
default Object setBeanId(Object bean, Object id) {
|
||||
return beanId(bean, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of the differences between two objects of the same type.
|
||||
@@ -851,7 +950,15 @@ public interface Database {
|
||||
* @param id the id value
|
||||
*/
|
||||
@Nonnull
|
||||
<T> T getReference(Class<T> beanType, Object id);
|
||||
<T> T reference(Class<T> beanType, Object id);
|
||||
|
||||
/**
|
||||
* Deprecated migrate to reference().
|
||||
*/
|
||||
@Deprecated
|
||||
default <T> T getReference(Class<T> beanType, Object id) {
|
||||
return reference(beanType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the extended API for Database.
|
||||
@@ -886,7 +993,7 @@ public interface Database {
|
||||
* <pre>{@code
|
||||
* public class Order { ...
|
||||
*
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* List<OrderDetail> details;
|
||||
* ...
|
||||
* }
|
||||
@@ -1420,13 +1527,29 @@ public interface Database {
|
||||
/**
|
||||
* Return the manager of the server cache ("L2" cache).
|
||||
*/
|
||||
ServerCacheManager getServerCacheManager();
|
||||
ServerCacheManager cacheManager();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to cacheManager().
|
||||
*/
|
||||
@Deprecated
|
||||
default ServerCacheManager getServerCacheManager() {
|
||||
return cacheManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BackgroundExecutor service for asynchronous processing of
|
||||
* queries.
|
||||
*/
|
||||
BackgroundExecutor getBackgroundExecutor();
|
||||
BackgroundExecutor backgroundExecutor();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to backgroundExecutor().
|
||||
*/
|
||||
@Deprecated
|
||||
default BackgroundExecutor getBackgroundExecutor() {
|
||||
return backgroundExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JsonContext for reading/writing JSON.
|
||||
@@ -1591,6 +1714,20 @@ public interface Database {
|
||||
*/
|
||||
<T> Set<String> validateQuery(Query<T> query);
|
||||
|
||||
/**
|
||||
* Load and lock the bean using {@code select for update}.
|
||||
* <p>
|
||||
* This should be executed inside a transaction and results in the bean being loaded or
|
||||
* refreshed from the database and a database row lock held via {@code select for update}.
|
||||
* <p>
|
||||
* The bean needs to have an ID property set and can be a reference bean (only has ID)
|
||||
* or partially or fully populated bean. This will load all the properties of the bean
|
||||
* from the database using {@code select for update} obtaining a database row lock (using WAIT).
|
||||
*
|
||||
* @param bean The entity bean that we wish to obtain a database lock on.
|
||||
*/
|
||||
void lock(Object bean);
|
||||
|
||||
/**
|
||||
* Truncate all the given tables.
|
||||
*/
|
||||
|
||||
@@ -16,23 +16,21 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
* <p>
|
||||
* This uses either DatabaseConfig or properties in the application.properties file to
|
||||
* configure and create a Database instance.
|
||||
* </p>
|
||||
* <p>
|
||||
* The Database instance can either be registered with the DB singleton or
|
||||
* not. The DB singleton effectively holds a map of Database by a name.
|
||||
* If the Database is registered with the DB singleton you can retrieve it
|
||||
* later via {@link DB#byName(String)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* One Database can be nominated as the 'default/primary' Database. Many
|
||||
* methods on the DB singleton such as {@link DB#find(Class)} are just a
|
||||
* convenient way of using the 'default/primary' Database.
|
||||
* </p>
|
||||
*/
|
||||
public class DatabaseFactory {
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
private static SpiContainer container;
|
||||
private static String defaultServerName;
|
||||
|
||||
static {
|
||||
EbeanVersion.getVersion();
|
||||
@@ -47,7 +45,7 @@ public class DatabaseFactory {
|
||||
public static void initialiseContainer(ContainerConfig containerConfig) {
|
||||
lock.lock();
|
||||
try {
|
||||
getContainer(containerConfig);
|
||||
container(containerConfig);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@@ -59,7 +57,7 @@ public class DatabaseFactory {
|
||||
public static Database create(String name) {
|
||||
lock.lock();
|
||||
try {
|
||||
return getContainer(null).createServer(name);
|
||||
return container(null).createServer(name);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@@ -67,6 +65,16 @@ public class DatabaseFactory {
|
||||
|
||||
/**
|
||||
* Create using the DatabaseConfig object to configure the database.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* DatabaseConfig config = new DatabaseConfig();
|
||||
* config.setName("db");
|
||||
* config.loadProperties();
|
||||
*
|
||||
* Database database = DatabaseFactory.create(config);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static Database create(DatabaseConfig config) {
|
||||
lock.lock();
|
||||
@@ -76,6 +84,12 @@ public class DatabaseFactory {
|
||||
}
|
||||
Database server = createInternal(config);
|
||||
if (config.isRegister()) {
|
||||
if (config.isDefaultServer()) {
|
||||
if (defaultServerName != null && !defaultServerName.equals(config.getName())) {
|
||||
throw new IllegalStateException("Registering [" + config.getName() + "] as the default server but [" + defaultServerName + "] is already registered as the default");
|
||||
}
|
||||
defaultServerName = config.getName();
|
||||
}
|
||||
DbPrimary.setSkip(true);
|
||||
DbContext.getInstance().register(server, config.isDefaultServer());
|
||||
}
|
||||
@@ -108,7 +122,6 @@ public class DatabaseFactory {
|
||||
* Shutdown gracefully all Database instances cleaning up any resources as required.
|
||||
* <p>
|
||||
* This is typically invoked via JVM shutdown hook and not explicitly called.
|
||||
* </p>
|
||||
*/
|
||||
public static void shutdown() {
|
||||
lock.lock();
|
||||
@@ -120,15 +133,15 @@ public class DatabaseFactory {
|
||||
}
|
||||
|
||||
private static Database createInternal(DatabaseConfig config) {
|
||||
return getContainer(config.getContainerConfig()).createServer(config);
|
||||
return container(config.getContainerConfig()).createServer(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the EbeanContainer initialising it if necessary.
|
||||
* Return the SpiContainer initialising it if necessary.
|
||||
*
|
||||
* @param containerConfig the configuration controlling clustering communication
|
||||
*/
|
||||
private static SpiContainer getContainer(ContainerConfig containerConfig) {
|
||||
private static SpiContainer container(ContainerConfig containerConfig) {
|
||||
// thread safe in that all calling methods hold lock
|
||||
if (container != null) {
|
||||
return container;
|
||||
|
||||
@@ -15,8 +15,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
final class DbContext {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DbContext.class);
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger("io.ebean");
|
||||
static {
|
||||
EbeanVersion.getVersion();
|
||||
}
|
||||
@@ -27,7 +26,7 @@ final class DbContext {
|
||||
|
||||
private final HashMap<String, Database> syncMap = new HashMap<>();
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* The 'default' Database.
|
||||
@@ -39,7 +38,6 @@ final class DbContext {
|
||||
if (!DbPrimary.isSkip()) {
|
||||
// look to see if there is a default server defined
|
||||
String defaultName = DbPrimary.getDefaultServerName();
|
||||
logger.debug("defaultName:{}", defaultName);
|
||||
if (defaultName != null && !defaultName.trim().isEmpty()) {
|
||||
defaultDatabase = getWithCreate(defaultName.trim());
|
||||
}
|
||||
@@ -54,7 +52,7 @@ final class DbContext {
|
||||
throw new DataSourceConfigurationException(msg, e);
|
||||
|
||||
} catch (Throwable e) {
|
||||
logger.error("Error trying to create the default Database", e);
|
||||
log.error("Error trying to create the default Database", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
@@ -115,7 +113,7 @@ final class DbContext {
|
||||
* Register a server so we can get it by its name.
|
||||
*/
|
||||
void register(Database server, boolean isDefault) {
|
||||
registerWithName(server.getName(), server, isDefault);
|
||||
registerWithName(server.name(), server, isDefault);
|
||||
}
|
||||
|
||||
private void registerWithName(String name, Database server, boolean isDefault) {
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
class DbPrimary {
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
private static String defaultServerName;
|
||||
private static boolean skip;
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ package io.ebean;
|
||||
|
||||
import io.ebean.docstore.DocQueryContext;
|
||||
import io.ebean.docstore.RawDoc;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -149,7 +149,7 @@ public interface DocumentStore {
|
||||
* .setUseDocStore(true)
|
||||
* .where()... // perhaps add predicates
|
||||
* .findEachWhile(new Predicate<Order>() {
|
||||
* @Override
|
||||
* @Override
|
||||
* public void accept(Order bean) {
|
||||
* // process the bean
|
||||
*
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Query for performing native SQL queries that return DTO Bean's.
|
||||
@@ -37,7 +38,7 @@ import java.util.function.Predicate;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public interface DtoQuery<T> {
|
||||
public interface DtoQuery<T> extends CancelableQuery {
|
||||
|
||||
/**
|
||||
* Execute the query returning a list.
|
||||
@@ -45,6 +46,26 @@ public interface DtoQuery<T> {
|
||||
@Nonnull
|
||||
List<T> findList();
|
||||
|
||||
/**
|
||||
* Execute the query iterating a row at a time.
|
||||
* <p>
|
||||
* Note that the QueryIterator holds resources related to the underlying
|
||||
* resultSet and potentially connection and MUST be closed. We should use
|
||||
* QueryIterator in a <em>try with resource block</em>.
|
||||
*/
|
||||
@Nonnull
|
||||
QueryIterator<T> findIterate();
|
||||
|
||||
/**
|
||||
* Execute the query returning a Stream.
|
||||
* <p>
|
||||
* Note that the Stream holds resources related to the underlying
|
||||
* resultSet and potentially connection and MUST be closed. We should use
|
||||
* the Stream in a <em>try with resource block</em>.
|
||||
*/
|
||||
@Nonnull
|
||||
Stream<T> findStream();
|
||||
|
||||
/**
|
||||
* Execute the query iterating a row at a time.
|
||||
* <p>
|
||||
@@ -53,6 +74,17 @@ public interface DtoQuery<T> {
|
||||
*/
|
||||
void findEach(Consumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query iterating the results and batching them for the consumer.
|
||||
* <p>
|
||||
* This runs like findEach streaming results from the database but just collects the results
|
||||
* into batches to pass to the consumer.
|
||||
*
|
||||
* @param batch The number of dto beans to collect before given them to the consumer
|
||||
* @param consumer The consumer to process the batch of DTO beans
|
||||
*/
|
||||
void findEach(int batch, Consumer<List<T>> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query iterating a row at a time with the ability to stop consuming part way through.
|
||||
* <p>
|
||||
|
||||
@@ -103,7 +103,7 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static ExpressionFactory getExpressionFactory() {
|
||||
return getDefault().getExpressionFactory();
|
||||
return getDefault().expressionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -346,7 +346,7 @@ public final class Ebean {
|
||||
* <pre>{@code
|
||||
* public class Order { ...
|
||||
*
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* List<OrderDetail> details;
|
||||
* ...
|
||||
* }
|
||||
@@ -642,7 +642,7 @@ public final class Ebean {
|
||||
* @param id the id value
|
||||
*/
|
||||
public static <T> T getReference(Class<T> beanType, Object id) {
|
||||
return getDefault().getReference(beanType, id);
|
||||
return getDefault().reference(beanType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1201,14 +1201,14 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static BeanState getBeanState(Object bean) {
|
||||
return getDefault().getBeanState(bean);
|
||||
return getDefault().beanState(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the manager of the server cache ("L2" cache).
|
||||
*/
|
||||
public static ServerCacheManager getServerCacheManager() {
|
||||
return getDefault().getServerCacheManager();
|
||||
return getDefault().cacheManager();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1216,7 +1216,7 @@ public final class Ebean {
|
||||
* queries.
|
||||
*/
|
||||
public static BackgroundExecutor getBackgroundExecutor() {
|
||||
return getDefault().getBackgroundExecutor();
|
||||
return getDefault().backgroundExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,13 +2,6 @@ package io.ebean;
|
||||
|
||||
import io.ebean.config.ContainerConfig;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.service.SpiContainer;
|
||||
import io.ebean.service.SpiContainerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* Deprecated - please migrate to DatabaseFactory.
|
||||
|
||||
@@ -14,26 +14,75 @@ import java.util.Properties;
|
||||
*/
|
||||
public class EbeanVersion {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(EbeanVersion.class);
|
||||
private static final Logger log = LoggerFactory.getLogger("io.ebean");
|
||||
|
||||
/**
|
||||
* Maintain the minimum ebean-agent version manually based on required ebean-agent bug fixes.
|
||||
*/
|
||||
private static final int MIN_AGENT_MAJOR_VERSION = 12;
|
||||
private static final int MIN_AGENT_MINOR_VERSION = 12;
|
||||
private static String version = "unknown";
|
||||
|
||||
static {
|
||||
readVersion();
|
||||
checkAgentVersion();
|
||||
}
|
||||
|
||||
private static void readVersion() {
|
||||
try {
|
||||
Properties prop = new Properties();
|
||||
try (InputStream in = DB.class.getResourceAsStream("/META-INF/maven/io.ebean/ebean/pom.properties")) {
|
||||
try (InputStream in = ClassLoader.getSystemResourceAsStream("META-INF/maven/io.ebean/ebean-api/pom.properties")) {
|
||||
if (in != null) {
|
||||
prop.load(in);
|
||||
in.close();
|
||||
version = prop.getProperty("version");
|
||||
version = readVersion(in);
|
||||
}
|
||||
}
|
||||
logger.info("ebean version: {}", version);
|
||||
log.info("ebean version: {}", version);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Could not determine ebean version: {}", e.getMessage());
|
||||
log.warn("Could not determine ebean version: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkAgentVersion() {
|
||||
try {
|
||||
try (InputStream in = ClassLoader.getSystemResourceAsStream("META-INF/maven/io.ebean/ebean-agent/pom.properties")) {
|
||||
// often we only have ebean-agent during development (with build time enhancement), null is expected
|
||||
if (in != null) {
|
||||
String agentVersion = readVersion(in);
|
||||
if (agentVersion != null) {
|
||||
if (checkMinAgentVersion(agentVersion)) {
|
||||
log.error("Expected minimum ebean-agent version {}.{}.0 but we have {}, please update the ebean-agent", MIN_AGENT_MAJOR_VERSION, MIN_AGENT_MINOR_VERSION, agentVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not check minimum ebean-agent version {}.{}.0 required due to - {}", MIN_AGENT_MAJOR_VERSION, MIN_AGENT_MINOR_VERSION, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if ebean-agent is NOT at our minimum version.
|
||||
*/
|
||||
static boolean checkMinAgentVersion(String agentVersion) {
|
||||
String[] versionSegments = agentVersion.split("\\.");
|
||||
if (versionSegments.length != 3) {
|
||||
return true;
|
||||
} else {
|
||||
int major = Integer.parseInt(versionSegments[0]);
|
||||
int minor = Integer.parseInt(versionSegments[1]);
|
||||
if (major < MIN_AGENT_MAJOR_VERSION) {
|
||||
return true;
|
||||
} else {
|
||||
return major == MIN_AGENT_MAJOR_VERSION && minor < MIN_AGENT_MINOR_VERSION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String readVersion(InputStream in) throws IOException {
|
||||
Properties prop = new Properties();
|
||||
prop.load(in);
|
||||
in.close();
|
||||
return prop.getProperty("version");
|
||||
}
|
||||
|
||||
private EbeanVersion() {
|
||||
// hide
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import java.util.Map;
|
||||
* This provides a convenient way to create expressions for the default
|
||||
* database.
|
||||
* <p>
|
||||
* See also {@link DB#getExpressionFactory()}
|
||||
* See also {@link DB#expressionFactory()}
|
||||
* </p>
|
||||
* <p>
|
||||
* Creates standard common expressions for using in a Query Where or Having
|
||||
@@ -34,14 +34,14 @@ public class Expr {
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
public static Expression eq(String propertyName, Object value) {
|
||||
return DB.getExpressionFactory().eq(propertyName, value);
|
||||
return DB.expressionFactory().eq(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not Equal To - property not equal to the given value.
|
||||
*/
|
||||
public static Expression ne(String propertyName, Object value) {
|
||||
return DB.getExpressionFactory().ne(propertyName, value);
|
||||
return DB.expressionFactory().ne(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,7 +49,7 @@ public class Expr {
|
||||
* using a lower() function to make it case insensitive).
|
||||
*/
|
||||
public static Expression ieq(String propertyName, String value) {
|
||||
return DB.getExpressionFactory().ieq(propertyName, value);
|
||||
return DB.expressionFactory().ieq(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,28 +59,28 @@ public class Expr {
|
||||
* </p>
|
||||
*/
|
||||
public static Expression inRange(String propertyName, Object value1, Object value2) {
|
||||
return DB.getExpressionFactory().inRange(propertyName, value1, value2);
|
||||
return DB.expressionFactory().inRange(propertyName, value1, value2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
public static Expression between(String propertyName, Object value1, Object value2) {
|
||||
return DB.getExpressionFactory().between(propertyName, value1, value2);
|
||||
return DB.expressionFactory().between(propertyName, value1, value2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Between - value between two given properties.
|
||||
*/
|
||||
public static Expression between(String lowProperty, String highProperty, Object value) {
|
||||
return DB.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
|
||||
return DB.expressionFactory().betweenProperties(lowProperty, highProperty, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Greater Than - property greater than the given value.
|
||||
*/
|
||||
public static Expression gt(String propertyName, Object value) {
|
||||
return DB.getExpressionFactory().gt(propertyName, value);
|
||||
return DB.expressionFactory().gt(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,42 +88,42 @@ public class Expr {
|
||||
* value.
|
||||
*/
|
||||
public static Expression ge(String propertyName, Object value) {
|
||||
return DB.getExpressionFactory().ge(propertyName, value);
|
||||
return DB.expressionFactory().ge(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Less Than - property less than the given value.
|
||||
*/
|
||||
public static Expression lt(String propertyName, Object value) {
|
||||
return DB.getExpressionFactory().lt(propertyName, value);
|
||||
return DB.expressionFactory().lt(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Less Than or Equal to - property less than or equal to the given value.
|
||||
*/
|
||||
public static Expression le(String propertyName, Object value) {
|
||||
return DB.getExpressionFactory().le(propertyName, value);
|
||||
return DB.expressionFactory().le(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Null - property is null.
|
||||
*/
|
||||
public static Expression isNull(String propertyName) {
|
||||
return DB.getExpressionFactory().isNull(propertyName);
|
||||
return DB.expressionFactory().isNull(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Not Null - property is not null.
|
||||
*/
|
||||
public static Expression isNotNull(String propertyName) {
|
||||
return DB.getExpressionFactory().isNotNull(propertyName);
|
||||
return DB.expressionFactory().isNotNull(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive {@link #exampleLike(Object)}
|
||||
*/
|
||||
public static ExampleExpression iexampleLike(Object example) {
|
||||
return DB.getExpressionFactory().iexampleLike(example);
|
||||
return DB.expressionFactory().iexampleLike(example);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,14 +131,14 @@ public class Expr {
|
||||
* LikeType.RAW (you need to add you own wildcards % and _).
|
||||
*/
|
||||
public static ExampleExpression exampleLike(Object example) {
|
||||
return DB.getExpressionFactory().exampleLike(example);
|
||||
return DB.expressionFactory().exampleLike(example);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the query by Example expression specifying more options.
|
||||
*/
|
||||
public static ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType) {
|
||||
return DB.getExpressionFactory().exampleLike(example, caseInsensitive, likeType);
|
||||
return DB.expressionFactory().exampleLike(example, caseInsensitive, likeType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,7 +146,7 @@ public class Expr {
|
||||
* characters % (percentage) and _ (underscore).
|
||||
*/
|
||||
public static Expression like(String propertyName, String value) {
|
||||
return DB.getExpressionFactory().like(propertyName, value);
|
||||
return DB.expressionFactory().like(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,14 +155,14 @@ public class Expr {
|
||||
* a lower() function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression ilike(String propertyName, String value) {
|
||||
return DB.getExpressionFactory().ilike(propertyName, value);
|
||||
return DB.expressionFactory().ilike(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts With - property like value%.
|
||||
*/
|
||||
public static Expression startsWith(String propertyName, String value) {
|
||||
return DB.getExpressionFactory().startsWith(propertyName, value);
|
||||
return DB.expressionFactory().startsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,14 +170,14 @@ public class Expr {
|
||||
* lower() function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression istartsWith(String propertyName, String value) {
|
||||
return DB.getExpressionFactory().istartsWith(propertyName, value);
|
||||
return DB.expressionFactory().istartsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends With - property like %value.
|
||||
*/
|
||||
public static Expression endsWith(String propertyName, String value) {
|
||||
return DB.getExpressionFactory().endsWith(propertyName, value);
|
||||
return DB.expressionFactory().endsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,14 +185,14 @@ public class Expr {
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression iendsWith(String propertyName, String value) {
|
||||
return DB.getExpressionFactory().iendsWith(propertyName, value);
|
||||
return DB.expressionFactory().iendsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains - property like %value%.
|
||||
*/
|
||||
public static Expression contains(String propertyName, String value) {
|
||||
return DB.getExpressionFactory().contains(propertyName, value);
|
||||
return DB.expressionFactory().contains(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,42 +200,42 @@ public class Expr {
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression icontains(String propertyName, String value) {
|
||||
return DB.getExpressionFactory().icontains(propertyName, value);
|
||||
return DB.expressionFactory().icontains(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* For collection properties that are empty (have not existing elements).
|
||||
*/
|
||||
public static Expression isEmpty(String propertyName) {
|
||||
return DB.getExpressionFactory().isEmpty(propertyName);
|
||||
return DB.expressionFactory().isEmpty(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* For collection properties that are not empty (have existing elements).
|
||||
*/
|
||||
public static Expression isNotEmpty(String propertyName) {
|
||||
return DB.getExpressionFactory().isNotEmpty(propertyName);
|
||||
return DB.expressionFactory().isNotEmpty(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the array of values.
|
||||
*/
|
||||
public static Expression in(String propertyName, Object[] values) {
|
||||
return DB.getExpressionFactory().in(propertyName, values);
|
||||
return DB.expressionFactory().in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - using a subQuery.
|
||||
*/
|
||||
public static Expression in(String propertyName, Query<?> subQuery) {
|
||||
return DB.getExpressionFactory().in(propertyName, subQuery);
|
||||
return DB.expressionFactory().in(propertyName, subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the collection of values.
|
||||
*/
|
||||
public static Expression in(String propertyName, Collection<?> values) {
|
||||
return DB.getExpressionFactory().in(propertyName, values);
|
||||
return DB.expressionFactory().in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -272,14 +272,14 @@ public class Expr {
|
||||
* }</pre>
|
||||
*/
|
||||
public static Expression inOrEmpty(String propertyName, Collection<?> values) {
|
||||
return DB.getExpressionFactory().inOrEmpty(propertyName, values);
|
||||
return DB.expressionFactory().inOrEmpty(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Id Equal to - ID property is equal to the value.
|
||||
*/
|
||||
public static Expression idEq(Object value) {
|
||||
return DB.getExpressionFactory().idEq(value);
|
||||
return DB.expressionFactory().idEq(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,7 +292,7 @@ public class Expr {
|
||||
* @param propertyMap a map keyed by property names.
|
||||
*/
|
||||
public static Expression allEq(Map<String, Object> propertyMap) {
|
||||
return DB.getExpressionFactory().allEq(propertyMap);
|
||||
return DB.expressionFactory().allEq(propertyMap);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -303,7 +303,7 @@ public class Expr {
|
||||
* </p>
|
||||
*/
|
||||
public static Expression raw(String raw, Object value) {
|
||||
return DB.getExpressionFactory().raw(raw, value);
|
||||
return DB.expressionFactory().raw(raw, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,53 +314,48 @@ public class Expr {
|
||||
* </p>
|
||||
*/
|
||||
public static Expression raw(String raw, Object[] values) {
|
||||
return DB.getExpressionFactory().raw(raw, values);
|
||||
return DB.expressionFactory().raw(raw, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw expression with no parameters.
|
||||
*/
|
||||
public static Expression raw(String raw) {
|
||||
return DB.getExpressionFactory().raw(raw);
|
||||
return DB.expressionFactory().raw(raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* And - join two expressions with a logical and.
|
||||
*/
|
||||
public static Expression and(Expression expOne, Expression expTwo) {
|
||||
|
||||
return DB.getExpressionFactory().and(expOne, expTwo);
|
||||
return DB.expressionFactory().and(expOne, expTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Or - join two expressions with a logical or.
|
||||
*/
|
||||
public static Expression or(Expression expOne, Expression expTwo) {
|
||||
|
||||
return DB.getExpressionFactory().or(expOne, expTwo);
|
||||
return DB.expressionFactory().or(expOne, expTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate the expression (prefix it with NOT).
|
||||
*/
|
||||
public static Expression not(Expression exp) {
|
||||
|
||||
return DB.getExpressionFactory().not(exp);
|
||||
return DB.expressionFactory().not(exp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by AND's.
|
||||
*/
|
||||
public static <T> Junction<T> conjunction(Query<T> query) {
|
||||
|
||||
return DB.getExpressionFactory().conjunction(query);
|
||||
return DB.expressionFactory().conjunction(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
*/
|
||||
public static <T> Junction<T> disjunction(Query<T> query) {
|
||||
|
||||
return DB.getExpressionFactory().disjunction(query);
|
||||
return DB.expressionFactory().disjunction(query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ public interface ExpressionFactory {
|
||||
Expression gtOrNull(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Greater than or Equal to OR Null <code> >= or null </code>
|
||||
* Greater than or Equal to OR Null ({@code >= or null })
|
||||
* <p>
|
||||
* A convenient expression combining GE and Is Null. Most often useful for range
|
||||
* expressions where the top range value is nullable.
|
||||
@@ -227,7 +227,7 @@ public interface ExpressionFactory {
|
||||
Expression ltOrNull(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than or Equal to OR Null <code> <= or null </code>
|
||||
* Less Than or Equal to OR Null ({@code <= or null })
|
||||
* <p>
|
||||
* A convenient expression combining LE and Is Null. Most often useful for range
|
||||
* expressions where the bottom range value is nullable.
|
||||
|
||||
@@ -169,6 +169,28 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
UpdateQuery<T> asUpdate();
|
||||
|
||||
/**
|
||||
* Execute the query with the given lock type and WAIT.
|
||||
* <p>
|
||||
* Note that <code>forUpdate()</code> is the same as
|
||||
* <code>withLock(LockType.UPDATE)</code>.
|
||||
* <p>
|
||||
* Provides us with the ability to explicitly use Postgres
|
||||
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
|
||||
*/
|
||||
Query<T> withLock(Query.LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute the query with the given lock type and lock wait.
|
||||
* <p>
|
||||
* Note that <code>forUpdateNoWait()</code> is the same as
|
||||
* <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
|
||||
* <p>
|
||||
* Provides us with the ability to explicitly use Postgres
|
||||
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
|
||||
*/
|
||||
Query<T> withLock(Query.LockType lockType, Query.LockWait lockWait);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause which results in the DB locking the record.
|
||||
*/
|
||||
@@ -285,6 +307,13 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
void findEach(Consumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute findEach with a batch consumer.
|
||||
*
|
||||
* @see Query#findEach(int, Consumer)
|
||||
*/
|
||||
void findEach(int batch, Consumer<List<T>> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query processing the beans one at a time with the ability to
|
||||
* stop processing before reading all the beans.
|
||||
@@ -887,7 +916,7 @@ public interface ExpressionList<T> {
|
||||
ExpressionList<T> gtOrNull(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Greater Than or Equal to OR Null - <code> >= or null </code>.
|
||||
* Greater Than or Equal to OR Null - ({@code >= or null }).
|
||||
*/
|
||||
ExpressionList<T> geOrNull(String propertyName, Object value);
|
||||
|
||||
@@ -908,7 +937,7 @@ public interface ExpressionList<T> {
|
||||
ExpressionList<T> ltOrNull(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than or Equal to OR Null - <code> <= or null </code>.
|
||||
* Less Than or Equal to OR Null - ({@code <= or null }).
|
||||
*/
|
||||
ExpressionList<T> leOrNull(String propertyName, Object value);
|
||||
|
||||
@@ -1642,7 +1671,7 @@ public interface ExpressionList<T> {
|
||||
ExpressionList<T> endAnd();
|
||||
|
||||
/**
|
||||
* End a AND junction - synonym for endJunction().
|
||||
* End a OR junction - synonym for endJunction().
|
||||
*/
|
||||
ExpressionList<T> endOr();
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ public interface ExtendedServer {
|
||||
*
|
||||
* @return True if the query finds a matching row in the database
|
||||
*/
|
||||
<T> boolean exists(Query<?> ormQuery, Transaction transaction);
|
||||
<T> boolean exists(Query<T> ormQuery, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Return the number of 'top level' or 'root' entities this query should return.
|
||||
@@ -159,6 +159,13 @@ public interface ExtendedServer {
|
||||
*/
|
||||
<T> void findEach(Query<T> query, Consumer<T> consumer, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute findEach with batch consumer.
|
||||
*
|
||||
* @see Query#findEach(int, Consumer)
|
||||
*/
|
||||
<T> void findEach(Query<T> query, int batch, Consumer<List<T>> consumer, Transaction t);
|
||||
|
||||
/**
|
||||
* Execute the query visiting the each bean one at a time.
|
||||
* <p>
|
||||
|
||||
@@ -3,30 +3,13 @@ package io.ebean;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Defines the configuration options for a "query fetch" or a
|
||||
* "lazy loading fetch". This gives you the ability to use multiple smaller
|
||||
* queries to populate an object graph as opposed to a single large query.
|
||||
* <p>
|
||||
* The primary goal is to provide efficient ways of loading complex object
|
||||
* graphs avoiding SQL Cartesian product and issues around populating object
|
||||
* graphs that have multiple *ToMany relationships.
|
||||
* </p>
|
||||
* <p>
|
||||
* It also provides the ability to control the lazy loading queries (batch size,
|
||||
* selected properties and fetches) to avoid N+1 queries etc.
|
||||
* <p>
|
||||
* There can also be cases loading across a single OneToMany where 2 SQL queries
|
||||
* using Ebean FetchConfig.query() can be more efficient than one SQL query.
|
||||
* When the "One" side is wide (lots of columns) and the cardinality difference
|
||||
* is high (a lot of "Many" beans per "One" bean) then this can be more
|
||||
* efficient loaded as 2 SQL queries.
|
||||
* </p>
|
||||
* Defines how a relationship is fetched via either normal SQL join,
|
||||
* a eager secondary query, via lazy loading or via eagerly hitting L2 cache.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
* // Normal fetch join results in a single SQL query
|
||||
* List<Order> list = DB.find(Order.class).fetch("details").findList();
|
||||
*
|
||||
* // Find Orders join details using a single SQL query
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL queries
|
||||
@@ -37,103 +20,13 @@ import java.io.Serializable;
|
||||
* // This will use 2 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* DB.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("details", FetchConfig.ofQuery())
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using 2 "query joins"
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* DB.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("customer", new FetchConfig().queryFirst(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
|
||||
* // query 3) find customer where id in (?,?,?,?,?) // first 5 customers
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using "query joins" and partial objects
|
||||
* </p>
|
||||
* <p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* DB.find(Order.class)
|
||||
* .select("status, shipDate")
|
||||
* .fetch("details", "quantity, price", new FetchConfig().query())
|
||||
* .fetch("details.product", "sku, name")
|
||||
* .fetch("customer", "name", new FetchConfig().queryFirst(5))
|
||||
* .fetch("customer.contacts")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order (status, shipDate)
|
||||
* // query 2) find orderDetail (quantity, price) fetch product (sku, name) where
|
||||
* // order.id in (?,? ...)
|
||||
* // query 3) find customer (name) fetch contacts (*) fetch shippingAddress (*)
|
||||
* // where id in (?,?,?,?,?)
|
||||
*
|
||||
* // Note: the fetch of "details.product" is automatically included into the
|
||||
* // fetch of "details"
|
||||
* //
|
||||
* // Note: the fetch of "customer.contacts" and "customer.shippingAddress"
|
||||
* // are automatically included in the fetch of "customer"
|
||||
* }</pre>
|
||||
* <p>
|
||||
* You can use query() and lazy together on a single join. The query is executed
|
||||
* immediately and the lazy defines the batch size to use for further lazy
|
||||
* loading (if lazy loading is invoked).
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> list =
|
||||
* DB.find(Order.class)
|
||||
* .fetch("customer", new FetchConfig().query(10).lazy(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find customer where id in (?,?,?,?,?,?,?,?,?,?) // first 10 customers
|
||||
* // .. then if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <p>
|
||||
* Example of controlling the lazy loading query:
|
||||
* </p>
|
||||
* <p>
|
||||
* This gives us the ability to optimise the lazy loading query for a given use
|
||||
* case.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> list = DB.find(Order.class)
|
||||
* .fetch("customer","name", new FetchConfig().lazy(5))
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .where().eq("status",Order.Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order where status = Order.Status.NEW
|
||||
* //
|
||||
* // .. if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @author mario
|
||||
* @author rbygrave
|
||||
@@ -142,149 +35,209 @@ public class FetchConfig implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int lazyBatchSize = -1;
|
||||
private static final int JOIN_MODE = 0;
|
||||
private static final int QUERY_MODE = 1;
|
||||
private static final int LAZY_MODE = 2;
|
||||
private static final int CACHE_MODE = 3;
|
||||
|
||||
private int queryBatchSize = -1;
|
||||
|
||||
private boolean queryAll;
|
||||
|
||||
private boolean cache;
|
||||
private int mode;
|
||||
private int batchSize;
|
||||
private int hashCode;
|
||||
|
||||
/**
|
||||
* Construct the fetch configuration object.
|
||||
* Deprecated - migrate to one of the static factory methods like {@link FetchConfig#ofQuery()}
|
||||
* <p>
|
||||
* Construct using default JOIN mode.
|
||||
*/
|
||||
@Deprecated
|
||||
public FetchConfig() {
|
||||
//this.mode = JOIN_MODE;
|
||||
this.batchSize = 100;
|
||||
this.hashCode = 1000;
|
||||
}
|
||||
|
||||
private FetchConfig(int mode, int batchSize) {
|
||||
this.mode = mode;
|
||||
this.batchSize = batchSize;
|
||||
this.hashCode = mode + 10 * batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this path should be lazy loaded using the default batch load
|
||||
* size.
|
||||
* Return FetchConfig to eagerly fetch the relationship using L2 cache.
|
||||
* <p>
|
||||
* Any cache misses will be loaded by secondary query to the database.
|
||||
*/
|
||||
public static FetchConfig ofCache() {
|
||||
return new FetchConfig(CACHE_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to eagerly fetch the relationship using a secondary query.
|
||||
*/
|
||||
public static FetchConfig ofQuery() {
|
||||
return new FetchConfig(QUERY_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to eagerly fetch the relationship using a secondary with a given batch size.
|
||||
*/
|
||||
public static FetchConfig ofQuery(int batchSize) {
|
||||
return new FetchConfig(QUERY_MODE, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to lazily load the relationship.
|
||||
*/
|
||||
public static FetchConfig ofLazy() {
|
||||
return new FetchConfig(LAZY_MODE, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to lazily load the relationship specifying the batch size.
|
||||
*/
|
||||
public static FetchConfig ofLazy(int batchSize) {
|
||||
return new FetchConfig(LAZY_MODE, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to fetch the relationship using SQL join.
|
||||
*/
|
||||
public static FetchConfig ofDefault() {
|
||||
return new FetchConfig(JOIN_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* We want to migrate away from mutating FetchConfig to a fully immutable FetchConfig.
|
||||
*/
|
||||
private FetchConfig mutate(int mode, int batchSize) {
|
||||
if (batchSize < 0) {
|
||||
throw new IllegalArgumentException("batch size " + batchSize + " must be > 0");
|
||||
}
|
||||
this.mode = mode;
|
||||
this.batchSize = batchSize;
|
||||
this.hashCode = mode + 10 * batchSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to FetchConfig.ofLazy().
|
||||
*/
|
||||
@Deprecated
|
||||
public FetchConfig lazy() {
|
||||
this.lazyBatchSize = 0;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
return mutate(LAZY_MODE, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this path should be lazy loaded with a specified batch size.
|
||||
*
|
||||
* @param lazyBatchSize the batch size for lazy loading
|
||||
* Deprecated - migrate to FetchConfig.ofLazy(batchSize).
|
||||
*/
|
||||
public FetchConfig lazy(int lazyBatchSize) {
|
||||
this.lazyBatchSize = lazyBatchSize;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
@Deprecated
|
||||
public FetchConfig lazy(int batchSize) {
|
||||
return mutate(LAZY_MODE, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to FetchConfig.ofQuery().
|
||||
* <p>
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
* <p>
|
||||
* This will use the default batch size for separate query which is 100.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
public FetchConfig query() {
|
||||
this.queryBatchSize = 0;
|
||||
this.queryAll = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the beans fetching the beans from the L2 bean cache
|
||||
* and using the DB for beans not in the cache.
|
||||
*/
|
||||
public FetchConfig cache() {
|
||||
this.cache = true;
|
||||
this.queryBatchSize = 0;
|
||||
this.queryAll = true;
|
||||
return this;
|
||||
return mutate(QUERY_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to FetchConfig.ofQuery(batchSize).
|
||||
* <p>
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
* <p>
|
||||
* The queryBatchSize is the number of parent id's that this separate query
|
||||
* will load per batch.
|
||||
* </p>
|
||||
* <p>
|
||||
* This will load all beans on this path eagerly unless a {@link #lazy(int)}
|
||||
* is also used.
|
||||
* </p>
|
||||
*
|
||||
* @param queryBatchSize the batch size used to load beans on this path
|
||||
* @param batchSize the batch size used to load beans on this path
|
||||
*/
|
||||
public FetchConfig query(int queryBatchSize) {
|
||||
this.queryBatchSize = queryBatchSize;
|
||||
// queryAll true as long as a lazy batch size has not already been set
|
||||
this.queryAll = (lazyBatchSize == -1);
|
||||
return this;
|
||||
@Deprecated
|
||||
public FetchConfig query(int batchSize) {
|
||||
return mutate(QUERY_MODE, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to FetchConfig.ofQuery(batchSize).
|
||||
* <p>
|
||||
* Eagerly fetch the first batch of beans on this path.
|
||||
* This is similar to {@link #query(int)} but only fetches the first batch.
|
||||
* <p>
|
||||
* If there are more parent beans than the batch size then they will not be
|
||||
* loaded eagerly but instead use lazy loading.
|
||||
* </p>
|
||||
*
|
||||
* @param queryBatchSize the number of parent beans this path is populated for
|
||||
* @param batchSize the number of parent beans this path is populated for
|
||||
*/
|
||||
public FetchConfig queryFirst(int queryBatchSize) {
|
||||
this.queryBatchSize = queryBatchSize;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
@Deprecated
|
||||
public FetchConfig queryFirst(int batchSize) {
|
||||
return query(batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size for lazy loading.
|
||||
* Deprecated - migrate to FetchConfig.ofCache().
|
||||
* <p>
|
||||
* Eagerly fetch the beans fetching the beans from the L2 bean cache
|
||||
* and using the DB for beans not in the cache.
|
||||
*/
|
||||
public int getLazyBatchSize() {
|
||||
return lazyBatchSize;
|
||||
@Deprecated
|
||||
public FetchConfig cache() {
|
||||
return mutate(CACHE_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size for separate query load.
|
||||
* Return the batch size for fetching.
|
||||
*/
|
||||
public int getQueryBatchSize() {
|
||||
return queryBatchSize;
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the query fetch should fetch 'all' rather than just the
|
||||
* 'first' batch.
|
||||
*/
|
||||
public boolean isQueryAll() {
|
||||
return queryAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this uses L2 bean cache.
|
||||
* Return true if the fetch should use the L2 cache.
|
||||
*/
|
||||
public boolean isCache() {
|
||||
return cache;
|
||||
return mode == CACHE_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the fetch should be a eager secondary query.
|
||||
*/
|
||||
public boolean isQuery() {
|
||||
return mode == QUERY_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the fetch should be a lazy query.
|
||||
*/
|
||||
public boolean isLazy() {
|
||||
return mode == LAZY_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the fetch should try to use SQL join.
|
||||
*/
|
||||
public boolean isJoin() {
|
||||
return mode == JOIN_MODE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
FetchConfig that = (FetchConfig) o;
|
||||
if (lazyBatchSize != that.lazyBatchSize) return false;
|
||||
if (queryBatchSize != that.queryBatchSize) return false;
|
||||
if (cache != that.cache) return false;
|
||||
return queryAll == that.queryAll;
|
||||
return (hashCode == ((FetchConfig) o).hashCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = lazyBatchSize;
|
||||
result = 92821 * result + queryBatchSize;
|
||||
result = 92821 * result + (queryAll ? 1 : 0);
|
||||
result = 92821 * result + (cache ? 1 : 0);
|
||||
return result;
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ import java.util.List;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @Entity
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final CustomerFinder find = new CustomerFinder();
|
||||
@@ -80,7 +80,7 @@ public class Finder<I, T> {
|
||||
* // ... add extra customer specific finder methods
|
||||
* }
|
||||
*
|
||||
* @Entity
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final CustomerFinder find = new CustomerFinder();
|
||||
@@ -137,11 +137,11 @@ public class Finder<I, T> {
|
||||
/**
|
||||
* Creates an entity reference for this ID.
|
||||
* <p>
|
||||
* Equivalent to {@link Database#getReference(Class, Object)}
|
||||
* Equivalent to {@link Database#reference(Class, Object)}
|
||||
*/
|
||||
@Nonnull
|
||||
public T ref(I id) {
|
||||
return db().getReference(type, id);
|
||||
return db().reference(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,16 +32,16 @@ import io.ebean.bean.EntityBean;
|
||||
* // Typically there is a common base model that has some
|
||||
* // common properties like the ones below
|
||||
*
|
||||
* @MappedSuperclass
|
||||
* @MappedSuperclass
|
||||
* public class BaseModel extends Model {
|
||||
*
|
||||
* @Id Long id;
|
||||
* @Id Long id;
|
||||
*
|
||||
* @Version Long version;
|
||||
* @Version Long version;
|
||||
*
|
||||
* @WhenCreated Timestamp whenCreated;
|
||||
* @WhenCreated Timestamp whenCreated;
|
||||
*
|
||||
* @WhenUpdated Timestamp whenUpdated;
|
||||
* @WhenUpdated Timestamp whenUpdated;
|
||||
*
|
||||
* ...
|
||||
* }
|
||||
@@ -52,7 +52,7 @@ import io.ebean.bean.EntityBean;
|
||||
*
|
||||
* // Extend the mappedSuperclass
|
||||
*
|
||||
* @Entity @Table(name="o_account")
|
||||
* @Entity @Table(name="o_account")
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* String name;
|
||||
|
||||
+3
-10
@@ -1,11 +1,9 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import java.io.Serializable;
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Owner object notified when a modification is detected.
|
||||
*/
|
||||
public interface ModifyAwareOwner extends Serializable {
|
||||
public interface ModifyAwareType {
|
||||
|
||||
/**
|
||||
* Return true if the value is considered dirty.
|
||||
@@ -16,11 +14,6 @@ public interface ModifyAwareOwner extends Serializable {
|
||||
/**
|
||||
* Marks the object as modified.
|
||||
*/
|
||||
void markAsModified();
|
||||
|
||||
/**
|
||||
* Reset the dirty state to clean.
|
||||
*/
|
||||
void resetMarkedDirty();
|
||||
void setMarkedDirty(boolean markedDirty);
|
||||
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import java.util.Objects;
|
||||
* on the Query object.
|
||||
* </p>
|
||||
*/
|
||||
public final class OrderBy<T> implements Serializable {
|
||||
public class OrderBy<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 9157089257745730539L;
|
||||
|
||||
@@ -69,7 +69,6 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Add a property with ascending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> asc(String propertyName) {
|
||||
|
||||
list.add(new Property(propertyName, true));
|
||||
return query;
|
||||
}
|
||||
@@ -98,7 +97,6 @@ public final class OrderBy<T> implements Serializable {
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the property is known to be contained in the order by clause.
|
||||
*/
|
||||
@@ -207,7 +205,6 @@ public final class OrderBy<T> implements Serializable {
|
||||
if (!(obj instanceof OrderBy<?>)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OrderBy<?> e = (OrderBy<?>) obj;
|
||||
return e.list.equals(list);
|
||||
}
|
||||
@@ -249,7 +246,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
/**
|
||||
* A property and its ascending descending order.
|
||||
*/
|
||||
public static final class Property implements Serializable {
|
||||
public static class Property implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1546009780322478077L;
|
||||
|
||||
@@ -415,13 +412,10 @@ public final class OrderBy<T> implements Serializable {
|
||||
}
|
||||
|
||||
private void parse(String orderByClause) {
|
||||
|
||||
if (orderByClause == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] chunks = orderByClause.split(",");
|
||||
for (String chunk : chunks) {
|
||||
for (String chunk : orderByClause.split(",")) {
|
||||
Property p = parseProperty(chunk);
|
||||
if (p != null) {
|
||||
list.add(p);
|
||||
@@ -467,8 +461,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
if (s.startsWith("desc")) {
|
||||
return false;
|
||||
}
|
||||
String m = "Expecting [" + s + "] to be asc or desc?";
|
||||
throw new RuntimeException(m);
|
||||
throw new RuntimeException("Expecting [" + s + "] to be asc or desc?");
|
||||
}
|
||||
|
||||
private boolean isEmptyString(String s) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebean;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Holds a list of value object pairs.
|
||||
@@ -18,7 +19,7 @@ import java.util.List;
|
||||
*
|
||||
* // where a bean is annotated with a complex
|
||||
* // natural key made of several properties
|
||||
* @Cache(naturalKey = {"store","code","sku"})
|
||||
* @Cache(naturalKey = {"store","code","sku"})
|
||||
*
|
||||
*
|
||||
* Pairs pairs = new Pairs("sku", "code");
|
||||
@@ -62,15 +63,14 @@ import java.util.List;
|
||||
* </p>
|
||||
* <pre>{@code sql
|
||||
*
|
||||
* create index ix_name on table_name ((sku || '-' || code));
|
||||
* create index ix_name on table_name (sku || '-' || code);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public class Pairs {
|
||||
public final class Pairs {
|
||||
|
||||
private final String property0;
|
||||
private final String property1;
|
||||
|
||||
private final List<Entry> entries = new ArrayList<>();
|
||||
|
||||
/**
|
||||
@@ -111,54 +111,70 @@ public class Pairs {
|
||||
/**
|
||||
* Return the first property name.
|
||||
*/
|
||||
public String getProperty0() {
|
||||
public String property0() {
|
||||
return property0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the second property name.
|
||||
*/
|
||||
public String getProperty1() {
|
||||
public String property1() {
|
||||
return property1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the value pairs.
|
||||
*/
|
||||
public List<Entry> getEntries() {
|
||||
public List<Entry> entries() {
|
||||
return Collections.unmodifiableList(entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the separator character used with DB varchar concatenation to combine the 2 values.
|
||||
*/
|
||||
public String getConcatSeparator() {
|
||||
public String concatSeparator() {
|
||||
return concatSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the separator character used with DB varchar concatenation to combine the 2 values.
|
||||
*/
|
||||
public Pairs setConcatSeparator(String concatSeparator) {
|
||||
public Pairs concatSeparator(String concatSeparator) {
|
||||
this.concatSeparator = concatSeparator;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated migrate to concatSeparator()
|
||||
*/
|
||||
@Deprecated
|
||||
public Pairs setConcatSeparator(String concatSeparator) {
|
||||
return concatSeparator(concatSeparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a suffix used with DB varchar concatenation to combine the 2 values.
|
||||
*/
|
||||
public String getConcatSuffix() {
|
||||
public String concatSuffix() {
|
||||
return concatSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a suffix used with DB varchar concatenation to combine the 2 values.
|
||||
*/
|
||||
public Pairs setConcatSuffix(String concatSuffix) {
|
||||
public Pairs concatSuffix(String concatSuffix) {
|
||||
this.concatSuffix = concatSuffix;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated migrate to concatSuffix()
|
||||
*/
|
||||
@Deprecated
|
||||
public Pairs setConcatSuffix(String concatSuffix) {
|
||||
return concatSuffix(concatSuffix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "p0:" + property0 + " p1:" + property1 + " entries:" + entries;
|
||||
@@ -208,16 +224,13 @@ public class Pairs {
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Entry that = (Entry) o;
|
||||
return a.equals(that.a) && b.equals(that.b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = a.hashCode();
|
||||
result = 92821 * result + b.hashCode();
|
||||
return result;
|
||||
return Objects.hash(a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,16 +177,47 @@ import java.util.stream.Stream;
|
||||
*
|
||||
* @param <T> the type of Entity bean this query will fetch.
|
||||
*/
|
||||
public interface Query<T> {
|
||||
public interface Query<T> extends CancelableQuery {
|
||||
|
||||
/**
|
||||
* For update mode.
|
||||
* The lock type (strength) to use with query FOR UPDATE row locking.
|
||||
*/
|
||||
enum ForUpdate {
|
||||
enum LockType {
|
||||
/**
|
||||
* The default lock type being either UPDATE or NO_KEY_UPDATE based on
|
||||
* PlatformConfig.forUpdateNoKey configuration (Postgres option).
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* FOR UPDATE.
|
||||
*/
|
||||
UPDATE,
|
||||
|
||||
/**
|
||||
* FOR NO KEY UPDATE (Postgres only).
|
||||
*/
|
||||
NO_KEY_UPDATE,
|
||||
|
||||
/**
|
||||
* FOR SHARE (Postgres only).
|
||||
*/
|
||||
SHARE,
|
||||
|
||||
/**
|
||||
* FOR KEY SHARE (Postgres only).
|
||||
*/
|
||||
KEY_SHARE
|
||||
}
|
||||
|
||||
/**
|
||||
* FOR UPDATE wait mode.
|
||||
*/
|
||||
enum LockWait {
|
||||
/**
|
||||
* Standard For update clause.
|
||||
*/
|
||||
BASE,
|
||||
WAIT,
|
||||
|
||||
/**
|
||||
* For update with No Wait option.
|
||||
@@ -260,15 +291,6 @@ public interface Query<T> {
|
||||
*/
|
||||
UpdateQuery<T> asUpdate();
|
||||
|
||||
/**
|
||||
* Cancel the query execution if supported by the underlying database and
|
||||
* driver.
|
||||
* <p>
|
||||
* This must be called from a different thread to the query executor.
|
||||
* </p>
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* Return a copy of the query.
|
||||
* <p>
|
||||
@@ -483,7 +505,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, fetchProperties, new FetchConfig().query())
|
||||
* fetch(path, fetchProperties, FetchConfig.ofQuery())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -517,7 +539,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, fetchProperties, new FetchConfig().lazy())
|
||||
* fetch(path, fetchProperties, FetchConfig.ofLazy())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -542,7 +564,7 @@ public interface Query<T> {
|
||||
* // fetch customers (their id, name and status)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* .select("name, status")
|
||||
* .fetch("contacts", "firstName,lastName,email", new FetchConfig().lazy(10))
|
||||
* .fetch("contacts", "firstName,lastName,email", FetchConfig.ofLazy(10))
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
@@ -579,7 +601,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, new FetchConfig().query())
|
||||
* fetch(path, FetchConfig.ofQuery())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -608,7 +630,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, new FetchConfig().lazy())
|
||||
* fetch(path, FetchConfig.ofLazy())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -631,7 +653,7 @@ public interface Query<T> {
|
||||
* // fetch customers (their id, name and status)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* // lazy fetch contacts with a batch size of 100
|
||||
* .fetch("contacts", new FetchConfig().lazy(100))
|
||||
* .fetch("contacts", FetchConfig.ofLazy(100))
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
@@ -779,7 +801,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <p>
|
||||
* This method is functionally equivalent to findIterate() but instead of using an
|
||||
* iterator uses the Consumer interface which is better suited to use with Java8 closures.
|
||||
* iterator uses the Consumer interface which is better suited to use with closures.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
@@ -798,6 +820,21 @@ public interface Query<T> {
|
||||
*/
|
||||
void findEach(Consumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute findEach streaming query batching the results for consuming.
|
||||
* <p>
|
||||
* This query execution will stream the results and is suited to consuming
|
||||
* large numbers of results from the database.
|
||||
* <p>
|
||||
* Typically we use this batch consumer when we want to do further processing on
|
||||
* the beans and want to do that processing in batch form, for example - 100 at
|
||||
* a time.
|
||||
*
|
||||
* @param batch The number of beans processed in the batch
|
||||
* @param consumer Process the batch of beans
|
||||
*/
|
||||
void findEach(int batch, Consumer<List<T>> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query using callbacks to a visitor to process the resulting
|
||||
* beans one at a time.
|
||||
@@ -808,12 +845,12 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <p>
|
||||
* This method is functionally equivalent to findIterate() but instead of using an
|
||||
* iterator uses the Predicate (SAM) interface which is better suited to use with Java8 closures.
|
||||
* iterator uses the Predicate interface which is better suited to use with closures.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* DB.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .fetchQuery("contacts")
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .setMaxRows(2000)
|
||||
@@ -1613,8 +1650,32 @@ public interface Query<T> {
|
||||
*/
|
||||
String getGeneratedSql();
|
||||
|
||||
/**
|
||||
* Execute the query with the given lock type and WAIT.
|
||||
* <p>
|
||||
* Note that <code>forUpdate()</code> is the same as
|
||||
* <code>withLock(LockType.UPDATE)</code>.
|
||||
* <p>
|
||||
* Provides us with the ability to explicitly use Postgres
|
||||
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
|
||||
*/
|
||||
Query<T> withLock(LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute the query with the given lock type and lock wait.
|
||||
* <p>
|
||||
* Note that <code>forUpdateNoWait()</code> is the same as
|
||||
* <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
|
||||
* <p>
|
||||
* Provides us with the ability to explicitly use Postgres
|
||||
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
|
||||
*/
|
||||
Query<T> withLock(LockType lockType, LockWait lockWait);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause which results in the DB locking the record.
|
||||
* <p>
|
||||
* The same as <code>withLock(LockType.UPDATE, LockWait.WAIT)</code>.
|
||||
*/
|
||||
Query<T> forUpdate();
|
||||
|
||||
@@ -1622,7 +1683,8 @@ public interface Query<T> {
|
||||
* Execute using "for update" clause with "no wait" option.
|
||||
* <p>
|
||||
* This is typically a Postgres and Oracle only option at this stage.
|
||||
* </p>
|
||||
* <p>
|
||||
* The same as <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
|
||||
*/
|
||||
Query<T> forUpdateNoWait();
|
||||
|
||||
@@ -1630,7 +1692,8 @@ public interface Query<T> {
|
||||
* Execute using "for update" clause with "skip locked" option.
|
||||
* <p>
|
||||
* This is typically a Postgres and Oracle only option at this stage.
|
||||
* </p>
|
||||
* <p>
|
||||
* The same as <code>withLock(LockType.UPDATE, LockWait.SKIPLOCKED)</code>.
|
||||
*/
|
||||
Query<T> forUpdateSkipLocked();
|
||||
|
||||
@@ -1640,9 +1703,14 @@ public interface Query<T> {
|
||||
boolean isForUpdate();
|
||||
|
||||
/**
|
||||
* Return the "for update" mode to use.
|
||||
* Return the "for update" wait mode to use.
|
||||
*/
|
||||
ForUpdate getForUpdateMode();
|
||||
LockWait getForUpdateLockWait();
|
||||
|
||||
/**
|
||||
* Return the lock type (strength) to use with "for update".
|
||||
*/
|
||||
LockType getForUpdateLockType();
|
||||
|
||||
/**
|
||||
* Set root table alias.
|
||||
|
||||
@@ -56,7 +56,7 @@ import java.util.Iterator;
|
||||
*
|
||||
* @param <T> the type of entity bean in the iteration
|
||||
*/
|
||||
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
|
||||
public interface QueryIterator<T> extends Iterator<T>, AutoCloseable {
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if the iteration has more elements.
|
||||
@@ -70,12 +70,6 @@ public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
|
||||
@Override
|
||||
T next();
|
||||
|
||||
/**
|
||||
* Remove is not allowed.
|
||||
*/
|
||||
@Override
|
||||
void remove();
|
||||
|
||||
/**
|
||||
* Close the underlying resources held by this iterator.
|
||||
*/
|
||||
|
||||
@@ -41,14 +41,14 @@ package io.ebean;
|
||||
* <h3>Example OrderAggregate</h3>
|
||||
* <pre>{@code
|
||||
* ...
|
||||
* // @Sql indicates to that this bean
|
||||
* // @Sql indicates to that this bean
|
||||
* // is based on RawSql rather than a table
|
||||
*
|
||||
* @Entity
|
||||
* @Sql
|
||||
* @Entity
|
||||
* @Sql
|
||||
* public class OrderAggregate {
|
||||
*
|
||||
* @OneToOne
|
||||
* @OneToOne
|
||||
* Order order;
|
||||
*
|
||||
* Double totalAmount;
|
||||
@@ -107,7 +107,7 @@ package io.ebean;
|
||||
*
|
||||
* List<OrderAggregate> orders = DB.find(OrderAggregate.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .fetch("order", "status,orderDate", new FetchConfig().query())
|
||||
* .fetch("order", "status,orderDate", FetchConfig.ofQuery())
|
||||
* .fetch("order.customer", "name")
|
||||
* .where().gt("order.id", 0)
|
||||
* .having().gt("totalAmount", 20)
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.sql.SQLException;
|
||||
* //
|
||||
* class CustomerMapper implements RowMapper<CustomerDto> {
|
||||
*
|
||||
* @Override
|
||||
* @Override
|
||||
* public CustomerDto map(ResultSet rset, int rowNum) throws SQLException {
|
||||
*
|
||||
* long id = rset.getLong(1);
|
||||
|
||||
@@ -37,7 +37,7 @@ import java.util.function.Predicate;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public interface SqlQuery extends Serializable {
|
||||
public interface SqlQuery extends Serializable, CancelableQuery {
|
||||
|
||||
/**
|
||||
* Execute the query returning a list.
|
||||
@@ -365,5 +365,10 @@ public interface SqlQuery extends Serializable {
|
||||
* Return the list of values.
|
||||
*/
|
||||
List<T> findList();
|
||||
|
||||
/**
|
||||
* Find streaming the result effectively consuming a row at a time.
|
||||
*/
|
||||
void findEach(Consumer<T> consumer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ package io.ebean;
|
||||
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.config.DocStoreConfig;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.DocStoreConfig;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.Connection;
|
||||
@@ -59,6 +59,14 @@ public interface Transaction extends AutoCloseable {
|
||||
*/
|
||||
void register(TransactionCallback callback);
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL - turn on automatic persistence of dirty beans and batchMode true.
|
||||
* <p>
|
||||
* With this turned on beans that are dirty in the persistence context
|
||||
* are automatically persisted on flush() and commit().
|
||||
*/
|
||||
void setAutoPersistUpdates(boolean autoPersistUpdates);
|
||||
|
||||
/**
|
||||
* Set a label on the transaction.
|
||||
* <p>
|
||||
@@ -339,15 +347,12 @@ public interface Transaction extends AutoCloseable {
|
||||
* The batch is automatically flushed when it hits the batch size and also when we
|
||||
* execute queries or when we mix UpdateSql and CallableSql with save and delete of
|
||||
* beans.
|
||||
* </p>
|
||||
* <p>
|
||||
* We use {@link #flush()} to explicitly flush the batch and we can use
|
||||
* {@link #setFlushOnQuery(boolean)} and {@link #setFlushOnMixed(boolean)}
|
||||
* to control the automatic flushing behaviour.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example: batch processing of CallableSql executing every 10 rows
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
@@ -392,14 +397,11 @@ public interface Transaction extends AutoCloseable {
|
||||
* <p>
|
||||
* This only takes effect when batch mode on the transaction has not already meant that
|
||||
* JDBC batch mode is being used.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is useful when the single save() or delete() cascades. For example, inserting a 'master' cascades
|
||||
* and inserts a collection of 'detail' beans. The detail beans can be inserted using JDBC batch.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is effectively already turned on for all platforms apart from older Sql Server.
|
||||
* </p>
|
||||
*
|
||||
* @param batchMode the batch mode to use per save(), insert(), update() or delete()
|
||||
* @see io.ebean.config.DatabaseConfig#setPersistBatchOnCascade(PersistBatch)
|
||||
@@ -422,15 +424,19 @@ public interface Transaction extends AutoCloseable {
|
||||
int getBatchSize();
|
||||
|
||||
/**
|
||||
* Specify if you want batched inserts to use getGeneratedKeys.
|
||||
* Specify if we want batched inserts to use getGeneratedKeys.
|
||||
* <p>
|
||||
* By default batched inserts will try to use getGeneratedKeys if it is
|
||||
* supported by the underlying jdbc driver and database.
|
||||
* </p>
|
||||
* <p>
|
||||
* You may want to turn getGeneratedKeys off when you are inserting a large
|
||||
* number of objects and you don't care about getting back the ids.
|
||||
* </p>
|
||||
* We want to turn off getGeneratedKeys when we are inserting a large
|
||||
* number of objects and we don't care about getting back the ids. In this
|
||||
* way we avoid the extra cost of getting back the generated id values
|
||||
* from the database.
|
||||
* <p>
|
||||
* Note that when we do turn off getGeneratedKeys then we have the limitation
|
||||
* that after a bean has been inserted we are unable to then mutate the bean
|
||||
* and update it in the same transaction as we have not obtained it's id value.
|
||||
*/
|
||||
void setGetGeneratedKeys(boolean getGeneratedKeys);
|
||||
|
||||
@@ -449,13 +455,11 @@ public interface Transaction extends AutoCloseable {
|
||||
* <p>
|
||||
* If you want to execute both WITHOUT having the batch automatically flush
|
||||
* you need to call this with batchFlushOnMixed = false.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that UpdateSql and CallableSql are ALWAYS executed first (before the
|
||||
* beans are executed). This is because the UpdateSql and CallableSql have
|
||||
* already been bound to their PreparedStatements. The beans on the other hand
|
||||
* have a 2 step process (delayed binding).
|
||||
* </p>
|
||||
*/
|
||||
void setFlushOnMixed(boolean batchFlushOnMixed);
|
||||
|
||||
@@ -473,7 +477,6 @@ public interface Transaction extends AutoCloseable {
|
||||
* <p>
|
||||
* Calling this method with batchFlushOnQuery = false means that you can
|
||||
* execute a query and the batch will not be automatically flushed.
|
||||
* </p>
|
||||
*/
|
||||
void setFlushOnQuery(boolean batchFlushOnQuery);
|
||||
|
||||
@@ -490,7 +493,6 @@ public interface Transaction extends AutoCloseable {
|
||||
* should be flushed prior to executing a query.
|
||||
* <p>
|
||||
* The default is for this to be true.
|
||||
* </p>
|
||||
*/
|
||||
boolean isFlushOnQuery();
|
||||
|
||||
@@ -507,7 +509,6 @@ public interface Transaction extends AutoCloseable {
|
||||
* flush the batch if you like.
|
||||
* <p>
|
||||
* Flushing occurs automatically when:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>the batch size is reached</li>
|
||||
* <li>A query is executed on the same transaction</li>
|
||||
@@ -519,11 +520,11 @@ public interface Transaction extends AutoCloseable {
|
||||
void flush() throws PersistenceException;
|
||||
|
||||
/**
|
||||
* This is a synonym for flush() and will be deprecated.
|
||||
* Deprecated - migrate to flush().
|
||||
* <p>
|
||||
* flush() is preferred as it matches the JPA flush() method.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
void flushBatch() throws PersistenceException;
|
||||
|
||||
/**
|
||||
@@ -533,29 +534,32 @@ public interface Transaction extends AutoCloseable {
|
||||
* commit() rollback() and end() methods on the Transaction should still be
|
||||
* used. Calling these methods on the Connection would be a big no no unless
|
||||
* you know what you are doing.
|
||||
* </p>
|
||||
* <p>
|
||||
* Examples of when a developer may wish to use the connection directly are:
|
||||
* Savepoints, advanced CLOB BLOB use and advanced stored procedure calls.
|
||||
* </p>
|
||||
*/
|
||||
Connection getConnection();
|
||||
Connection connection();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to connection().
|
||||
*/
|
||||
@Deprecated
|
||||
default Connection getConnection() {
|
||||
return connection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add table modification information to the TransactionEvent.
|
||||
* <p>
|
||||
* Use this in conjunction with getConnection() and raw JDBC.
|
||||
* </p>
|
||||
* <p>
|
||||
* This effectively informs Ebean of the data that has been changed by the
|
||||
* transaction and this information is normally automatically handled by Ebean
|
||||
* when you save entity beans or use UpdateSql etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you use raw JDBC then you can use this method to inform Ebean for the
|
||||
* tables that have been modified. Ebean uses this information to keep its
|
||||
* caches in synch and maintain text indexes.
|
||||
* </p>
|
||||
*/
|
||||
void addModification(String tableName, boolean inserts, boolean updates, boolean deletes);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebean;
|
||||
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.annotation.TxOption;
|
||||
import io.ebean.annotation.TxType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -33,6 +34,8 @@ public final class TxScope {
|
||||
|
||||
private TxIsolation isolation;
|
||||
|
||||
private TxOption autoPersistUpdates;
|
||||
|
||||
private PersistBatch batch;
|
||||
|
||||
private PersistBatch batchOnCascade;
|
||||
@@ -123,6 +126,13 @@ public final class TxScope {
|
||||
+ "] serverName[" + serverName + "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the AutoPersistUpdates mode as a nullable Boolean.
|
||||
*/
|
||||
public Boolean getAutoPersistUpdates() {
|
||||
return autoPersistUpdates == null ? null : autoPersistUpdates.asBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if PersistBatch has been set.
|
||||
*/
|
||||
@@ -176,6 +186,14 @@ public final class TxScope {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the autoPersistUpdates mode.
|
||||
*/
|
||||
public TxScope setAutoPersistUpdates(TxOption autoPersistUpdates) {
|
||||
this.autoPersistUpdates = autoPersistUpdates;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction profile id.
|
||||
*/
|
||||
|
||||
@@ -13,23 +13,23 @@ package io.ebean;
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* ...
|
||||
* @NamedUpdates(value = {
|
||||
* @NamedUpdate(
|
||||
* @NamedUpdates(value = {
|
||||
* @NamedUpdate(
|
||||
* name = "setTitle",
|
||||
* notifyCache = false,
|
||||
* update = "update topic set title = :title, postCount = :count where id = :id"),
|
||||
* @NamedUpdate(
|
||||
* @NamedUpdate(
|
||||
* name = "setPostCount",
|
||||
* notifyCache = false,
|
||||
* update = "update f_topic set post_count = :postCount where id = :id"),
|
||||
* @NamedUpdate(
|
||||
* @NamedUpdate(
|
||||
* name = "incrementPostCount",
|
||||
* notifyCache = false,
|
||||
* update = "update Topic set postCount = postCount + 1 where id = :id")
|
||||
* //update = "update f_topic set post_count = post_count + 1 where id = :id")
|
||||
* })
|
||||
* @Entity
|
||||
* @Table(name = "f_topic")
|
||||
* @Entity
|
||||
* @Table(name = "f_topic")
|
||||
* public class Topic {
|
||||
* ...
|
||||
* }
|
||||
|
||||
@@ -13,12 +13,10 @@ import java.util.Set;
|
||||
* from the Map Set or List. The purpose of gathering the additions and removals
|
||||
* is to support persisting ManyToMany objects. The additions and removals
|
||||
* become inserts and deletes from the intersection table.
|
||||
* </p>
|
||||
* <p>
|
||||
* Technically this is <em>NOT</em> an extension of
|
||||
* <em>java.util.Collection</em>. The reason being that java.util.Map is not a
|
||||
* Collection. I realise this makes this name confusing so I apologise for that.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanCollection<E> extends Serializable {
|
||||
|
||||
@@ -68,7 +66,6 @@ public interface BeanCollection<E> extends Serializable {
|
||||
* Return true if the collection is uninitialised or is empty without any held modifications.
|
||||
* <p>
|
||||
* Returning true means can safely skip cascade save for this bean collection.
|
||||
* </p>
|
||||
*/
|
||||
boolean isSkipSave();
|
||||
|
||||
@@ -93,7 +90,6 @@ public interface BeanCollection<E> extends Serializable {
|
||||
* <p>
|
||||
* That is, if the collection was not loaded due to filterMany predicates etc
|
||||
* then make sure the collection is set to empty.
|
||||
* </p>
|
||||
*/
|
||||
boolean checkEmptyLazyLoad();
|
||||
|
||||
@@ -136,10 +132,7 @@ public interface BeanCollection<E> extends Serializable {
|
||||
boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Add the bean to the collection.
|
||||
* <p>
|
||||
* This is disallowed for BeanMap.
|
||||
* </p>
|
||||
* Add the bean to the collection. This is disallowed for BeanMap.
|
||||
*/
|
||||
void internalAdd(Object bean);
|
||||
|
||||
@@ -168,7 +161,6 @@ public interface BeanCollection<E> extends Serializable {
|
||||
* Map.Entry.
|
||||
* <p>
|
||||
* For maps this returns the entrySet as we need the keys of the map.
|
||||
* </p>
|
||||
*/
|
||||
Collection<?> getActualEntries();
|
||||
|
||||
@@ -185,6 +177,11 @@ public interface BeanCollection<E> extends Serializable {
|
||||
*/
|
||||
boolean isReference();
|
||||
|
||||
/**
|
||||
* Return true if the collection is modify listening and has modifications.
|
||||
*/
|
||||
boolean hasModifications();
|
||||
|
||||
/**
|
||||
* Set modify listening on or off. This is used to keep track of objects that
|
||||
* have been added to or removed from the list set or map.
|
||||
@@ -192,7 +189,6 @@ public interface BeanCollection<E> extends Serializable {
|
||||
* This is required only for ManyToMany collections. The additions and
|
||||
* deletions are used to insert or delete entries from the intersection table.
|
||||
* Otherwise modifyListening is false.
|
||||
* </p>
|
||||
*/
|
||||
void setModifyListening(ModifyListenMode modifyListenMode);
|
||||
|
||||
@@ -206,7 +202,6 @@ public interface BeanCollection<E> extends Serializable {
|
||||
* <p>
|
||||
* This will potentially end up as an insert into a intersection table for a
|
||||
* ManyToMany.
|
||||
* </p>
|
||||
*/
|
||||
void modifyAddition(E bean);
|
||||
|
||||
@@ -215,7 +210,6 @@ public interface BeanCollection<E> extends Serializable {
|
||||
* <p>
|
||||
* This will potentially end up as an delete from an intersection table for a
|
||||
* ManyToMany.
|
||||
* </p>
|
||||
*/
|
||||
void modifyRemoval(Object bean);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ public interface BeanCollectionLoader {
|
||||
/**
|
||||
* Return the name of the associated Database.
|
||||
*/
|
||||
String getName();
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Invoke the lazy loading for this bean collection.
|
||||
|
||||
@@ -27,17 +27,6 @@ public interface EntityBean extends Serializable {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the enhancement marker value.
|
||||
* <p>
|
||||
* This is the class name of the enhanced class and used to check that all
|
||||
* entity classes are enhanced (specifically not just a super class).
|
||||
* </p>
|
||||
*/
|
||||
default String _ebean_getMarker() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new entity bean instance.
|
||||
*/
|
||||
|
||||
@@ -32,39 +32,52 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
private static final int STATE_REFERENCE = 1;
|
||||
private static final int STATE_LOADED = 2;
|
||||
|
||||
private transient final ReentrantLock lock = new ReentrantLock(false);
|
||||
/**
|
||||
* Used when a bean is partially filled.
|
||||
*/
|
||||
private static final byte FLAG_LOADED_PROP = 1;
|
||||
private static final byte FLAG_CHANGED_PROP = 2;
|
||||
private static final byte FLAG_CHANGEDLOADED_PROP = 3;
|
||||
/**
|
||||
* Flags indicating if a property is a dirty embedded bean. Used to distinguish
|
||||
* between an embedded bean being completely overwritten and one of its
|
||||
* embedded properties being made dirty.
|
||||
*/
|
||||
private static final byte FLAG_EMBEDDED_DIRTY = 4;
|
||||
/**
|
||||
* Flags indicating if a property is a dirty embedded bean. Used to distinguish
|
||||
* between an embedded bean being completely overwritten and one of its
|
||||
* embedded properties being made dirty.
|
||||
*/
|
||||
private static final byte FLAG_ORIG_VALUE_SET = 8;
|
||||
|
||||
/**
|
||||
* Flags indicating if the mutable hash is set.
|
||||
*/
|
||||
private static final byte FLAG_MUTABLE_HASH_SET = 16;
|
||||
|
||||
private transient final ReentrantLock lock = new ReentrantLock();
|
||||
private transient NodeUsageCollector nodeUsageCollector;
|
||||
|
||||
private transient PersistenceContext persistenceContext;
|
||||
|
||||
private transient BeanLoader beanLoader;
|
||||
|
||||
private transient PreGetterCallback preGetterCallback;
|
||||
|
||||
private String ebeanServerName;
|
||||
|
||||
private boolean deletedFromCollection;
|
||||
|
||||
/**
|
||||
* The actual entity bean that 'owns' this intercept.
|
||||
*/
|
||||
private final EntityBean owner;
|
||||
|
||||
private EntityBean embeddedOwner;
|
||||
private int embeddedOwnerIndex;
|
||||
|
||||
/**
|
||||
* One of NEW, REF, UPD.
|
||||
*/
|
||||
private int state;
|
||||
|
||||
private boolean forceUpdate;
|
||||
|
||||
private boolean readOnly;
|
||||
|
||||
private boolean dirty;
|
||||
|
||||
/**
|
||||
* Flag set to disable lazy loading - typically for SQL "report" type entity beans.
|
||||
*/
|
||||
@@ -74,41 +87,26 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* Flag set when lazy loading failed due to the underlying bean being deleted in the DB.
|
||||
*/
|
||||
private boolean lazyLoadFailure;
|
||||
|
||||
/**
|
||||
* Used when a bean is partially filled.
|
||||
*/
|
||||
private static final byte FLAG_LOADED_PROP = 1;
|
||||
|
||||
/**
|
||||
* Set of changed properties.
|
||||
*/
|
||||
private static final byte FLAG_CHANGED_PROP = 2;
|
||||
|
||||
/**
|
||||
* Flags indicating if a property is a dirty embedded bean. Used to distinguish
|
||||
* between an embedded bean being completely overwritten and one of its
|
||||
* embedded properties being made dirty.
|
||||
*/
|
||||
private static final byte FLAG_EMBEDDED_DIRTY = 4;
|
||||
|
||||
/**
|
||||
* Flags indicating if a property is a dirty embedded bean. Used to distinguish
|
||||
* between an embedded bean being completely overwritten and one of its
|
||||
* embedded properties being made dirty.
|
||||
*/
|
||||
private static final byte FLAG_ORIG_VALUE_SET = 8;
|
||||
|
||||
private final byte[] flags;
|
||||
|
||||
private boolean fullyLoadedBean;
|
||||
private boolean loadedFromCache;
|
||||
private final byte[] flags;
|
||||
private Object[] origValues;
|
||||
private Exception[] loadErrors;
|
||||
private int lazyLoadProperty = -1;
|
||||
private Object ownerId;
|
||||
private int sortOrder;
|
||||
|
||||
/**
|
||||
* Holds information of json loaded jackson beans (e.g. the original json or checksum).
|
||||
*/
|
||||
private MutableValueInfo[] mutableInfo;
|
||||
|
||||
/**
|
||||
* Holds json content determined at point of dirty check.
|
||||
* Stored here on dirty check such that we only convert to json once.
|
||||
*/
|
||||
private MutableValueNext[] mutableNext;
|
||||
|
||||
/**
|
||||
* Create a intercept with a given entity.
|
||||
*/
|
||||
@@ -246,6 +244,17 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* if any embedded beans are either new or dirty (and hence need saving).
|
||||
*/
|
||||
public boolean isDirty() {
|
||||
if (dirty) {
|
||||
return true;
|
||||
}
|
||||
if (mutableInfo != null) {
|
||||
for (int i = 0; i < mutableInfo.length; i++) {
|
||||
if (mutableInfo[i] != null && !mutableInfo[i].isEqualToObject(owner._ebean_getField(i))) {
|
||||
dirty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dirty;
|
||||
}
|
||||
|
||||
@@ -386,8 +395,18 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
this.owner._ebean_setEmbeddedLoaded();
|
||||
this.lazyLoadProperty = -1;
|
||||
this.origValues = null;
|
||||
// after save, transfer the mutable next values back to mutable info
|
||||
if (mutableNext != null) {
|
||||
for (int i = 0; i < mutableNext.length; i++) {
|
||||
MutableValueNext next = mutableNext[i];
|
||||
if (next != null) {
|
||||
mutableInfo(i, next.info());
|
||||
}
|
||||
}
|
||||
}
|
||||
this.mutableNext = null;
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
flags[i] &= ~(FLAG_CHANGED_PROP + FLAG_ORIG_VALUE_SET);
|
||||
flags[i] &= ~(FLAG_CHANGED_PROP | FLAG_ORIG_VALUE_SET);
|
||||
}
|
||||
this.dirty = false;
|
||||
}
|
||||
@@ -460,6 +479,10 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* Return the original value that was changed via an update.
|
||||
*/
|
||||
public Object getOrigValue(int propertyIndex) {
|
||||
if ((flags[propertyIndex] & (FLAG_ORIG_VALUE_SET | FLAG_MUTABLE_HASH_SET)) == FLAG_MUTABLE_HASH_SET) {
|
||||
// mutable hash set, but not ORIG_VALUE
|
||||
setOriginalValue(propertyIndex, mutableInfo[propertyIndex].get());
|
||||
}
|
||||
if (origValues == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -494,7 +517,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* Return the number of properties.
|
||||
*/
|
||||
public int getPropertyLength() {
|
||||
return owner._ebean_getPropertyNames().length;
|
||||
return flags.length;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -569,6 +592,10 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
flags[propertyIndex] |= FLAG_CHANGED_PROP;
|
||||
}
|
||||
|
||||
private void setChangeLoaded(int propertyIndex) {
|
||||
flags[propertyIndex] |= FLAG_CHANGEDLOADED_PROP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set that an embedded bean has had one of its properties changed.
|
||||
*/
|
||||
@@ -578,7 +605,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
|
||||
private void setOriginalValue(int propertyIndex, Object value) {
|
||||
if (origValues == null) {
|
||||
origValues = new Object[owner._ebean_getPropertyNames().length];
|
||||
origValues = new Object[flags.length];
|
||||
}
|
||||
if ((flags[propertyIndex] & FLAG_ORIG_VALUE_SET) == 0) {
|
||||
flags[propertyIndex] |= FLAG_ORIG_VALUE_SET;
|
||||
@@ -591,7 +618,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
*/
|
||||
private void setOriginalValueForce(int propertyIndex, Object value) {
|
||||
if (origValues == null) {
|
||||
origValues = new Object[owner._ebean_getPropertyNames().length];
|
||||
origValues = new Object[flags.length];
|
||||
}
|
||||
origValues[propertyIndex] = value;
|
||||
}
|
||||
@@ -652,7 +679,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public void addDirtyPropertyNames(Set<String> props, String prefix) {
|
||||
int len = getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
|
||||
if (isChangedProp(i)) {
|
||||
// the property has been changed on this bean
|
||||
props.add((prefix == null ? getProperty(i) : prefix + getProperty(i)));
|
||||
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
|
||||
@@ -670,7 +697,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
String[] names = owner._ebean_getPropertyNames();
|
||||
int len = getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
|
||||
if (isChangedProp(i)) {
|
||||
if (propertyNames.contains(names[i])) {
|
||||
return true;
|
||||
}
|
||||
@@ -698,7 +725,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public void addDirtyPropertyValues(Map<String, ValuePair> dirtyValues, String prefix) {
|
||||
int len = getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
|
||||
if (isChangedProp(i)) {
|
||||
// the property has been changed on this bean
|
||||
String propName = (prefix == null ? getProperty(i) : prefix + getProperty(i));
|
||||
Object newVal = owner._ebean_getField(i);
|
||||
@@ -720,7 +747,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public void addDirtyPropertyValues(BeanDiffVisitor visitor) {
|
||||
int len = getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
|
||||
if (isChangedProp(i)) {
|
||||
// the property has been changed on this bean
|
||||
Object newVal = owner._ebean_getField(i);
|
||||
Object oldVal = getOrigValue(i);
|
||||
@@ -755,7 +782,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
int len = getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
|
||||
if ((flags[i] & FLAG_CHANGED_PROP) != 0) { // we do not check against mutablecontent here.
|
||||
sb.append(i).append(',');
|
||||
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
|
||||
// an embedded property has been changed - recurse
|
||||
@@ -816,7 +843,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
// For stand alone reference bean or after deserialisation lazy load
|
||||
// using the ebeanServer. Synchronise only on the bean.
|
||||
loadBeanInternal(loadProperty, database.getPluginApi().beanLoader());
|
||||
loadBeanInternal(loadProperty, database.pluginApi().beanLoader());
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
@@ -931,10 +958,14 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* OneToMany and ManyToMany only set loaded state.
|
||||
*/
|
||||
public void preSetterMany(boolean interceptField, int propertyIndex, Object oldValue, Object newValue) {
|
||||
if (readOnly) {
|
||||
throw new IllegalStateException("This bean is readOnly");
|
||||
if (state == STATE_NEW) {
|
||||
setLoadedProperty(propertyIndex);
|
||||
} else {
|
||||
if (readOnly) {
|
||||
throw new IllegalStateException("This bean is readOnly");
|
||||
}
|
||||
setChangeLoaded(propertyIndex);
|
||||
}
|
||||
setLoadedProperty(propertyIndex);
|
||||
}
|
||||
|
||||
private void setChangedPropertyValue(int propertyIndex, boolean setDirtyState, Object origValue) {
|
||||
@@ -973,7 +1004,6 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check for primitive boolean.
|
||||
*/
|
||||
@@ -1123,7 +1153,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
*/
|
||||
public void setLoadError(int propertyIndex, Exception t) {
|
||||
if (loadErrors == null) {
|
||||
loadErrors = new Exception[owner._ebean_getPropertyNames().length];
|
||||
loadErrors = new Exception[flags.length];
|
||||
}
|
||||
loadErrors[propertyIndex] = t;
|
||||
flags[propertyIndex] |= FLAG_LOADED_PROP;
|
||||
@@ -1149,4 +1179,61 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private boolean isChangedProp(int i) {
|
||||
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
|
||||
return true;
|
||||
} else if (mutableInfo == null || mutableInfo[i] == null || mutableInfo[i].isEqualToObject(owner._ebean_getField(i))) {
|
||||
return false;
|
||||
} else {
|
||||
// mark for change
|
||||
flags[i] |= FLAG_CHANGED_PROP;
|
||||
dirty = true; // this makes the bean automatically dirty!
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MutableValueInfo for the given property or null.
|
||||
*/
|
||||
public MutableValueInfo mutableInfo(int propertyIndex) {
|
||||
return mutableInfo == null ? null : mutableInfo[propertyIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the MutableValueInfo for the given property.
|
||||
*/
|
||||
public void mutableInfo(int propertyIndex, MutableValueInfo info) {
|
||||
if (mutableInfo == null) {
|
||||
mutableInfo = new MutableValueInfo[flags.length];
|
||||
}
|
||||
flags[propertyIndex] |= FLAG_MUTABLE_HASH_SET;
|
||||
mutableInfo[propertyIndex] = info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dirty detection set the next mutable property content and info .
|
||||
* <p>
|
||||
* Set here as the mutable property dirty detection is based on json content comparison.
|
||||
* We only want to perform the json serialisation once so storing it here as part of
|
||||
* dirty detection so that we can get it back to bind in insert or update etc.
|
||||
*/
|
||||
public void mutableNext(int propertyIndex, MutableValueNext next) {
|
||||
if (mutableNext == null) {
|
||||
mutableNext = new MutableValueNext[flags.length];
|
||||
}
|
||||
mutableNext[propertyIndex] = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the 'next' mutable info returning the content that was obtained via dirty detection.
|
||||
*/
|
||||
public String mutableNext(int propertyIndex) {
|
||||
if (mutableNext == null) {
|
||||
return null;
|
||||
}
|
||||
final MutableValueNext next = mutableNext[propertyIndex];
|
||||
return next != null ? next.content() : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* Holds information on mutable values (like plain beans stored as json).
|
||||
* <p>
|
||||
* Used internally in EntityBeanIntercept for dirty detection on mutable values.
|
||||
* Typically, mutation detection is based on a hash/checksum of json content or the
|
||||
* original json content itself.
|
||||
* <p>
|
||||
* Refer to the mapping options {@code @DbJson(mutationDetection)}.
|
||||
*/
|
||||
public interface MutableValueInfo {
|
||||
|
||||
/**
|
||||
* Compares the given json returning null if deemed unchanged or returning
|
||||
* the MutableValueNext to use if deemed dirty/changed.
|
||||
* <p>
|
||||
* Returning MutableValueNext allows an implementation based on hash/checksum
|
||||
* to only perform that computation once.
|
||||
*
|
||||
* @return Null if deemed unchanged or the MutableValueNext if deemed changed.
|
||||
*/
|
||||
MutableValueNext nextDirty(String json);
|
||||
|
||||
/**
|
||||
* Compares the given object to an internal value.
|
||||
* <p>
|
||||
* This is used to support changelog/beanState. The implementation can serialize the
|
||||
* object into json form and compare it against the original json.
|
||||
*/
|
||||
boolean isEqualToObject(Object obj);
|
||||
|
||||
/**
|
||||
* Creates a new instance from the internal json string.
|
||||
* <p>
|
||||
* This is used to provide an original/old value for change logging / persist listeners.
|
||||
* This is only available for properties that have {@code @DbJson(keepSource=true)}.
|
||||
*/
|
||||
default Object get() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* Represents a next value to use for mutable content properties (DbJson with jackson beans).
|
||||
*/
|
||||
public interface MutableValueNext {
|
||||
|
||||
/**
|
||||
* Return the next content to use. Provided such that we serialise to json once.
|
||||
*/
|
||||
String content();
|
||||
|
||||
/**
|
||||
* Return the next MutableValueInfo to use after an update.
|
||||
*/
|
||||
MutableValueInfo info();
|
||||
}
|
||||
@@ -5,7 +5,6 @@ package io.ebean.bean;
|
||||
* <p>
|
||||
* This is used to ensure only one instance for a given entity type and id is
|
||||
* used to build object graphs from queries and lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
public interface PersistenceContext {
|
||||
|
||||
@@ -20,7 +19,6 @@ public interface PersistenceContext {
|
||||
* <p>
|
||||
* Returns an existing entity bean (if one is already there) and otherwise
|
||||
* returns null.
|
||||
* </p>
|
||||
*/
|
||||
Object putIfAbsent(Class<?> rootType, Object id, Object bean);
|
||||
|
||||
@@ -82,7 +80,6 @@ public interface PersistenceContext {
|
||||
* <p>
|
||||
* If a bean has been deleted then for the same persistence context is should
|
||||
* not be able to be fetched from persistence context or L2 cache.
|
||||
* </p>
|
||||
*/
|
||||
class WithOption {
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
public abstract class SingleBeanLoader implements BeanLoader {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
protected final Database database;
|
||||
|
||||
@@ -20,7 +20,7 @@ public abstract class SingleBeanLoader implements BeanLoader {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return database.getName();
|
||||
return database.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,7 +39,7 @@ public abstract class SingleBeanLoader implements BeanLoader {
|
||||
|
||||
@Override
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
database.getPluginApi().loadBeanL2(ebi);
|
||||
database.pluginApi().loadBeanL2(ebi);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public abstract class SingleBeanLoader implements BeanLoader {
|
||||
|
||||
@Override
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
database.getPluginApi().loadBeanRef(ebi);
|
||||
database.pluginApi().loadBeanRef(ebi);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public abstract class SingleBeanLoader implements BeanLoader {
|
||||
|
||||
@Override
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
database.getPluginApi().loadBean(ebi);
|
||||
database.pluginApi().loadBean(ebi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,7 @@ import java.util.Set;
|
||||
public class QueryCacheEntry {
|
||||
|
||||
private final Object value;
|
||||
|
||||
private final Set<String> dependentTables;
|
||||
|
||||
private final long timestamp;
|
||||
|
||||
/**
|
||||
|
||||
+19
-3
@@ -10,17 +10,17 @@ import java.util.Set;
|
||||
* Represents part of the "L2" server side cache.
|
||||
* <p>
|
||||
* This is used to cache beans or query results (bean collections).
|
||||
* </p>
|
||||
* <p>
|
||||
* There are 2 ServerCache's for each bean type. One is used as the 'bean cache'
|
||||
* which holds beans of a given type. The other is the 'query cache' holding
|
||||
* query results for a given type.
|
||||
* </p>
|
||||
*/
|
||||
public interface ServerCache {
|
||||
|
||||
/**
|
||||
* Get values for many keys.
|
||||
*/
|
||||
default Map<Object, Object> getAll(Set<Object> keys) {
|
||||
|
||||
Map<Object, Object> map = new LinkedHashMap<>();
|
||||
for (Object key : keys) {
|
||||
Object value = get(key);
|
||||
@@ -73,6 +73,14 @@ public interface ServerCache {
|
||||
/**
|
||||
* Return the hit ratio the cache is currently getting.
|
||||
*/
|
||||
default int hitRatio() {
|
||||
return getHitRatio();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated migrate to hitRatio().
|
||||
*/
|
||||
@Deprecated
|
||||
int getHitRatio();
|
||||
|
||||
/**
|
||||
@@ -80,6 +88,14 @@ public interface ServerCache {
|
||||
*
|
||||
* @param reset if true the statistics are reset.
|
||||
*/
|
||||
default ServerCacheStatistics statistics(boolean reset) {
|
||||
return getStatistics(reset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated migrate to statistics().
|
||||
*/
|
||||
@Deprecated
|
||||
ServerCacheStatistics getStatistics(boolean reset);
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,15 @@ public interface ServerCacheManager {
|
||||
* rather than background processing.
|
||||
* </p>
|
||||
*/
|
||||
boolean isLocalL2Caching();
|
||||
boolean localL2Caching();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to localL2Caching().
|
||||
*/
|
||||
@Deprecated
|
||||
default boolean isLocalL2Caching() {
|
||||
return localL2Caching();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the cache regions.
|
||||
@@ -36,37 +44,78 @@ public interface ServerCacheManager {
|
||||
*
|
||||
* @param regions A region name or comma delimited list of region names.
|
||||
*/
|
||||
void setEnabledRegions(String regions);
|
||||
void enabledRegions(String regions);
|
||||
|
||||
/**
|
||||
* Deprecated migrate to enabledRegions().
|
||||
*/
|
||||
@Deprecated
|
||||
default void setEnabledRegions(String regions) {
|
||||
enabledRegions(regions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable all the cache regions.
|
||||
*/
|
||||
void setAllRegionsEnabled(boolean enabled);
|
||||
void allRegionsEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Return the cache region by name. Typically to enable or disable the region.
|
||||
* Deprecated migrate to allRegionsEnabled().
|
||||
*/
|
||||
ServerCacheRegion getRegion(String name);
|
||||
@Deprecated
|
||||
default void setAllRegionsEnabled(boolean enabled) {
|
||||
allRegionsEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache region by name. Typically, to enable or disable the region.
|
||||
*/
|
||||
ServerCacheRegion region(String name);
|
||||
|
||||
@Deprecated
|
||||
default ServerCacheRegion getRegion(String name) {
|
||||
return region(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache for mapping natural keys to id values.
|
||||
*/
|
||||
ServerCache getNaturalKeyCache(Class<?> beanType);
|
||||
ServerCache naturalKeyCache(Class<?> beanType);
|
||||
|
||||
@Deprecated
|
||||
default ServerCache getNaturalKeyCache(Class<?> beanType) {
|
||||
return naturalKeyCache(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache for beans of a particular type.
|
||||
*/
|
||||
ServerCache getBeanCache(Class<?> beanType);
|
||||
ServerCache beanCache(Class<?> beanType);
|
||||
|
||||
@Deprecated
|
||||
default ServerCache getBeanCache(Class<?> beanType) {
|
||||
return beanCache(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache for associated many properties of a bean type.
|
||||
*/
|
||||
ServerCache getCollectionIdsCache(Class<?> beanType, String propertyName);
|
||||
ServerCache collectionIdsCache(Class<?> beanType, String propertyName);
|
||||
|
||||
@Deprecated
|
||||
default ServerCache getCollectionIdsCache(Class<?> beanType, String propertyName) {
|
||||
return collectionIdsCache(beanType, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache for query results of a particular type of bean.
|
||||
*/
|
||||
ServerCache getQueryCache(Class<?> beanType);
|
||||
ServerCache queryCache(Class<?> beanType);
|
||||
|
||||
@Deprecated
|
||||
default ServerCache getQueryCache(Class<?> beanType) {
|
||||
return queryCache(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* This clears both the bean and query cache for a given type.
|
||||
|
||||
@@ -18,7 +18,6 @@ public class ServerCacheOptions {
|
||||
* Construct with no set options.
|
||||
*/
|
||||
public ServerCacheOptions() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,7 +72,6 @@ public class ServerCacheOptions {
|
||||
* Return a copy of this object.
|
||||
*/
|
||||
public ServerCacheOptions copy() {
|
||||
|
||||
ServerCacheOptions copy = new ServerCacheOptions();
|
||||
copy.maxSize = maxSize;
|
||||
copy.maxIdleSecs = maxIdleSecs;
|
||||
|
||||
@@ -8,7 +8,15 @@ public interface ServerCacheRegion {
|
||||
/**
|
||||
* Return the region name.
|
||||
*/
|
||||
String getName();
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Deprecated migrate to name().
|
||||
*/
|
||||
@Deprecated
|
||||
default String getName() {
|
||||
return name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the cache region is enabled.
|
||||
|
||||
@@ -16,7 +16,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
private static final long serialVersionUID = 3365725236140187588L;
|
||||
|
||||
protected final ReentrantLock lock = new ReentrantLock(false);
|
||||
protected final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
protected boolean readOnly;
|
||||
|
||||
@@ -63,7 +63,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
*/
|
||||
AbstractBeanCollection(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
|
||||
this.loader = loader;
|
||||
this.ebeanServerName = loader.getName();
|
||||
this.ebeanServerName = loader.name();
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.readOnly = ownerBean != null && ownerBean._ebean_getIntercept().isReadOnly();
|
||||
@@ -111,7 +111,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
public void setLoader(BeanCollectionLoader loader) {
|
||||
this.registeredWithLoadContext = true;
|
||||
this.loader = loader;
|
||||
this.ebeanServerName = loader.getName();
|
||||
this.ebeanServerName = loader.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -135,6 +135,11 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
// Support for modify additions deletions etc - ManyToMany
|
||||
// ---------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public boolean hasModifications() {
|
||||
return modifyHolder != null && modifyHolder.hasModifications();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModifyListenMode getModifyListening() {
|
||||
return modifyListenMode;
|
||||
@@ -145,7 +150,6 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
*/
|
||||
@Override
|
||||
public void setModifyListening(ModifyListenMode mode) {
|
||||
|
||||
this.modifyListenMode = mode;
|
||||
this.modifyListening = mode != null && ModifyListenMode.NONE != mode;
|
||||
if (modifyListening) {
|
||||
|
||||
@@ -87,7 +87,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
|
||||
@Override
|
||||
public void internalAddWithCheck(Object bean) {
|
||||
if (list == null || !containsInstance(bean)) {
|
||||
if (list == null || bean == null || !containsInstance(bean)) {
|
||||
internalAdd(bean);
|
||||
}
|
||||
}
|
||||
@@ -198,10 +198,9 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
}
|
||||
if (list == null) {
|
||||
sb.append("deferred ");
|
||||
|
||||
} else {
|
||||
sb.append("size[").append(list.size()).append("] ");
|
||||
sb.append("list").append(list).append("");
|
||||
sb.append("list").append(list);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
}
|
||||
|
||||
public void internalPutWithCheck(Object key, Object bean) {
|
||||
if (map == null || !map.containsKey(key)) {
|
||||
if (map == null || key == null || !map.containsKey(key)) {
|
||||
internalPut(key, bean);
|
||||
}
|
||||
}
|
||||
@@ -175,10 +175,6 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
|
||||
/**
|
||||
* Returns the map entrySet.
|
||||
* <p>
|
||||
* This is because the key values may need to be set against the details (so
|
||||
* they don't need to be set twice).
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public Collection<?> getActualEntries() {
|
||||
@@ -194,7 +190,6 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
}
|
||||
if (map == null) {
|
||||
sb.append("deferred ");
|
||||
|
||||
} else {
|
||||
sb.append("size[").append(map.size()).append("]");
|
||||
sb.append(" map").append(map);
|
||||
@@ -243,17 +238,12 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public Set<Entry<K, E>> entrySet() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return Collections.unmodifiableSet(map.entrySet());
|
||||
}
|
||||
if (modifyListening) {
|
||||
Set<Entry<K, E>> s = map.entrySet();
|
||||
return new ModifySet(this, s);
|
||||
}
|
||||
return map.entrySet();
|
||||
return modifyListening ? new ModifyEntrySet<>(this, map.entrySet()) : map.entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -274,8 +264,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
if (isReadOnly()) {
|
||||
return Collections.unmodifiableSet(map.keySet());
|
||||
}
|
||||
// we don't really care about modifications to the ketSet?
|
||||
return map.keySet();
|
||||
return modifyListening ? new ModifyKeySet<>(this, map.keySet()) : map.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -346,11 +335,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
if (isReadOnly()) {
|
||||
return Collections.unmodifiableCollection(map.values());
|
||||
}
|
||||
if (modifyListening) {
|
||||
Collection<E> c = map.values();
|
||||
return new ModifyCollection<>(this, c);
|
||||
}
|
||||
return map.values();
|
||||
return modifyListening ? new ModifyCollection<>(this, map.values()) : map.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -70,9 +70,8 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
|
||||
@Override
|
||||
public void internalAddWithCheck(Object bean) {
|
||||
if (set == null || !set.contains(bean)) {
|
||||
internalAdd(bean);
|
||||
}
|
||||
// set add() already de-dups so just add it
|
||||
internalAdd(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -177,7 +176,6 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
}
|
||||
if (set == null) {
|
||||
sb.append("deferred ");
|
||||
|
||||
} else {
|
||||
sb.append("size[").append(set.size()).append("]");
|
||||
sb.append(" set").append(set);
|
||||
|
||||
@@ -20,7 +20,7 @@ public final class CopyOnFirstWriteList<E> extends AbstractList<E> implements Li
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* The underlying List implementation.
|
||||
|
||||
@@ -25,7 +25,7 @@ class ModifyCollection<E> implements Collection<E> {
|
||||
* The owner is notified of the additions and removals.
|
||||
* </p>
|
||||
*/
|
||||
public ModifyCollection(BeanCollection<E> owner, Collection<E> c) {
|
||||
ModifyCollection(BeanCollection<E> owner, Collection<E> c) {
|
||||
this.owner = owner;
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package io.ebean.common;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Handles the Entry Set for BeanMap.
|
||||
*/
|
||||
class ModifyEntrySet<K, E> implements Set<Map.Entry<K, E>> {
|
||||
|
||||
private final BeanMap<K, E> owner;
|
||||
private final Set<Map.Entry<K, E>> entrySet;
|
||||
|
||||
ModifyEntrySet(BeanMap<K, E> owner, Set<Map.Entry<K, E>> entrySet) {
|
||||
this.owner = owner;
|
||||
this.entrySet = entrySet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return entrySet.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return entrySet.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return entrySet.contains(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return entrySet.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return entrySet.toArray(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> entries) {
|
||||
return entrySet.containsAll(entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
owner.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Map.Entry<K, E> entry) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends Map.Entry<K, E>> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
if (o instanceof Map.Entry) {
|
||||
Map.Entry entry = (Map.Entry) o;
|
||||
final E val = owner.get(entry.getKey());
|
||||
if (Objects.equals(val, entry.getValue())) {
|
||||
owner.remove(entry.getKey());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> entries) {
|
||||
boolean modified = false;
|
||||
final Iterator<Map.Entry<K, E>> it = iterator();
|
||||
while (it.hasNext()) {
|
||||
if (!entries.contains(it.next())) {
|
||||
it.remove();
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> entries) {
|
||||
boolean modified = false;
|
||||
for (Object entry : entries) {
|
||||
modified |= remove(entry);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<K, E>> iterator() {
|
||||
return new EntrySetIterator(new ArrayList<>(entrySet).iterator());
|
||||
}
|
||||
|
||||
class EntrySetIterator implements Iterator<Map.Entry<K, E>> {
|
||||
|
||||
private final Iterator<Map.Entry<K, E>> iterator;
|
||||
private Map.Entry<K, E> entry;
|
||||
|
||||
EntrySetIterator(Iterator<Map.Entry<K, E>> iterator) {
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map.Entry<K, E> next() {
|
||||
entry = iterator.next();
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
owner.remove(entry.getKey());
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,9 +3,7 @@ package io.ebean.common;
|
||||
import io.ebean.bean.EntityBean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Holds sets of additions and deletions from a 'owner' List Set or Map.
|
||||
@@ -23,19 +21,19 @@ class ModifyHolder<E> implements Serializable {
|
||||
/**
|
||||
* Deletions list for manyToMany persistence.
|
||||
*/
|
||||
private Set<E> modifyDeletions = new LinkedHashSet<>();
|
||||
private Map<E,Object> modifyDeletions = new IdentityHashMap<>();
|
||||
|
||||
/**
|
||||
* Additions list for manyToMany persistence.
|
||||
*/
|
||||
private Set<E> modifyAdditions = new LinkedHashSet<>();
|
||||
private Map<E,Object> modifyAdditions = new IdentityHashMap<>();
|
||||
|
||||
private boolean touched;
|
||||
|
||||
void reset() {
|
||||
touched = false;
|
||||
modifyDeletions = new LinkedHashSet<>();
|
||||
modifyAdditions = new LinkedHashSet<>();
|
||||
modifyDeletions = new IdentityHashMap<>();
|
||||
modifyAdditions = new IdentityHashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,51 +48,46 @@ class ModifyHolder<E> implements Serializable {
|
||||
}
|
||||
|
||||
private boolean undoDeletion(E bean) {
|
||||
return (bean != null) && modifyDeletions.remove(bean);
|
||||
return (bean != null) && modifyDeletions.remove(bean) != null;
|
||||
}
|
||||
|
||||
void modifyAddition(E bean) {
|
||||
if (bean != null) {
|
||||
touched = true;
|
||||
|
||||
if (bean instanceof EntityBean) {
|
||||
((EntityBean) bean)._ebean_getIntercept().setDeletedFromCollection(false);
|
||||
}
|
||||
|
||||
// If it is to delete then just remove the deletion
|
||||
if (!undoDeletion(bean)) {
|
||||
// Insert
|
||||
modifyAdditions.add(bean);
|
||||
modifyAdditions.put(bean, bean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean undoAddition(Object bean) {
|
||||
return (bean != null) && modifyAdditions.remove(bean);
|
||||
return (bean != null) && modifyAdditions.remove(bean) != null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void modifyRemoval(Object bean) {
|
||||
if (bean != null) {
|
||||
touched = true;
|
||||
|
||||
if (bean instanceof EntityBean) {
|
||||
((EntityBean) bean)._ebean_getIntercept().setDeletedFromCollection(true);
|
||||
}
|
||||
|
||||
// If it is to be added then just remove the addition
|
||||
if (!undoAddition(bean)) {
|
||||
modifyDeletions.add((E) bean);
|
||||
modifyDeletions.put((E) bean, bean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<E> getModifyAdditions() {
|
||||
return modifyAdditions;
|
||||
return modifyAdditions.keySet();
|
||||
}
|
||||
|
||||
Set<E> getModifyRemovals() {
|
||||
return modifyDeletions;
|
||||
return modifyDeletions.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
package io.ebean.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Handle the Key Set for BeanMap.
|
||||
*/
|
||||
class ModifyKeySet<E> implements Set<E> {
|
||||
|
||||
private final Set<E> keySet;
|
||||
private final BeanMap<E, ?> owner;
|
||||
|
||||
ModifyKeySet(BeanMap<E, ?> owner, Set<E> keySet) {
|
||||
this.owner = owner;
|
||||
this.keySet = keySet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return keySet.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return keySet.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return keySet.contains(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return keySet.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return keySet.toArray(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> keys) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return owner.remove(o) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> keys) {
|
||||
return keySet.containsAll(keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
owner.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new KeySetIterator<>(new ArrayList<>(keySet).iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> keys) {
|
||||
return keysMatch(keys, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> keys) {
|
||||
return keysMatch(keys, true);
|
||||
}
|
||||
|
||||
private boolean keysMatch(Collection<?> keys, boolean containsMatch) {
|
||||
boolean changed = false;
|
||||
final Iterator<E> iterator = iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final E key = iterator.next();
|
||||
if (keys.contains(key) == containsMatch) {
|
||||
iterator.remove();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
||||
class KeySetIterator<K> implements Iterator<K> {
|
||||
|
||||
private final Iterator<K> iterator;
|
||||
private K key;
|
||||
|
||||
KeySetIterator(Iterator<K> iterator) {
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K next() {
|
||||
key = iterator.next();
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
owner.remove(key);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package io.ebean.common;
|
||||
|
||||
import io.ebean.bean.BeanCollection;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Wraps a Set for the purposes of notifying removals and additions to the
|
||||
* BeanCollection owner.
|
||||
* <p>
|
||||
* This is required for persisting ManyToMany objects. Additions and removals
|
||||
* become inserts and deletes to the intersection table.
|
||||
* </p>
|
||||
*/
|
||||
class ModifySet<E> extends ModifyCollection<E> implements Set<E> {
|
||||
|
||||
/**
|
||||
* Create with an Owner that is notified of any additions or deletions.
|
||||
*/
|
||||
public ModifySet(BeanCollection<E> owner, Set<E> s) {
|
||||
super(owner, s);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import static io.ebean.util.StringHelper.isNull;
|
||||
|
||||
/**
|
||||
* Provides some base implementation for NamingConventions.
|
||||
*
|
||||
@@ -78,10 +80,16 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
|
||||
@Override
|
||||
public String getSequenceName(String rawTableName, String pkColumn) {
|
||||
final String tableNameUnquoted = databasePlatform.unQuote(rawTableName);
|
||||
TableName tableName = new TableName(rawTableName);
|
||||
String seqName = seqName(pkColumn, tableName.getName());
|
||||
return tableName.withCatalogAndSchema(seqName);
|
||||
}
|
||||
|
||||
private String seqName(String pkColumn, String tableName) {
|
||||
final String tableNameUnquoted = unQuote(tableName);
|
||||
String seqName = sequenceFormat.replace("{table}", tableNameUnquoted);
|
||||
pkColumn = (pkColumn == null) ? "" : databasePlatform.unQuote(pkColumn);
|
||||
return seqName.replace("{column}", pkColumn);
|
||||
pkColumn = (pkColumn == null) ? "" : unQuote(pkColumn);
|
||||
return quoteIdentifiers(seqName.replace("{column}", pkColumn));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,15 +224,13 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
|| AnnotationUtil.has(supCls, DiscriminatorValue.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TableName getM2MJoinTableName(TableName lhsTable, TableName rhsTable) {
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append(lhsTable.getName());
|
||||
buffer.append(unQuote(lhsTable.getName()));
|
||||
buffer.append("_");
|
||||
|
||||
String rhsTableName = rhsTable.getName();
|
||||
String rhsTableName = unQuote(rhsTable.getName());
|
||||
if (rhsTableName.indexOf('_') < rhsPrefixLength) {
|
||||
// trim off a xx_ prefix if there is one
|
||||
rhsTableName = rhsTableName.substring(rhsTableName.indexOf('_') + 1);
|
||||
@@ -238,7 +244,13 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
buffer.setLength(maxTableNameLength);
|
||||
}
|
||||
|
||||
return new TableName(lhsTable.getCatalog(), lhsTable.getSchema(), buffer.toString());
|
||||
String tableName = quoteIdentifiers(buffer.toString());
|
||||
return new TableName(lhsTable.getCatalog(), lhsTable.getSchema(), tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deriveM2MColumn(String tableName, String dbColumn) {
|
||||
return quoteIdentifiers(unQuote(tableName) +"_" + unQuote(dbColumn));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -255,14 +267,29 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTableName(String catalog, String schema, String name) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (!isNull(catalog)) {
|
||||
sb.append(quoteIdentifiers(catalog)).append(".");
|
||||
}
|
||||
if (!isNull(schema)) {
|
||||
sb.append(quoteIdentifiers(schema)).append(".");
|
||||
}
|
||||
return sb.append(quoteIdentifiers(name)).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace back ticks (if they are used) with database platform specific
|
||||
* quoted identifiers.
|
||||
* Replace back ticks (if they are used) with database platform specific quoted identifiers.
|
||||
*/
|
||||
protected String quoteIdentifiers(String s) {
|
||||
return databasePlatform.convertQuotedIdentifiers(s);
|
||||
}
|
||||
|
||||
private String unQuote(String val) {
|
||||
return databasePlatform.unQuote(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks string is null or empty .
|
||||
*/
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package io.ebean.config;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* Helper to find classes taking into account the context class loader.
|
||||
*/
|
||||
@@ -26,20 +21,6 @@ public class ClassLoadConfig {
|
||||
this.context = new ClassLoaderContext(classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the Java.time types are available and should be supported.
|
||||
*/
|
||||
public boolean isJavaTimePresent() {
|
||||
return isPresent("java.time.LocalDate");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Java7 is present.
|
||||
*/
|
||||
public boolean isJava7Present() {
|
||||
return isPresent("java.nio.file.Path");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the Joda types are available and should be supported.
|
||||
*/
|
||||
@@ -54,6 +35,13 @@ public class ClassLoadConfig {
|
||||
return isPresent("javax.validation.constraints.NotNull");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if jakarta validation annotations like Size and NotNull are present.
|
||||
*/
|
||||
public boolean isJakartaValidationAnnotationsPresent() {
|
||||
return isPresent("jakarta.validation.constraints.NotNull");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if javax PostConstruct annotation is present (maybe not in java9).
|
||||
* If not we don't support PostConstruct lifecycle events.
|
||||
@@ -84,22 +72,14 @@ public class ClassLoadConfig {
|
||||
* Return a new instance of the class using the default constructor.
|
||||
*/
|
||||
public Object newInstance(String className) {
|
||||
|
||||
try {
|
||||
Class<?> cls = forName(className);
|
||||
return cls.newInstance();
|
||||
return cls.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Error constructing " + className, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resources for the given name.
|
||||
*/
|
||||
public Enumeration<URL> getResources(String name) throws IOException {
|
||||
return context.getResources(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given class is present.
|
||||
*/
|
||||
@@ -136,9 +116,7 @@ public class ClassLoadConfig {
|
||||
* Optional - if set only use this classLoader (no fallback).
|
||||
*/
|
||||
protected final ClassLoader preferredLoader;
|
||||
|
||||
protected final ClassLoader contextLoader;
|
||||
|
||||
protected final ClassLoader callerLoader;
|
||||
|
||||
ClassLoaderContext(ClassLoader preferredLoader) {
|
||||
@@ -152,15 +130,7 @@ public class ClassLoadConfig {
|
||||
return (loader != null) ? loader : callerLoader;
|
||||
}
|
||||
|
||||
Enumeration<URL> getResources(String name) throws IOException {
|
||||
if (preferredLoader != null) {
|
||||
return preferredLoader.getResources(name);
|
||||
}
|
||||
return contextLoader().getResources(name);
|
||||
}
|
||||
|
||||
Class<?> forName(String name) throws ClassNotFoundException {
|
||||
|
||||
if (preferredLoader != null) {
|
||||
// only use the explicitly set classLoader
|
||||
return classForName(name, preferredLoader);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
|
||||
/**
|
||||
* Custom mappings for DB types that override the default.
|
||||
|
||||
@@ -2,46 +2,28 @@ package io.ebean.config;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import io.avaje.config.Config;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.annotation.Encrypted;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.*;
|
||||
import io.ebean.annotation.*;
|
||||
import io.ebean.cache.ServerCachePlugin;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbEncrypt;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.datasource.DataSourceConfig;
|
||||
import io.ebean.event.BeanFindController;
|
||||
import io.ebean.event.BeanPersistController;
|
||||
import io.ebean.event.BeanPersistListener;
|
||||
import io.ebean.event.BeanPostConstructListener;
|
||||
import io.ebean.event.BeanPostLoad;
|
||||
import io.ebean.event.BeanQueryAdapter;
|
||||
import io.ebean.event.BulkTableEventListener;
|
||||
import io.ebean.event.ServerConfigStartup;
|
||||
import io.ebean.event.*;
|
||||
import io.ebean.event.changelog.ChangeLogListener;
|
||||
import io.ebean.event.changelog.ChangeLogPrepare;
|
||||
import io.ebean.event.changelog.ChangeLogRegister;
|
||||
import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.migration.MigrationRunner;
|
||||
import io.ebean.util.StringHelper;
|
||||
|
||||
import javax.persistence.EnumType;
|
||||
import javax.sql.DataSource;
|
||||
import java.time.Clock;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* The configuration used for creating a Database.
|
||||
@@ -82,7 +64,6 @@ import java.util.ServiceLoader;
|
||||
*/
|
||||
public class DatabaseConfig {
|
||||
|
||||
|
||||
/**
|
||||
* The Database name.
|
||||
*/
|
||||
@@ -191,6 +172,11 @@ public class DatabaseConfig {
|
||||
*/
|
||||
private JsonConfig.Include jsonInclude = JsonConfig.Include.ALL;
|
||||
|
||||
/**
|
||||
* The default mode used for {@code @DbJson} with Jackson ObjectMapper.
|
||||
*/
|
||||
private MutationDetection jsonMutationDetection = MutationDetection.HASH;
|
||||
|
||||
/**
|
||||
* The database platform name. Used to imply a DatabasePlatform to use.
|
||||
*/
|
||||
@@ -230,6 +216,12 @@ public class DatabaseConfig {
|
||||
*/
|
||||
private String historyTableSuffix = "_history";
|
||||
|
||||
/**
|
||||
* When true explicit transactions beans that have been made dirty will be
|
||||
* automatically persisted via update on flush.
|
||||
*/
|
||||
private boolean autoPersistUpdates;
|
||||
|
||||
/**
|
||||
* Use for transaction scoped batch mode.
|
||||
*/
|
||||
@@ -277,6 +269,25 @@ public class DatabaseConfig {
|
||||
|
||||
private String ddlSeedSql;
|
||||
|
||||
private String ddlHeader;
|
||||
|
||||
/**
|
||||
* Mode used to check non-null columns added via migration have a default value specified etc.
|
||||
*/
|
||||
private boolean ddlStrictMode = true;
|
||||
|
||||
/**
|
||||
* Comma and equals delimited key/value placeholders to replace in DDL scripts.
|
||||
*/
|
||||
private String ddlPlaceholders;
|
||||
|
||||
/**
|
||||
* Map of key/value placeholders to replace in DDL scripts.
|
||||
*/
|
||||
private Map<String, String> ddlPlaceholderMap;
|
||||
|
||||
private boolean runMigration;
|
||||
|
||||
/**
|
||||
* When true L2 bean cache use is skipped after a write has occurred on a transaction.
|
||||
*/
|
||||
@@ -289,6 +300,8 @@ public class DatabaseConfig {
|
||||
*/
|
||||
private ExternalTransactionManager externalTransactionManager;
|
||||
|
||||
private boolean skipDataSourceCheck;
|
||||
|
||||
/**
|
||||
* The data source (if programmatically provided).
|
||||
*/
|
||||
@@ -322,11 +335,6 @@ public class DatabaseConfig {
|
||||
*/
|
||||
private String dbSchema;
|
||||
|
||||
/**
|
||||
* The db migration config (migration resource path etc).
|
||||
*/
|
||||
private DbMigrationConfig migrationConfig = new DbMigrationConfig();
|
||||
|
||||
/**
|
||||
* The ClassLoadConfig used to detect Joda, Java8, Jackson etc and create plugin instances given a className.
|
||||
*/
|
||||
@@ -375,8 +383,8 @@ public class DatabaseConfig {
|
||||
private List<BeanPostConstructListener> postConstructListeners = new ArrayList<>();
|
||||
private List<BeanPersistListener> persistListeners = new ArrayList<>();
|
||||
private List<BeanQueryAdapter> queryAdapters = new ArrayList<>();
|
||||
private List<BulkTableEventListener> bulkTableEventListeners = new ArrayList<>();
|
||||
private List<ServerConfigStartup> configStartupListeners = new ArrayList<>();
|
||||
private final List<BulkTableEventListener> bulkTableEventListeners = new ArrayList<>();
|
||||
private final List<ServerConfigStartup> configStartupListeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* By default inserts are included in the change log.
|
||||
@@ -384,42 +392,26 @@ public class DatabaseConfig {
|
||||
private boolean changeLogIncludeInserts = true;
|
||||
|
||||
private ChangeLogPrepare changeLogPrepare;
|
||||
|
||||
private ChangeLogListener changeLogListener;
|
||||
|
||||
private ChangeLogRegister changeLogRegister;
|
||||
|
||||
private boolean changeLogAsync = true;
|
||||
|
||||
private ReadAuditLogger readAuditLogger;
|
||||
|
||||
private ReadAuditPrepare readAuditPrepare;
|
||||
|
||||
private EncryptKeyManager encryptKeyManager;
|
||||
|
||||
private EncryptDeployManager encryptDeployManager;
|
||||
|
||||
private Encryptor encryptor;
|
||||
|
||||
private boolean dbOffline;
|
||||
|
||||
private DbEncrypt dbEncrypt;
|
||||
|
||||
private boolean dbOffline;
|
||||
private ServerCachePlugin serverCachePlugin;
|
||||
|
||||
/**
|
||||
* The default PersistenceContextScope used if one is not explicitly set on a query.
|
||||
*/
|
||||
private PersistenceContextScope persistenceContextScope = PersistenceContextScope.TRANSACTION;
|
||||
|
||||
private JsonFactory jsonFactory;
|
||||
|
||||
private boolean localTimeWithNanos;
|
||||
|
||||
private boolean durationWithNanos;
|
||||
|
||||
private int maxCallStack = 5;
|
||||
|
||||
private boolean transactionRollbackOnChecked = true;
|
||||
|
||||
// configuration for the background executor service (thread pool)
|
||||
@@ -473,7 +465,7 @@ public class DatabaseConfig {
|
||||
* Should the javax.validation.constraints.NotNull enforce a notNull column in DB.
|
||||
* If set to false, use io.ebean.annotation.NotNull or Column(nullable=true).
|
||||
*/
|
||||
private boolean useJavaxValidationNotNull = true;
|
||||
private boolean useValidationNotNull = true;
|
||||
|
||||
/**
|
||||
* Generally we want to perform L2 cache notification in the background and not impact
|
||||
@@ -482,14 +474,23 @@ public class DatabaseConfig {
|
||||
private boolean notifyL2CacheInForeground;
|
||||
|
||||
/**
|
||||
* Set to true to support query plan capture.
|
||||
* Set to true to enable bind capture required for query plan capture.
|
||||
*/
|
||||
private boolean collectQueryPlans;
|
||||
private boolean queryPlanEnable;
|
||||
|
||||
/**
|
||||
* The default threshold in micros for collecting query plans.
|
||||
*/
|
||||
private long collectQueryPlanThresholdMicros = Long.MAX_VALUE;
|
||||
private long queryPlanThresholdMicros = Long.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* Set to true to enable automatic periodic query plan capture.
|
||||
*/
|
||||
private boolean queryPlanCapture;
|
||||
private long queryPlanCapturePeriodSecs = 60 * 10; // 10 minutes
|
||||
private long queryPlanCaptureMaxTimeMillis = 10_000; // 10 seconds
|
||||
private int queryPlanCaptureMaxCount = 10;
|
||||
private QueryPlanListener queryPlanListener;
|
||||
|
||||
/**
|
||||
* The time in millis used to determine when a query is alerted for being slow.
|
||||
@@ -706,6 +707,24 @@ public class DatabaseConfig {
|
||||
this.jsonInclude = jsonInclude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default MutableDetection to use with {@code @DbJson} using Jackson.
|
||||
*
|
||||
* @see DbJson#mutationDetection()
|
||||
*/
|
||||
public MutationDetection getJsonMutationDetection() {
|
||||
return jsonMutationDetection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default MutableDetection to use with {@code @DbJson} using Jackson.
|
||||
*
|
||||
* @see DbJson#mutationDetection()
|
||||
*/
|
||||
public void setJsonMutationDetection(MutationDetection jsonMutationDetection) {
|
||||
this.jsonMutationDetection = jsonMutationDetection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the Database.
|
||||
*/
|
||||
@@ -880,6 +899,20 @@ public class DatabaseConfig {
|
||||
this.tenantCatalogProvider = tenantCatalogProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if dirty beans are automatically persisted.
|
||||
*/
|
||||
public boolean isAutoPersistUpdates() {
|
||||
return autoPersistUpdates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if dirty beans are automatically persisted.
|
||||
*/
|
||||
public void setAutoPersistUpdates(boolean autoPersistUpdates) {
|
||||
this.autoPersistUpdates = autoPersistUpdates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the PersistBatch mode to use by default at the transaction level.
|
||||
* <p>
|
||||
@@ -1029,7 +1062,6 @@ public class DatabaseConfig {
|
||||
* This is a performance optimisation to reduce the number times Ebean
|
||||
* requests a sequence to be used as an Id for a bean (aka reduce network
|
||||
* chatter).
|
||||
|
||||
*/
|
||||
public void setDatabaseSequenceBatchSize(int databaseSequenceBatchSize) {
|
||||
platformConfig.setDatabaseSequenceBatchSize(databaseSequenceBatchSize);
|
||||
@@ -1212,20 +1244,6 @@ public class DatabaseConfig {
|
||||
this.dbSchema = dbSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB migration configuration.
|
||||
*/
|
||||
public DbMigrationConfig getMigrationConfig() {
|
||||
return migrationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB migration configuration.
|
||||
*/
|
||||
public void setMigrationConfig(DbMigrationConfig migrationConfig) {
|
||||
this.migrationConfig = migrationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Geometry SRID.
|
||||
*/
|
||||
@@ -1600,6 +1618,20 @@ public class DatabaseConfig {
|
||||
this.autoTuneConfig = autoTuneConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the startup DataSource check should be skipped.
|
||||
*/
|
||||
public boolean skipDataSourceCheck() {
|
||||
return skipDataSourceCheck;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to skip the startup DataSource check.
|
||||
*/
|
||||
public void setSkipDataSourceCheck(boolean skipDataSourceCheck) {
|
||||
this.skipDataSourceCheck = skipDataSourceCheck;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DataSource.
|
||||
*/
|
||||
@@ -2026,7 +2058,15 @@ public class DatabaseConfig {
|
||||
* as it is often the only thing we need to configure for migrations.
|
||||
*/
|
||||
public void setRunMigration(boolean runMigration) {
|
||||
migrationConfig.setRunMigration(runMigration);
|
||||
this.runMigration = runMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the DB migration should run on server start.
|
||||
*/
|
||||
public boolean isRunMigration() {
|
||||
final String run = System.getProperty("ebean.migration.run");
|
||||
return (run != null) ? Boolean.parseBoolean(run) : runMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2134,6 +2174,67 @@ public class DatabaseConfig {
|
||||
return ddlExtra;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the header to use with DDL generation.
|
||||
*/
|
||||
public void setDdlHeader(String ddlHeader) {
|
||||
this.ddlHeader = ddlHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the header to use with DDL generation.
|
||||
*/
|
||||
public String getDdlHeader() {
|
||||
if (ddlHeader != null && !ddlHeader.isEmpty()) {
|
||||
String header = ddlHeader.replace("${version}", EbeanVersion.getVersion());
|
||||
header = header.replace("${timestamp}", ZonedDateTime.now().format(DateTimeFormatter.ISO_INSTANT));
|
||||
return header;
|
||||
}
|
||||
return ddlHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if strict mode is used which includes a check that non-null columns have a default value.
|
||||
*/
|
||||
public boolean isDdlStrictMode() {
|
||||
return ddlStrictMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to false to turn off strict mode allowing non-null columns to not have a default value.
|
||||
*/
|
||||
public void setDdlStrictMode(boolean ddlStrictMode) {
|
||||
this.ddlStrictMode = ddlStrictMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a comma and equals delimited placeholders that are substituted in DDL scripts.
|
||||
*/
|
||||
public String getDdlPlaceholders() {
|
||||
return ddlPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a comma and equals delimited placeholders that are substituted in DDL scripts.
|
||||
*/
|
||||
public void setDdlPlaceholders(String ddlPlaceholders) {
|
||||
this.ddlPlaceholders = ddlPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of placeholder values that are substituted in DDL scripts.
|
||||
*/
|
||||
public Map<String, String> getDdlPlaceholderMap() {
|
||||
return ddlPlaceholderMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a map of placeholder values that are substituted in DDL scripts.
|
||||
*/
|
||||
public void setDdlPlaceholderMap(Map<String, String> ddlPlaceholderMap) {
|
||||
this.ddlPlaceholderMap = ddlPlaceholderMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the class path search should be disabled.
|
||||
*/
|
||||
@@ -2605,24 +2706,13 @@ public class DatabaseConfig {
|
||||
this.classLoadConfig = classLoadConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the service loader using the classLoader defined in ClassLoadConfig.
|
||||
*/
|
||||
public <T> ServiceLoader<T> serviceLoad(Class<T> spiService) {
|
||||
return ServiceLoader.load(spiService, classLoadConfig.getClassLoader());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the first service using the service loader (or null).
|
||||
*/
|
||||
public <T> T service(Class<T> spiService) {
|
||||
ServiceLoader<T> load = serviceLoad(spiService);
|
||||
Iterator<T> serviceInstances = load.iterator();
|
||||
return serviceInstances.hasNext() ? serviceInstances.next() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load settings from ebean.properties.
|
||||
* Load settings from application.properties, application.yaml and other sources.
|
||||
* <p>
|
||||
* Uses <code>avaje-config</code> to load configuration properties. Goto https://avaje.io/config
|
||||
* for detail on how and where properties are loaded from.
|
||||
*/
|
||||
public void loadFromProperties() {
|
||||
this.properties = Config.asProperties();
|
||||
@@ -2655,7 +2745,7 @@ public class DatabaseConfig {
|
||||
*/
|
||||
private List<AutoConfigure> autoConfiguration() {
|
||||
List<AutoConfigure> list = new ArrayList<>();
|
||||
for (AutoConfigure autoConfigure : serviceLoad(AutoConfigure.class)) {
|
||||
for (AutoConfigure autoConfigure : ServiceLoader.load(AutoConfigure.class)) {
|
||||
autoConfigure.preConfigure(this);
|
||||
list.add(autoConfigure);
|
||||
}
|
||||
@@ -2699,13 +2789,8 @@ public class DatabaseConfig {
|
||||
* Load the configuration settings from the properties file.
|
||||
*/
|
||||
protected void loadSettings(PropertiesWrapper p) {
|
||||
|
||||
dbSchema = p.get("dbSchema", dbSchema);
|
||||
if (dbSchema != null) {
|
||||
migrationConfig.setDefaultDbSchema(dbSchema);
|
||||
}
|
||||
profilingConfig.loadSettings(p, name);
|
||||
migrationConfig.loadSettings(p, name);
|
||||
platformConfig.loadSettings(p);
|
||||
if (platformConfig.isAllQuotedIdentifiers()) {
|
||||
adjustNamingConventionForAllQuoted();
|
||||
@@ -2729,21 +2814,27 @@ public class DatabaseConfig {
|
||||
}
|
||||
loadDocStoreSettings(p);
|
||||
|
||||
defaultServer = p.getBoolean("defaultServer", defaultServer);
|
||||
autoPersistUpdates = p.getBoolean("autoPersistUpdates", autoPersistUpdates);
|
||||
loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo);
|
||||
maxCallStack = p.getInt("maxCallStack", maxCallStack);
|
||||
dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown);
|
||||
dumpMetricsOptions = p.get("dumpMetricsOptions", dumpMetricsOptions);
|
||||
queryPlanTTLSeconds = p.getInt("queryPlanTTLSeconds", queryPlanTTLSeconds);
|
||||
slowQueryMillis = p.getLong("slowQueryMillis", slowQueryMillis);
|
||||
collectQueryPlans = p.getBoolean("collectQueryPlans", collectQueryPlans);
|
||||
collectQueryPlanThresholdMicros = p.getLong("collectQueryPlanThresholdMicros", collectQueryPlanThresholdMicros);
|
||||
queryPlanEnable = p.getBoolean("queryPlan.enable", queryPlanEnable);
|
||||
queryPlanThresholdMicros = p.getLong("queryPlan.thresholdMicros", queryPlanThresholdMicros);
|
||||
queryPlanCapture = p.getBoolean("queryPlan.capture", queryPlanCapture);
|
||||
queryPlanCapturePeriodSecs = p.getLong("queryPlan.capturePeriodSecs", queryPlanCapturePeriodSecs);
|
||||
queryPlanCaptureMaxTimeMillis = p.getLong("queryPlan.captureMaxTimeMillis", queryPlanCaptureMaxTimeMillis);
|
||||
queryPlanCaptureMaxCount = p.getInt("queryPlan.captureMaxCount", queryPlanCaptureMaxCount);
|
||||
docStoreOnly = p.getBoolean("docStoreOnly", docStoreOnly);
|
||||
disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache);
|
||||
localOnlyL2Cache = p.getBoolean("localOnlyL2Cache", localOnlyL2Cache);
|
||||
enabledL2Regions = p.get("enabledL2Regions", enabledL2Regions);
|
||||
notifyL2CacheInForeground = p.getBoolean("notifyL2CacheInForeground", notifyL2CacheInForeground);
|
||||
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager);
|
||||
useJavaxValidationNotNull = p.getBoolean("useJavaxValidationNotNull", useJavaxValidationNotNull);
|
||||
useValidationNotNull = p.getBoolean("useValidationNotNull", useValidationNotNull);
|
||||
autoReadOnlyDataSource = p.getBoolean("autoReadOnlyDataSource", autoReadOnlyDataSource);
|
||||
idGeneratorAutomatic = p.getBoolean("idGeneratorAutomatic", idGeneratorAutomatic);
|
||||
|
||||
@@ -2806,13 +2897,19 @@ public class DatabaseConfig {
|
||||
jsonInclude = p.getEnum(JsonConfig.Include.class, "jsonInclude", jsonInclude);
|
||||
jsonDateTime = p.getEnum(JsonConfig.DateTime.class, "jsonDateTime", jsonDateTime);
|
||||
jsonDate = p.getEnum(JsonConfig.Date.class, "jsonDate", jsonDate);
|
||||
jsonMutationDetection = p.getEnum(MutationDetection.class, "jsonMutationDetection", jsonMutationDetection);
|
||||
|
||||
skipDataSourceCheck = p.getBoolean("skipDataSourceCheck", skipDataSourceCheck);
|
||||
runMigration = p.getBoolean("migration.run", runMigration);
|
||||
ddlGenerate = p.getBoolean("ddl.generate", ddlGenerate);
|
||||
ddlRun = p.getBoolean("ddl.run", ddlRun);
|
||||
ddlExtra = p.getBoolean("ddl.extra", ddlExtra);
|
||||
ddlCreateOnly = p.getBoolean("ddl.createOnly", ddlCreateOnly);
|
||||
ddlInitSql = p.get("ddl.initSql", ddlInitSql);
|
||||
ddlSeedSql = p.get("ddl.seedSql", ddlSeedSql);
|
||||
ddlStrictMode = p.getBoolean("ddl.strictMode", ddlStrictMode);
|
||||
ddlPlaceholders = p.get("ddl.placeholders", ddlPlaceholders);
|
||||
ddlHeader = p.get("ddl.header", ddlHeader);
|
||||
|
||||
// read tenant-configuration from config:
|
||||
// tenant.mode = NONE | DB | SCHEMA | CATALOG | PARTITION
|
||||
@@ -2986,20 +3083,21 @@ public class DatabaseConfig {
|
||||
/**
|
||||
* Returns if we use javax.validation.constraints.NotNull
|
||||
*/
|
||||
public boolean isUseJavaxValidationNotNull() {
|
||||
return useJavaxValidationNotNull;
|
||||
public boolean isUseValidationNotNull() {
|
||||
return useValidationNotNull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls if Ebean should ignore <code>&x64;javax.validation.contstraints.NotNull</code>
|
||||
* Controls if Ebean should ignore <code>&x64;javax.validation.contstraints.NotNull</code> or
|
||||
* <code>&x64;jakarta.validation.contstraints.NotNull</code>
|
||||
* with respect to generating a <code>NOT NULL</code> column.
|
||||
* <p>
|
||||
* Normally when Ebean sees javax NotNull annotation it means that column is defined as NOT NULL.
|
||||
* Set this to <code>false</code> and the javax NotNull annotation is effectively ignored (and
|
||||
* we instead use Ebean's own NotNull annotation or JPA Column(nullable=false) annotation.
|
||||
*/
|
||||
public void setUseJavaxValidationNotNull(boolean useJavaxValidationNotNull) {
|
||||
this.useJavaxValidationNotNull = useJavaxValidationNotNull;
|
||||
public void setUseValidationNotNull(boolean useValidationNotNull) {
|
||||
this.useValidationNotNull = useValidationNotNull;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3021,30 +3119,22 @@ public class DatabaseConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query plan time to live.
|
||||
* Return the time to live for ebean's internal query plan.
|
||||
*/
|
||||
public int getQueryPlanTTLSeconds() {
|
||||
return queryPlanTTLSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the query plan time to live.
|
||||
* Set the time to live for ebean's internal query plan.
|
||||
* <p>
|
||||
* This is the plan that knows how to execute the query, read the result
|
||||
* and collects execution metrics. By default this is set to 5 mins.
|
||||
*/
|
||||
public void setQueryPlanTTLSeconds(int queryPlanTTLSeconds) {
|
||||
this.queryPlanTTLSeconds = queryPlanTTLSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the DB migration against the DataSource.
|
||||
*/
|
||||
public DataSource runDbMigration(DataSource dataSource) {
|
||||
if (migrationConfig.isRunMigration()) {
|
||||
MigrationRunner runner = migrationConfig.createRunner(getClassLoadConfig().getClassLoader(), properties);
|
||||
runner.run(dataSource);
|
||||
}
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new PlatformConfig based of the one held but with overridden properties by reading
|
||||
* properties with the given path and prefix.
|
||||
@@ -3112,29 +3202,110 @@ public class DatabaseConfig {
|
||||
/**
|
||||
* Return true if query plan capture is enabled.
|
||||
*/
|
||||
public boolean isCollectQueryPlans() {
|
||||
return collectQueryPlans;
|
||||
public boolean isQueryPlanEnable() {
|
||||
return queryPlanEnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to enable query plan capture.
|
||||
*/
|
||||
public void setCollectQueryPlans(boolean collectQueryPlans) {
|
||||
this.collectQueryPlans = collectQueryPlans;
|
||||
public void setQueryPlanEnable(boolean queryPlanEnable) {
|
||||
this.queryPlanEnable = queryPlanEnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query plan collection threshold in microseconds.
|
||||
*/
|
||||
public long getCollectQueryPlanThresholdMicros() {
|
||||
return collectQueryPlanThresholdMicros;
|
||||
public long getQueryPlanThresholdMicros() {
|
||||
return queryPlanThresholdMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the query plan collection threshold in microseconds.
|
||||
* <p>
|
||||
* Queries executing slower than this will have bind values captured such that later
|
||||
* the query plan can be captured and reported.
|
||||
*/
|
||||
public void setCollectQueryPlanThresholdMicros(long collectQueryPlanThresholdMicros) {
|
||||
this.collectQueryPlanThresholdMicros = collectQueryPlanThresholdMicros;
|
||||
public void setQueryPlanThresholdMicros(long queryPlanThresholdMicros) {
|
||||
this.queryPlanThresholdMicros = queryPlanThresholdMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if periodic capture of query plans is enabled.
|
||||
*/
|
||||
public boolean isQueryPlanCapture() {
|
||||
return queryPlanCapture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to turn on periodic capture of query plans.
|
||||
*/
|
||||
public void setQueryPlanCapture(boolean queryPlanCapture) {
|
||||
this.queryPlanCapture = queryPlanCapture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the frequency to capture query plans.
|
||||
*/
|
||||
public long getQueryPlanCapturePeriodSecs() {
|
||||
return queryPlanCapturePeriodSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the frequency in seconds to capture query plans.
|
||||
*/
|
||||
public void setQueryPlanCapturePeriodSecs(long queryPlanCapturePeriodSecs) {
|
||||
this.queryPlanCapturePeriodSecs = queryPlanCapturePeriodSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time after which a capture query plans request will
|
||||
* stop capturing more query plans.
|
||||
* <p>
|
||||
* Effectively this controls the amount of load/time we want to
|
||||
* allow for query plan capture.
|
||||
*/
|
||||
public long getQueryPlanCaptureMaxTimeMillis() {
|
||||
return queryPlanCaptureMaxTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time after which a capture query plans request will
|
||||
* stop capturing more query plans.
|
||||
* <p>
|
||||
* Effectively this controls the amount of load/time we want to
|
||||
* allow for query plan capture.
|
||||
*/
|
||||
public void setQueryPlanCaptureMaxTimeMillis(long queryPlanCaptureMaxTimeMillis) {
|
||||
this.queryPlanCaptureMaxTimeMillis = queryPlanCaptureMaxTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the max number of query plans captured per request.
|
||||
*/
|
||||
public int getQueryPlanCaptureMaxCount() {
|
||||
return queryPlanCaptureMaxCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the max number of query plans captured per request.
|
||||
*/
|
||||
public void setQueryPlanCaptureMaxCount(int queryPlanCaptureMaxCount) {
|
||||
this.queryPlanCaptureMaxCount = queryPlanCaptureMaxCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listener used to process captured query plans.
|
||||
*/
|
||||
public QueryPlanListener getQueryPlanListener() {
|
||||
return queryPlanListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listener used to process captured query plans.
|
||||
*/
|
||||
public void setQueryPlanListener(QueryPlanListener queryPlanListener) {
|
||||
this.queryPlanListener = queryPlanListener;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,7 +15,7 @@ package io.ebean.config;
|
||||
*
|
||||
* public class EbeanConfigProvider implements DatabaseConfigProvider {
|
||||
*
|
||||
* @Override
|
||||
* @Override
|
||||
* public void apply(DatabaseConfig config) {
|
||||
*
|
||||
* // register the entity bean classes explicitly
|
||||
|
||||
@@ -1,509 +0,0 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import io.ebean.EbeanVersion;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.migration.MigrationConfig;
|
||||
import io.ebean.migration.MigrationRunner;
|
||||
import io.ebean.util.StringHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import static io.ebean.util.StringHelper.replace;
|
||||
|
||||
/**
|
||||
* Configuration for the DB migration processing.
|
||||
*/
|
||||
public class DbMigrationConfig {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(DbMigrationConfig.class);
|
||||
|
||||
protected MigrationConfig runnerConfig = new MigrationConfig();
|
||||
|
||||
/**
|
||||
* The database platform to generate migration DDL for.
|
||||
*/
|
||||
protected Platform platform;
|
||||
|
||||
/**
|
||||
* Resource path for the migration xml and sql.
|
||||
*/
|
||||
protected String migrationPath = "dbmigration";
|
||||
|
||||
protected String migrationInitPath = "dbinit";
|
||||
|
||||
/**
|
||||
* Subdirectory the model xml files go into.
|
||||
*/
|
||||
protected String modelPath = "model";
|
||||
|
||||
protected String applySuffix = ".sql";
|
||||
|
||||
/**
|
||||
* Set this to "V" to be compatible with FlywayDB.
|
||||
*/
|
||||
protected String applyPrefix = "";
|
||||
|
||||
protected String modelSuffix = ".model.xml";
|
||||
|
||||
/**
|
||||
* For running migration the DB table that holds migration execution status.
|
||||
*/
|
||||
protected String metaTable = "db_migration";
|
||||
|
||||
/**
|
||||
* Flag set to true means to run any outstanding migrations on startup.
|
||||
*/
|
||||
protected boolean runMigration;
|
||||
|
||||
/**
|
||||
* Comma and equals delimited key/value placeholders to replace in DDL scripts.
|
||||
*/
|
||||
protected String runPlaceholders;
|
||||
|
||||
/**
|
||||
* Map of key/value placeholders to replace in DDL scripts.
|
||||
*/
|
||||
protected Map<String, String> runPlaceholderMap;
|
||||
|
||||
/**
|
||||
* DB schema used for the migration (and testing).
|
||||
*/
|
||||
protected String dbSchema;
|
||||
|
||||
/**
|
||||
* Set to true if we consider this the 'default schema' (Postgres schema that matches DB username)
|
||||
*/
|
||||
protected boolean defaultDbSchema;
|
||||
|
||||
/**
|
||||
* DB user used to run the DB migration.
|
||||
*/
|
||||
protected String dbUsername;
|
||||
|
||||
/**
|
||||
* DB password used to run the DB migration.
|
||||
*/
|
||||
protected String dbPassword;
|
||||
|
||||
protected String patchInsertOn;
|
||||
|
||||
protected String patchResetChecksumOn;
|
||||
|
||||
/**
|
||||
* Mode used to check non-null columns added via migration have a default value specified etc.
|
||||
*/
|
||||
protected boolean strictMode = true;
|
||||
|
||||
/**
|
||||
* Contains the DDL-header information.
|
||||
*/
|
||||
protected String ddlHeader;
|
||||
|
||||
/**
|
||||
* Return the DB platform to generate migration DDL for.
|
||||
* <p>
|
||||
* We typically need to explicitly specify this as migration can often be generated
|
||||
* when running against H2.
|
||||
*/
|
||||
public Platform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB platform to generate migration DDL for.
|
||||
*/
|
||||
public void setPlatform(Platform platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path for normal migrations or dbinit migrations.
|
||||
*
|
||||
* @param dbinitMigration When true return the path for dbinit migrations.
|
||||
*/
|
||||
public String getMigrationPath(boolean dbinitMigration) {
|
||||
return dbinitMigration ? migrationInitPath : migrationPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resource path for db migrations.
|
||||
*/
|
||||
public String getMigrationPath() {
|
||||
return migrationPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource path for db migrations.
|
||||
* <p>
|
||||
* The default of "dbmigration" is reasonable in most cases. You may look to set this
|
||||
* to be something like "dbmigration/myapp" where myapp gives it a unique resource path
|
||||
* in the case there are multiple Database applications in the single classpath.
|
||||
* </p>
|
||||
*/
|
||||
public void setMigrationPath(String migrationPath) {
|
||||
this.migrationPath = migrationPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the relative path for the model files (defaults to model).
|
||||
*/
|
||||
public String getModelPath() {
|
||||
return modelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the relative path for the model files.
|
||||
*/
|
||||
public void setModelPath(String modelPath) {
|
||||
this.modelPath = modelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the model suffix (defaults to model.xml)
|
||||
*/
|
||||
public String getModelSuffix() {
|
||||
return modelSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the model suffix.
|
||||
*/
|
||||
public void setModelSuffix(String modelSuffix) {
|
||||
this.modelSuffix = modelSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the apply script suffix (defaults to sql).
|
||||
*/
|
||||
public String getApplySuffix() {
|
||||
return applySuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the apply script suffix (defaults to sql).
|
||||
*/
|
||||
public void setApplySuffix(String applySuffix) {
|
||||
this.applySuffix = applySuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the apply prefix.
|
||||
*/
|
||||
public String getApplyPrefix() {
|
||||
return applyPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the apply prefix. This might be set to "V" for use with FlywayDB.
|
||||
*/
|
||||
public void setApplyPrefix(String applyPrefix) {
|
||||
this.applyPrefix = applyPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the table name that holds the migration run details
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public String getMetaTable() {
|
||||
return metaTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table name that holds the migration run details
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public void setMetaTable(String metaTable) {
|
||||
this.metaTable = metaTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a comma and equals delimited placeholders that are substituted in SQL scripts when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public String getRunPlaceholders() {
|
||||
// environment properties take precedence
|
||||
String placeholders = readEnvironment("ddl.migration.placeholders");
|
||||
if (placeholders != null) {
|
||||
return placeholders;
|
||||
}
|
||||
return runPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a comma and equals delimited placeholders that are substituted in SQL scripts when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public void setRunPlaceholders(String runPlaceholders) {
|
||||
this.runPlaceholders = runPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of placeholder values that are substituted in SQL scripts when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public Map<String, String> getRunPlaceholderMap() {
|
||||
return runPlaceholderMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a map of placeholder values that are substituted when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public void setRunPlaceholderMap(Map<String, String> runPlaceholderMap) {
|
||||
this.runPlaceholderMap = runPlaceholderMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the DB migration should be run on startup.
|
||||
*/
|
||||
public boolean isRunMigration() {
|
||||
// environment properties take precedence
|
||||
String run = readEnvironment("ddl.migration.run");
|
||||
if (run != null) {
|
||||
return "true".equalsIgnoreCase(run.trim());
|
||||
}
|
||||
return runMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to run the DB migration on startup.
|
||||
*/
|
||||
public void setRunMigration(boolean runMigration) {
|
||||
this.runMigration = runMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB username to use for running DB migrations.
|
||||
*/
|
||||
public String getDbUsername() {
|
||||
// environment properties take precedence
|
||||
String user = readEnvironment("ddl.migration.user");
|
||||
if (user != null) {
|
||||
return user;
|
||||
}
|
||||
return dbUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB username to use for running DB migrations.
|
||||
*/
|
||||
public void setDbUsername(String dbUsername) {
|
||||
this.dbUsername = dbUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB password to use for running DB migrations.
|
||||
*/
|
||||
public String getDbPassword() {
|
||||
String user = readEnvironment("ddl.migration.password");
|
||||
if (user != null) {
|
||||
return user;
|
||||
}
|
||||
return dbPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB password to use for running DB migrations.
|
||||
*/
|
||||
public void setDbPassword(String dbPassword) {
|
||||
this.dbPassword = dbPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB schema to use (for migration, testing etc).
|
||||
*/
|
||||
public String getDbSchema() {
|
||||
String schema = readEnvironment("ddl.migration.schema");
|
||||
if (schema != null) {
|
||||
return schema;
|
||||
}
|
||||
return dbSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Db schema to use.
|
||||
*/
|
||||
public void setDbSchema(String dbSchema) {
|
||||
this.dbSchema = dbSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Db schema if it hasn't already been defined.
|
||||
*/
|
||||
public void setDefaultDbSchema(String dbSchema) {
|
||||
this.defaultDbSchema = true;
|
||||
this.dbSchema = dbSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is considered the default DB schema (Postgres schema matching DB username).
|
||||
*/
|
||||
public boolean isDefaultDbSchema() {
|
||||
return defaultDbSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return migration versions that should be added to history without running.
|
||||
*/
|
||||
public String getPatchInsertOn() {
|
||||
return patchInsertOn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set migration versions that should be added to history without running.
|
||||
* <p>
|
||||
* Value can be a string containing comma delimited list of version numbers.
|
||||
* </p>
|
||||
*/
|
||||
public void setPatchInsertOn(String patchInsertOn) {
|
||||
this.patchInsertOn = patchInsertOn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return migration versions that should have their checksum reset and not run.
|
||||
*/
|
||||
public String getPatchResetChecksumOn() {
|
||||
return patchResetChecksumOn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a DDL header prepend for each DDL. E.g. for copyright headers
|
||||
* You can use placeholders like ${version} or ${timestamp} in properties file.
|
||||
*/
|
||||
public String getDdlHeader() {
|
||||
if (ddlHeader != null && !ddlHeader.isEmpty()) {
|
||||
ddlHeader = replace(ddlHeader, "${version}", EbeanVersion.getVersion());
|
||||
ddlHeader = replace(ddlHeader, "${timestamp}", ZonedDateTime.now().format( DateTimeFormatter.ISO_INSTANT ));
|
||||
}
|
||||
return ddlHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the header prepended to the DDL.
|
||||
*/
|
||||
public void setDdlHeader(String ddlHeader) {
|
||||
this.ddlHeader = ddlHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set migration versions that should have their checksum reset and not run.
|
||||
* <p>
|
||||
* Value can be a string containing comma delimited list of version numbers.
|
||||
* </p>
|
||||
*/
|
||||
public void setPatchResetChecksumOn(String patchResetChecksumOn) {
|
||||
this.patchResetChecksumOn = patchResetChecksumOn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if strict mode is used which includes a check that non-null columns have a default value.
|
||||
*/
|
||||
public boolean isStrictMode() {
|
||||
String envValue = readEnvironment("ddl.migration.strictMode");
|
||||
if (!isEmpty(envValue)) {
|
||||
return Boolean.parseBoolean(envValue.trim());
|
||||
}
|
||||
return strictMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to false to turn off strict mode allowing non-null columns to not have a default value.
|
||||
*/
|
||||
public void setStrictMode(boolean strictMode) {
|
||||
this.strictMode = strictMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying migration runner configuration allowing for more advanced settings.
|
||||
*/
|
||||
public MigrationConfig getRunnerConfig() {
|
||||
return runnerConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from the PropertiesWrapper.
|
||||
*/
|
||||
public void loadSettings(PropertiesWrapper properties, String serverName) {
|
||||
|
||||
migrationPath = properties.get("migration.migrationPath", migrationPath);
|
||||
migrationInitPath = properties.get("migration.migrationInitPath", migrationInitPath);
|
||||
modelPath = properties.get("migration.modelPath", modelPath);
|
||||
applyPrefix = properties.get("migration.applyPrefix", applyPrefix);
|
||||
applySuffix = properties.get("migration.applySuffix", applySuffix);
|
||||
modelSuffix = properties.get("migration.modelSuffix", modelSuffix);
|
||||
|
||||
platform = properties.getEnum(Platform.class, "migration.platform", platform);
|
||||
patchInsertOn = properties.get("migration.patchInsertOn", patchInsertOn);
|
||||
patchResetChecksumOn = properties.get("migration.patchResetChecksumOn", patchResetChecksumOn);
|
||||
|
||||
runMigration = properties.getBoolean("migration.run", runMigration);
|
||||
metaTable = properties.get("migration.metaTable", metaTable);
|
||||
runPlaceholders = properties.get("migration.placeholders", runPlaceholders);
|
||||
dbSchema = properties.get("migration.dbSchema", dbSchema);
|
||||
|
||||
//Do not set user and pass from "datasource.db.username"
|
||||
//There is a null test in MigrationRunner::getConnection to handle this
|
||||
//String adminUser = properties.get("datasource." + serverName + ".username", dbUsername);
|
||||
String adminUser = properties.get("datasource." + serverName + ".adminusername", dbUsername);
|
||||
dbUsername = properties.get("migration.dbusername", adminUser);
|
||||
|
||||
//String adminPwd = properties.get("datasource." + serverName + ".password", dbPassword);
|
||||
String adminPwd = properties.get("datasource." + serverName + ".adminpassword", dbPassword);
|
||||
dbPassword = properties.get("migration.dbpassword", adminPwd);
|
||||
ddlHeader = properties.get("ddl.header", ddlHeader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the system or environment property.
|
||||
*/
|
||||
protected String readEnvironment(String key) {
|
||||
|
||||
String val = System.getProperty(key);
|
||||
if (val == null) {
|
||||
val = System.getenv(key);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the string is null or empty.
|
||||
*/
|
||||
protected boolean isEmpty(String val) {
|
||||
return val == null || val.trim().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the MigrationRunner to run migrations if necessary.
|
||||
*/
|
||||
public MigrationRunner createRunner(ClassLoader classLoader, Properties properties) {
|
||||
|
||||
runnerConfig.setMetaTable(metaTable);
|
||||
runnerConfig.setApplySuffix(applySuffix);
|
||||
runnerConfig.setMigrationPath(migrationPath);
|
||||
runnerConfig.setMigrationInitPath(migrationInitPath);
|
||||
runnerConfig.setRunPlaceholderMap(runPlaceholderMap);
|
||||
runnerConfig.setRunPlaceholders(runPlaceholders);
|
||||
runnerConfig.setDbUsername(getDbUsername());
|
||||
runnerConfig.setDbPassword(getDbPassword());
|
||||
runnerConfig.setDbSchema(getDbSchema());
|
||||
if (defaultDbSchema) {
|
||||
runnerConfig.setSetCurrentSchema(false);
|
||||
}
|
||||
runnerConfig.setClassLoader(classLoader);
|
||||
if (patchInsertOn != null) {
|
||||
runnerConfig.setPatchInsertOn(patchInsertOn);
|
||||
}
|
||||
if (patchResetChecksumOn != null) {
|
||||
runnerConfig.setPatchResetChecksumOn(patchResetChecksumOn);
|
||||
}
|
||||
if (properties != null) {
|
||||
runnerConfig.load(properties);
|
||||
}
|
||||
return new MigrationRunner(runnerConfig);
|
||||
}
|
||||
}
|
||||
@@ -39,11 +39,6 @@ public class MatchingNamingConvention extends AbstractNamingConvention {
|
||||
return new TableName(quoteIdentifiers(getCatalog()), quoteIdentifiers(getSchema()), quoteIdentifiers(beanClass.getSimpleName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPropertyFromColumn(Class<?> beanClass, String dbColumnName) {
|
||||
return dbColumnName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getForeignKey(String prefix, String fkProperty) {
|
||||
prefix = databasePlatform.unQuote(prefix);
|
||||
|
||||
@@ -7,13 +7,8 @@ import java.util.List;
|
||||
*/
|
||||
public interface ModuleInfoLoader {
|
||||
|
||||
/**
|
||||
* Return the entity classes to register with the default DB.
|
||||
*/
|
||||
List<Class<?>> entityClasses();
|
||||
|
||||
/**
|
||||
* Return entity classes to register for a named DB (not default DB).
|
||||
*/
|
||||
List<Class<?>> entityClassesFor(String dbName);
|
||||
List<Class<?>> classesFor(String dbName, boolean defaultServer);
|
||||
}
|
||||
|
||||
@@ -53,6 +53,16 @@ public interface NamingConvention {
|
||||
*/
|
||||
TableName getM2MJoinTableName(TableName lhsTable, TableName rhsTable);
|
||||
|
||||
/**
|
||||
* Derive a DB Column from a FK table and column.
|
||||
*/
|
||||
String deriveM2MColumn(String tableName, String dbColumn);
|
||||
|
||||
/**
|
||||
* Return the full table name taking into account quoted identifiers.
|
||||
*/
|
||||
String getTableName(String catalog, String schema, String name);
|
||||
|
||||
/**
|
||||
* Return the column name given the property name.
|
||||
*
|
||||
@@ -60,18 +70,6 @@ public interface NamingConvention {
|
||||
*/
|
||||
String getColumnFromProperty(Class<?> beanClass, String propertyName);
|
||||
|
||||
/**
|
||||
* Return the property name from the column name.
|
||||
* <p>
|
||||
* This is used to help mapping of raw SQL queries onto bean properties.
|
||||
* </p>
|
||||
*
|
||||
* @param beanClass the bean class
|
||||
* @param dbColumnName the db column name
|
||||
* @return the property name from the column name
|
||||
*/
|
||||
String getPropertyFromColumn(Class<?> beanClass, String dbColumnName);
|
||||
|
||||
/**
|
||||
* Return the sequence name given the table name (for DB's that use sequences).
|
||||
* <p>
|
||||
|
||||
@@ -17,6 +17,11 @@ public class PlatformConfig {
|
||||
|
||||
private boolean allQuotedIdentifiers;
|
||||
|
||||
/**
|
||||
* Set this to true for Postgres FOR UPDATE to use NO KEY option.
|
||||
*/
|
||||
private boolean forUpdateNoKey;
|
||||
|
||||
private DbConstraintNaming constraintNaming;
|
||||
|
||||
/**
|
||||
@@ -77,6 +82,7 @@ public class PlatformConfig {
|
||||
* Construct based on given config - typically for DbMigration generation with many platforms.
|
||||
*/
|
||||
public PlatformConfig(PlatformConfig platformConfig) {
|
||||
this.forUpdateNoKey = platformConfig.forUpdateNoKey;
|
||||
this.databaseBooleanFalse = platformConfig.databaseBooleanFalse;
|
||||
this.databaseBooleanTrue = platformConfig.databaseBooleanTrue;
|
||||
this.databaseSequenceBatchSize = platformConfig.databaseSequenceBatchSize;
|
||||
@@ -133,14 +139,26 @@ public class PlatformConfig {
|
||||
this.caseSensitiveCollation = caseSensitiveCollation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Postgres FOR UPDATE should use the NO KEY option.
|
||||
*/
|
||||
public boolean isForUpdateNoKey() {
|
||||
return forUpdateNoKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true such that Postgres FOR UPDATE should use the NO KEY option.
|
||||
*/
|
||||
public void setForUpdateNoKey(boolean forUpdateNoKey) {
|
||||
this.forUpdateNoKey = forUpdateNoKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a value used to represent TRUE in the database.
|
||||
* <p>
|
||||
* This is used for databases that do not support boolean natively.
|
||||
* </p>
|
||||
* <p>
|
||||
* The value returned is either a Integer or a String (e.g. "1", or "T").
|
||||
* </p>
|
||||
*/
|
||||
public String getDatabaseBooleanTrue() {
|
||||
return databaseBooleanTrue;
|
||||
@@ -150,10 +168,8 @@ public class PlatformConfig {
|
||||
* Set the value to represent TRUE in the database.
|
||||
* <p>
|
||||
* This is used for databases that do not support boolean natively.
|
||||
* </p>
|
||||
* <p>
|
||||
* The value set is either a Integer or a String (e.g. "1", or "T").
|
||||
* </p>
|
||||
*/
|
||||
public void setDatabaseBooleanTrue(String databaseBooleanTrue) {
|
||||
this.databaseBooleanTrue = databaseBooleanTrue;
|
||||
@@ -245,7 +261,6 @@ public class PlatformConfig {
|
||||
|
||||
/**
|
||||
* Add a custom type mapping.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set the default mapping for BigDecimal.class/decimal
|
||||
@@ -266,7 +281,6 @@ public class PlatformConfig {
|
||||
|
||||
/**
|
||||
* Add a custom type mapping that applies to all platforms.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set the default mapping for BigDecimal/decimal
|
||||
@@ -294,6 +308,7 @@ public class PlatformConfig {
|
||||
public void loadSettings(PropertiesWrapper p) {
|
||||
|
||||
idType = p.getEnum(IdType.class, "idType", idType);
|
||||
forUpdateNoKey = p.getBoolean("forUpdateNoKey", forUpdateNoKey);
|
||||
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
|
||||
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
|
||||
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
|
||||
@@ -334,7 +349,6 @@ public class PlatformConfig {
|
||||
*/
|
||||
public enum DbUuid {
|
||||
|
||||
|
||||
/**
|
||||
* Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40).
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import io.ebean.Database;
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The captured query plans.
|
||||
*/
|
||||
public class QueryPlanCapture {
|
||||
|
||||
private final Database database;
|
||||
private final List<MetaQueryPlan> plans;
|
||||
|
||||
public QueryPlanCapture(Database database, List<MetaQueryPlan> plans) {
|
||||
this.database = database;
|
||||
this.plans = plans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the database the plans were captured for.
|
||||
*/
|
||||
public Database database() {
|
||||
return database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated migrate to database().
|
||||
*/
|
||||
@Deprecated
|
||||
public Database getDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the captured query plans.
|
||||
*/
|
||||
public List<MetaQueryPlan> plans() {
|
||||
return plans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated migrate to plans().
|
||||
*/
|
||||
@Deprecated
|
||||
public List<MetaQueryPlan> getPlans() {
|
||||
return plans;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package io.ebean.config;
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL: Listener for captured query plans.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface QueryPlanListener {
|
||||
|
||||
/**
|
||||
* Process the captured query plans.
|
||||
*/
|
||||
void process(QueryPlanCapture capture);
|
||||
}
|
||||
@@ -1,47 +1,6 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import io.avaje.config.Config;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.annotation.Encrypted;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.cache.ServerCachePlugin;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbEncrypt;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.datasource.DataSourceConfig;
|
||||
import io.ebean.event.BeanFindController;
|
||||
import io.ebean.event.BeanPersistController;
|
||||
import io.ebean.event.BeanPersistListener;
|
||||
import io.ebean.event.BeanPostConstructListener;
|
||||
import io.ebean.event.BeanPostLoad;
|
||||
import io.ebean.event.BeanQueryAdapter;
|
||||
import io.ebean.event.BulkTableEventListener;
|
||||
import io.ebean.event.ServerConfigStartup;
|
||||
import io.ebean.event.changelog.ChangeLogListener;
|
||||
import io.ebean.event.changelog.ChangeLogPrepare;
|
||||
import io.ebean.event.changelog.ChangeLogRegister;
|
||||
import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.migration.MigrationRunner;
|
||||
import io.ebean.util.StringHelper;
|
||||
|
||||
import javax.persistence.EnumType;
|
||||
import javax.sql.DataSource;
|
||||
import java.time.Clock;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* Deprecated - please migrate to <code>io.ebean.DatabaseConfig</code>.
|
||||
|
||||
@@ -16,7 +16,7 @@ package io.ebean.config;
|
||||
*
|
||||
* public class EbeanConfigProvider implements ServerConfigProvider {
|
||||
*
|
||||
* @Override
|
||||
* @Override
|
||||
* public void apply(ServerConfig config) {
|
||||
*
|
||||
* // register the entity bean classes explicitly
|
||||
|
||||
@@ -20,7 +20,7 @@ public final class TableName {
|
||||
/**
|
||||
* The name.
|
||||
*/
|
||||
private String name;
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Construct with the given catalog schema and table name.
|
||||
@@ -29,7 +29,6 @@ public final class TableName {
|
||||
* </p>
|
||||
*/
|
||||
public TableName(String catalog, String schema, String name) {
|
||||
super();
|
||||
this.catalog = catalog != null ? catalog.trim() : null;
|
||||
this.schema = schema != null ? schema.trim() : null;
|
||||
this.name = name != null ? name.trim() : null;
|
||||
@@ -110,14 +109,11 @@ public final class TableName {
|
||||
* @return the qualified name
|
||||
*/
|
||||
public String getQualifiedName() {
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
|
||||
// Add catalog
|
||||
if (catalog != null) {
|
||||
buffer.append(catalog);
|
||||
}
|
||||
|
||||
// Add schema
|
||||
if (schema != null) {
|
||||
if (buffer.length() > 0) {
|
||||
@@ -125,31 +121,27 @@ public final class TableName {
|
||||
}
|
||||
buffer.append(schema);
|
||||
}
|
||||
|
||||
if (buffer.length() > 0) {
|
||||
buffer.append(".");
|
||||
}
|
||||
buffer.append(name);
|
||||
|
||||
return buffer.toString();
|
||||
return buffer.append(name).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a catalog and schema prefix if they exist to the string builder.
|
||||
*/
|
||||
public void appendCatalogAndSchema(StringBuilder buffer) {
|
||||
if (catalog != null) {
|
||||
buffer.append(catalog).append(".");
|
||||
}
|
||||
public String withCatalogAndSchema(String name) {
|
||||
if (schema != null) {
|
||||
buffer.append(schema).append(".");
|
||||
name = schema + "." + name;
|
||||
}
|
||||
if (catalog != null) {
|
||||
name = catalog + "." + name;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is table name is valid i.e. it has at least a name.
|
||||
*
|
||||
* @return true, if is valid
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return name != null && !name.isEmpty();
|
||||
|
||||
@@ -60,18 +60,6 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention {
|
||||
return toUnderscoreFromCamel(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts underscore based column name to Camel case property name.
|
||||
*
|
||||
* @param beanClass the bean class
|
||||
* @param dbColumnName the db column name
|
||||
* @return the property from column
|
||||
*/
|
||||
@Override
|
||||
public String getPropertyFromColumn(Class<?> beanClass, String dbColumnName) {
|
||||
return toCamelFromUnderscore(dbColumnName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the result will be upper case.
|
||||
* <p>
|
||||
|
||||
@@ -9,9 +9,6 @@ import java.sql.Types;
|
||||
* functions for varchar, date and timestamp. If they are left null then that is
|
||||
* treated as though that data type can not be encrypted in the DB and will
|
||||
* instead use java client encryption.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public abstract class AbstractDbEncrypt implements DbEncrypt {
|
||||
|
||||
@@ -47,13 +44,10 @@ public abstract class AbstractDbEncrypt implements DbEncrypt {
|
||||
case Types.CHAR:
|
||||
case Types.LONGVARCHAR:
|
||||
return varcharEncryptFunction;
|
||||
|
||||
case Types.DATE:
|
||||
return dateEncryptFunction;
|
||||
|
||||
case Types.TIMESTAMP:
|
||||
return timestampEncryptFunction;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import java.sql.Types;
|
||||
*/
|
||||
public class DatabasePlatform {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DatabasePlatform.class);
|
||||
private static final Logger log = LoggerFactory.getLogger("io.ebean");
|
||||
|
||||
/**
|
||||
* Behavior used when ending a query only transaction (at read committed isolation level).
|
||||
@@ -640,7 +640,7 @@ public class DatabasePlatform {
|
||||
if (dbName.charAt(dbName.length() - 1) == BACK_TICK) {
|
||||
return openQuote + dbName.substring(1, dbName.length() - 1) + closeQuote;
|
||||
} else {
|
||||
logger.error("Missing backquote on [" + dbName + "]");
|
||||
log.error("Missing backquote on [" + dbName + "]");
|
||||
}
|
||||
} else if (allQuotedIdentifiers) {
|
||||
return openQuote + dbName + closeQuote;
|
||||
@@ -679,23 +679,22 @@ public class DatabasePlatform {
|
||||
|
||||
public String completeSql(String sql, Query<?> query) {
|
||||
if (query.isForUpdate()) {
|
||||
sql = withForUpdate(sql, query.getForUpdateMode());
|
||||
sql = withForUpdate(sql, query.getForUpdateLockWait(), query.getForUpdateLockType());
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* For update hint on the FROM clause (SQL server only).
|
||||
*/
|
||||
public String fromForUpdate(Query.ForUpdate forUpdateMode) {
|
||||
public String fromForUpdate(Query.LockWait lockWait) {
|
||||
// return null except for sql server
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
// silently assume the database does not support the "for update" clause.
|
||||
logger.info("it seems your database does not support the 'for update' clause");
|
||||
log.info("it seems your database does not support the 'for update' clause");
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -729,7 +728,7 @@ public class DatabasePlatform {
|
||||
if (!schemaExists(dbSchema, connection)) {
|
||||
Statement query = connection.createStatement();
|
||||
try {
|
||||
logger.info("create schema:{}", dbSchema);
|
||||
log.debug("create schema:{}", dbSchema);
|
||||
query.executeUpdate("create schema " + dbSchema);
|
||||
} finally {
|
||||
JdbcClose.close(query);
|
||||
@@ -759,7 +758,6 @@ public class DatabasePlatform {
|
||||
* Return true if the table exists.
|
||||
*/
|
||||
public boolean tableExists(Connection connection, String catalog, String schema, String table) throws SQLException {
|
||||
|
||||
DatabaseMetaData metaData = connection.getMetaData();
|
||||
ResultSet tables = metaData.getTables(catalog, schema, table, null);
|
||||
try {
|
||||
|
||||
@@ -79,7 +79,7 @@ public class DbDefaultValue {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks & convert the {@link DbDefault#value()} to a valid SQL literal.
|
||||
* This method checks and converts the {@link DbDefault#value()} to a valid SQL literal.
|
||||
*
|
||||
* This is mainly to quote string literals and verify integer/dates for correctness.
|
||||
* <p>
|
||||
|
||||
@@ -70,7 +70,6 @@ public class DbPlatformTypeMapping {
|
||||
* Load the standard types. These can be overridden by DB specific platform.
|
||||
*/
|
||||
private void loadDefaults(boolean logicalTypes) {
|
||||
|
||||
put(DbType.BOOLEAN, BOOLEAN_LOGICAL);
|
||||
put(DbType.BIT);
|
||||
put(DbType.INTEGER);
|
||||
@@ -88,7 +87,6 @@ public class DbPlatformTypeMapping {
|
||||
put(DbType.LONGVARCHAR);
|
||||
// most commonly real maps to db float
|
||||
put(DbType.REAL, new DbPlatformType("float"));
|
||||
|
||||
put(DbType.POINT, POINT);
|
||||
put(DbType.POLYGON, POLYGON);
|
||||
put(DbType.LINESTRING, LINESTRING);
|
||||
@@ -103,7 +101,7 @@ public class DbPlatformTypeMapping {
|
||||
put(DbType.VARBINARY, new DbPlatformType("varbinary"));
|
||||
put(DbType.BINARY, new DbPlatformType("binary"));
|
||||
put(DbType.CHAR, new DbPlatformType("char"));
|
||||
|
||||
put(DbType.LOCALDATETIME, new DbPlatformType("localdatetime", false));
|
||||
put(DbType.HSTORE, new DbPlatformType("hstore", false));
|
||||
put(DbType.JSON, new DbPlatformType("json", false));
|
||||
put(DbType.JSONB, new DbPlatformType("jsonb", false));
|
||||
@@ -120,7 +118,7 @@ public class DbPlatformTypeMapping {
|
||||
put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
|
||||
put(DbType.BINARY, new DbPlatformType("binary", 255));
|
||||
put(DbType.CHAR, new DbPlatformType("char", 1));
|
||||
|
||||
put(DbType.LOCALDATETIME, DbType.TIMESTAMP.createPlatformType());
|
||||
put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON
|
||||
put(DbType.JSONB, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSONB
|
||||
put(DbType.JSONCLOB, JSON_CLOB_PLACEHOLDER);
|
||||
@@ -137,7 +135,6 @@ public class DbPlatformTypeMapping {
|
||||
* Lookup the platform specific DbType given the standard sql type name.
|
||||
*/
|
||||
public DbPlatformType lookup(String name, boolean withScale) {
|
||||
|
||||
DbType type = lookup.byName(name);
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Unknown type [" + name + "] - not standard sql type");
|
||||
@@ -160,7 +157,6 @@ public class DbPlatformTypeMapping {
|
||||
}
|
||||
|
||||
private DbPlatformType getJsonType(DbType type, boolean withScale) {
|
||||
|
||||
DbPlatformType dbType = get(type);
|
||||
if (dbType == JSON_CLOB_PLACEHOLDER) {
|
||||
// if we have scale that implies this maps to varchar
|
||||
|
||||
@@ -34,6 +34,7 @@ public enum DbType {
|
||||
|
||||
ARRAY(Types.ARRAY),
|
||||
|
||||
LOCALDATETIME(ExtraDbTypes.LOCALDATETIME),
|
||||
UUID(ExtraDbTypes.UUID),
|
||||
INET(ExtraDbTypes.INET),
|
||||
CIDR(ExtraDbTypes.CIDR),
|
||||
|
||||
@@ -5,11 +5,6 @@ package io.ebean.config.dbplatform;
|
||||
*/
|
||||
public interface ExtraDbTypes {
|
||||
|
||||
/**
|
||||
* DB native UUID type (H2 and Postgres).
|
||||
*/
|
||||
int UUID = 5010;
|
||||
|
||||
/**
|
||||
* Type to map Map content to Postgres HSTORE.
|
||||
*/
|
||||
@@ -40,6 +35,12 @@ public interface ExtraDbTypes {
|
||||
*/
|
||||
int JSONBlob = 5005;
|
||||
|
||||
int LOCALDATETIME = 5009;
|
||||
|
||||
/**
|
||||
* DB native UUID type (H2 and Postgres).
|
||||
*/
|
||||
int UUID = 5010;
|
||||
int INET = 5020;
|
||||
int CIDR = 5021;
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
@@ -23,26 +24,15 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger("io.ebean.SEQ");
|
||||
protected static final Logger log = LoggerFactory.getLogger("io.ebean.SEQ");
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final ReentrantLock loadLock = new ReentrantLock(false);
|
||||
|
||||
/**
|
||||
* The actual sequence name.
|
||||
*/
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
protected final String seqName;
|
||||
|
||||
protected final DataSource dataSource;
|
||||
|
||||
protected final BackgroundExecutor backgroundExecutor;
|
||||
|
||||
protected final NavigableSet<Long> idList = new TreeSet<>();
|
||||
|
||||
protected final int allocationSize;
|
||||
|
||||
protected boolean currentlyBackgroundLoading;
|
||||
protected AtomicBoolean currentlyBackgroundLoading = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* Construct given a dataSource and sql to return the next sequence value.
|
||||
@@ -128,27 +118,16 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
* Load another batch of Id's using a background thread.
|
||||
*/
|
||||
protected void loadInBackground(final int requestSize) {
|
||||
// single threaded processing...
|
||||
loadLock.lock();
|
||||
try {
|
||||
if (currentlyBackgroundLoading) {
|
||||
// skip as already background loading
|
||||
logger.debug("... skip background sequence load (another load in progress)");
|
||||
return;
|
||||
}
|
||||
currentlyBackgroundLoading = true;
|
||||
backgroundExecutor.execute(() -> {
|
||||
loadMore(requestSize);
|
||||
loadLock.lock();
|
||||
try {
|
||||
currentlyBackgroundLoading = false;
|
||||
} finally {
|
||||
loadLock.unlock();
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
loadLock.lock();
|
||||
if (currentlyBackgroundLoading.get()) {
|
||||
// skip as already background loading
|
||||
log.debug("... skip background sequence load (another load in progress)");
|
||||
return;
|
||||
}
|
||||
currentlyBackgroundLoading.set(true);
|
||||
backgroundExecutor.execute(() -> {
|
||||
loadMore(requestSize);
|
||||
currentlyBackgroundLoading.set(false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,8 +152,8 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
resultSet = statement.executeQuery();
|
||||
|
||||
List<Long> newIds = readIds(resultSet, requestSize);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("seq:{} loaded:{} sql:{}", seqName, newIds.size(), sql);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("seq:{} loaded:{} sql:{}", seqName, newIds.size(), sql);
|
||||
}
|
||||
if (newIds.isEmpty()) {
|
||||
throw new PersistenceException("Always expecting more than 1 row from " + sql);
|
||||
@@ -185,7 +164,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
} catch (SQLException e) {
|
||||
if (e.getMessage().contains("Database is already closed")) {
|
||||
String msg = "Error getting SEQ when DB shutting down " + e.getMessage();
|
||||
logger.error(msg);
|
||||
log.error(msg);
|
||||
System.out.println(msg);
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
|
||||
@@ -2,8 +2,6 @@ package io.ebean.config.dbplatform;
|
||||
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.util.JdbcClose;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
@@ -20,12 +18,8 @@ import java.sql.SQLException;
|
||||
*/
|
||||
public class SimpleSequenceIdGenerator implements PlatformIdGenerator {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SimpleSequenceIdGenerator.class);
|
||||
|
||||
private final String sql;
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
||||
private final String seqName;
|
||||
|
||||
/**
|
||||
@@ -61,7 +55,7 @@ public class SimpleSequenceIdGenerator implements PlatformIdGenerator {
|
||||
PreparedStatement pstmt = null;
|
||||
ResultSet rset = null;
|
||||
try {
|
||||
c = useTxnConnection ? t.getConnection() : dataSource.getConnection();
|
||||
c = useTxnConnection ? t.connection() : dataSource.getConnection();
|
||||
pstmt = c.prepareStatement(sql);
|
||||
rset = pstmt.executeQuery();
|
||||
if (rset.next()) {
|
||||
|
||||
+1
-4
@@ -26,7 +26,6 @@ public class ClickHousePlatform extends DatabasePlatform {
|
||||
|
||||
this.booleanDbType = Types.INTEGER;
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("UInt8"));
|
||||
|
||||
// using unsigned as default types ...
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("UInt8", false));
|
||||
dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("UInt16", false));
|
||||
@@ -34,15 +33,13 @@ public class ClickHousePlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("UInt64", false));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("Decimal", 16, 3));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("Float64", false));
|
||||
|
||||
dbTypeMap.put(DbType.DATE, new DbPlatformType("Date", false));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("DateTime", false));
|
||||
|
||||
dbTypeMap.put(DbType.LOCALDATETIME, new DbPlatformType("DateTime", false));
|
||||
dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("String", false));
|
||||
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("String", false));
|
||||
dbTypeMap.put(DbType.CLOB, new DbPlatformType("String", false));
|
||||
dbTypeMap.put(DbType.JSONVARCHAR, new DbPlatformType("String", false));
|
||||
|
||||
dbTypeMap.put(DbType.UUID, new DbPlatformType("UUID", false));
|
||||
dbTypeMap.put(DbType.INET, new DbPlatformType("String", false));
|
||||
dbTypeMap.put(DbType.CIDR, new DbPlatformType("String", false));
|
||||
|
||||
@@ -5,8 +5,6 @@ import io.ebean.config.dbplatform.DbEncryptFunction;
|
||||
|
||||
/**
|
||||
* H2 encryption support via encrypt decrypt function.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class H2DbEncrypt extends AbstractDbEncrypt {
|
||||
|
||||
|
||||
@@ -4,11 +4,7 @@ import org.h2.api.Trigger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
@@ -16,7 +12,7 @@ import java.util.Arrays;
|
||||
*/
|
||||
public class H2HistoryTrigger implements Trigger {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(H2HistoryTrigger.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(H2HistoryTrigger.class);
|
||||
|
||||
/**
|
||||
* Hardcoding the column and history table suffix for now. Not sure how to get that
|
||||
@@ -43,7 +39,6 @@ public class H2HistoryTrigger implements Trigger {
|
||||
|
||||
@Override
|
||||
public void init(Connection conn, String schemaName, String triggerName, String tableName, boolean before, int type) throws SQLException {
|
||||
|
||||
// get the columns for the table
|
||||
ResultSet rs = conn.getMetaData().getColumns(null, schemaName, tableName, null);
|
||||
|
||||
@@ -74,12 +69,11 @@ public class H2HistoryTrigger implements Trigger {
|
||||
insertSql.append(");");
|
||||
|
||||
this.insertHistorySql = insertSql.toString();
|
||||
logger.debug("History table insert sql: {}", insertHistorySql);
|
||||
log.debug("History table insert sql: {}", insertHistorySql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fire(Connection connection, Object[] oldRow, Object[] newRow) throws SQLException {
|
||||
|
||||
if (oldRow != null) {
|
||||
// a delete or update event
|
||||
Timestamp now = new Timestamp(System.currentTimeMillis());
|
||||
@@ -88,8 +82,8 @@ public class H2HistoryTrigger implements Trigger {
|
||||
// update event. Set the effective start timestamp to now.
|
||||
newRow[effectStartPosition] = now;
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("History insert: {}", Arrays.toString(oldRow));
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("History insert: {}", Arrays.toString(oldRow));
|
||||
}
|
||||
insertIntoHistory(connection, oldRow);
|
||||
}
|
||||
@@ -99,7 +93,6 @@ public class H2HistoryTrigger implements Trigger {
|
||||
* Insert the data into the history table.
|
||||
*/
|
||||
private void insertIntoHistory(Connection connection, Object[] oldRow) throws SQLException {
|
||||
|
||||
try (PreparedStatement stmt = connection.prepareStatement(insertHistorySql)) {
|
||||
for (int i = 0; i < oldRow.length; i++) {
|
||||
stmt.setObject(i + 1, oldRow[i]);
|
||||
@@ -110,11 +103,11 @@ public class H2HistoryTrigger implements Trigger {
|
||||
|
||||
@Override
|
||||
public void close() throws SQLException {
|
||||
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() throws SQLException {
|
||||
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class H2Platform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
// NOWAIT and SKIP LOCKED currently not supported with H2
|
||||
return sql + " for update";
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebean.config.dbplatform.hana;
|
||||
|
||||
import io.ebean.Query.ForUpdate;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.Query.LockWait;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.PlatformConfig;
|
||||
@@ -68,16 +69,16 @@ public class HanaPlatform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
case BASE:
|
||||
protected String withForUpdate(String sql, LockWait lockWait, Query.LockType lockType) {
|
||||
switch (lockWait) {
|
||||
case WAIT:
|
||||
return sql + " for update";
|
||||
case NOWAIT:
|
||||
return sql + " for update nowait";
|
||||
case SKIPLOCKED:
|
||||
return sql + " for update ignore locked";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown update mode: " + forUpdateMode.name());
|
||||
throw new IllegalArgumentException("Unknown update mode: " + lockWait);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ public abstract class BaseMySqlPlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(DbType.BIT, new DbPlatformType("tinyint(1)"));
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("tinyint(1)"));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime(6)"));
|
||||
dbTypeMap.put(DbType.LOCALDATETIME, new DbPlatformType("datetime(6)"));
|
||||
dbTypeMap.put(DbType.CLOB, new MySqlClob());
|
||||
dbTypeMap.put(DbType.BLOB, new MySqlBlob());
|
||||
dbTypeMap.put(DbType.BINARY, new DbPlatformType("binary", 255));
|
||||
@@ -60,7 +61,7 @@ public abstract class BaseMySqlPlatform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
// NOWAIT and SKIP LOCKED currently not supported with MySQL
|
||||
return sql + " for update";
|
||||
}
|
||||
|
||||
@@ -10,5 +10,6 @@ public class MySql55Platform extends BaseMySqlPlatform {
|
||||
super();
|
||||
this.platform = Platform.MYSQL55;
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime"));
|
||||
dbTypeMap.put(DbType.LOCALDATETIME, new DbPlatformType("datetime"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import io.ebean.config.dbplatform.DbEncryptFunction;
|
||||
|
||||
/**
|
||||
* MySql aes_encrypt aes_decrypt based encryption support.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class MySqlDbEncrypt extends AbstractDbEncrypt {
|
||||
|
||||
|
||||
@@ -48,8 +48,8 @@ public class NuoDbPlatform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
switch (lockWait) {
|
||||
case NOWAIT:
|
||||
return sql + " for update nowait";
|
||||
case SKIPLOCKED:
|
||||
|
||||
@@ -11,8 +11,8 @@ public class Oracle11Platform extends OraclePlatform {
|
||||
public Oracle11Platform() {
|
||||
super();
|
||||
this.platform = Platform.ORACLE11;
|
||||
this.columnAliasPrefix = "c";
|
||||
this.sqlLimiter = new OracleRownumSqlLimiter();
|
||||
this.basicSqlLimiter = new OracleRownumBasicLimiter();
|
||||
dbIdentity.setIdType(IdType.SEQUENCE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ public class OracleDbEncrypt extends AbstractDbEncrypt {
|
||||
* @param decryptFunction the decrypt stored procedure
|
||||
*/
|
||||
public OracleDbEncrypt(String encryptFunction, String decryptFunction) {
|
||||
|
||||
this.varcharEncryptFunction = new OraVarcharFunction(encryptFunction, decryptFunction);
|
||||
this.dateEncryptFunction = new OraDateFunction(encryptFunction, decryptFunction);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
public OraclePlatform() {
|
||||
super();
|
||||
this.platform = Platform.ORACLE;
|
||||
this.columnAliasPrefix = "c";
|
||||
this.supportsDeleteTableAlias = true;
|
||||
this.maxTableNameLength = 30;
|
||||
this.maxConstraintNameLength = 30;
|
||||
@@ -79,8 +80,8 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
switch (lockWait) {
|
||||
case SKIPLOCKED:
|
||||
return sql + " for update skip locked";
|
||||
case NOWAIT:
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package io.ebean.config.dbplatform.oracle;
|
||||
|
||||
import io.ebean.config.dbplatform.BasicSqlLimiter;
|
||||
|
||||
/**
|
||||
* Row limiter for Oracle 9,10,11 using rownum.
|
||||
*/
|
||||
public class OracleRownumBasicLimiter implements BasicSqlLimiter {
|
||||
|
||||
@Override
|
||||
public String limit(String dbSql, int firstRow, int maxRows) {
|
||||
if (firstRow < 1 && maxRows < 1) {
|
||||
return dbSql;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(60 + dbSql.length());
|
||||
int lastRow = maxRows;
|
||||
if (lastRow > 0) {
|
||||
lastRow += firstRow;
|
||||
}
|
||||
sb.append("select * from (select ");
|
||||
if (maxRows > 0) {
|
||||
sb.append("/*+ FIRST_ROWS(").append(maxRows).append(") */ ");
|
||||
}
|
||||
sb.append("a.*, rownum rn_ from (");
|
||||
sb.append(dbSql).append(") a ");
|
||||
if (lastRow > 0) {
|
||||
sb.append(" where rownum <= ").append(lastRow);
|
||||
}
|
||||
sb.append(") ");
|
||||
if (firstRow > 0) {
|
||||
sb.append(" where rn_ > ").append(firstRow);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.annotation.PartitionMode;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.PlatformConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
@@ -25,6 +26,15 @@ import java.sql.Types;
|
||||
*/
|
||||
public class PostgresPlatform extends DatabasePlatform {
|
||||
|
||||
private static final String SKIP_LOCKED = " skip locked";
|
||||
private static final String NO_WAIT = " nowait";
|
||||
private static final String FOR_UPDATE = " for update";
|
||||
private static final String FOR_NO_KEY_UPDATE = " for no key update";
|
||||
private static final String FOR_SHARE = " for share";
|
||||
private static final String FOR_KEY_SHARE = " for key share";
|
||||
|
||||
private boolean forUpdateNoKey;
|
||||
|
||||
public PostgresPlatform() {
|
||||
super();
|
||||
this.platform = Platform.POSTGRES;
|
||||
@@ -59,28 +69,31 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
|
||||
DbPlatformType dbTypeText = new DbPlatformType("text", false);
|
||||
DbPlatformType dbBytea = new DbPlatformType("bytea", false);
|
||||
|
||||
dbTypeMap.put(DbType.UUID, new DbPlatformType("uuid", false));
|
||||
dbTypeMap.put(DbType.INET, new DbPlatformType("inet", false));
|
||||
dbTypeMap.put(DbType.CIDR, new DbPlatformType("cidr", false));
|
||||
dbTypeMap.put(DbType.HSTORE, new DbPlatformType("hstore", false));
|
||||
dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false));
|
||||
dbTypeMap.put(DbType.JSONB, new DbPlatformType("jsonb", false));
|
||||
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("timestamptz"));
|
||||
|
||||
dbTypeMap.put(DbType.LOCALDATETIME, new DbPlatformType("timestamp"));
|
||||
dbTypeMap.put(DbType.BINARY, dbBytea);
|
||||
dbTypeMap.put(DbType.VARBINARY, dbBytea);
|
||||
|
||||
dbTypeMap.put(DbType.BLOB, dbBytea);
|
||||
dbTypeMap.put(DbType.CLOB, dbTypeText);
|
||||
dbTypeMap.put(DbType.LONGVARBINARY, dbBytea);
|
||||
dbTypeMap.put(DbType.LONGVARCHAR, dbTypeText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(PlatformConfig config) {
|
||||
super.configure(config);
|
||||
forUpdateNoKey = config.isForUpdateNoKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addGeoTypes(int srid) {
|
||||
dbTypeMap.put(DbType.POINT, geoType("point", srid));
|
||||
@@ -108,22 +121,32 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
*/
|
||||
@Override
|
||||
public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) {
|
||||
|
||||
return new PostgresSequenceIdGenerator(be, ds, seqName, sequenceBatchSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
switch (lockWait) {
|
||||
case SKIPLOCKED:
|
||||
return sql + " for update skip locked";
|
||||
return sql + lock(lockType) + SKIP_LOCKED;
|
||||
case NOWAIT:
|
||||
return sql + " for update nowait";
|
||||
return sql + lock(lockType) + NO_WAIT;
|
||||
default:
|
||||
return sql + " for update";
|
||||
return sql + lock(lockType);
|
||||
}
|
||||
}
|
||||
|
||||
private String lock(Query.LockType lockType) {
|
||||
switch (lockType) {
|
||||
case UPDATE: return FOR_UPDATE;
|
||||
case NO_KEY_UPDATE: return FOR_NO_KEY_UPDATE;
|
||||
case SHARE: return FOR_SHARE;
|
||||
case KEY_SHARE: return FOR_KEY_SHARE;
|
||||
case DEFAULT: return forUpdateNoKey ? FOR_NO_KEY_UPDATE : FOR_UPDATE;
|
||||
}
|
||||
return FOR_UPDATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tablePartitionsExist(Connection connection, String table) throws SQLException {
|
||||
try (PreparedStatement statement = connection.prepareStatement("select count(*) from pg_inherits i WHERE i.inhparent = ?::regclass")) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user