mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
577
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae68d41519 | ||
|
|
722692d934 | ||
|
|
21a3f322e1 | ||
|
|
0d175557b0 | ||
|
|
57ccd19fe6 | ||
|
|
9674711516 | ||
|
|
9155716752 | ||
|
|
d7d8c3e651 | ||
|
|
16f6f2ee7f | ||
|
|
fea6dfd62b | ||
|
|
464ed4322e | ||
|
|
c3f556f0dc | ||
|
|
ba6810891e | ||
|
|
c530883e5e | ||
|
|
06542b031e | ||
|
|
4b5365e708 | ||
|
|
1d471fee92 | ||
|
|
3825dea00a | ||
|
|
3fd130ac4c | ||
|
|
196645e7a2 | ||
|
|
f5459920e9 | ||
|
|
ee6452cfb0 | ||
|
|
ad7e18561b | ||
|
|
c640524bfc | ||
|
|
fea840c859 | ||
|
|
bb7df71391 | ||
|
|
cb6f0335b1 | ||
|
|
762899ef10 | ||
|
|
848d4f031e | ||
|
|
481f828507 | ||
|
|
b3d0c21a80 | ||
|
|
a115cdf095 | ||
|
|
410e9d475b | ||
|
|
462385c7d0 | ||
|
|
3655e2c6f8 | ||
|
|
318f6ae3f5 | ||
|
|
c63acad7e0 | ||
|
|
6dba4a3d28 | ||
|
|
ecf1e53616 | ||
|
|
0ff9a00427 | ||
|
|
725ff8dc58 | ||
|
|
a780dc133e | ||
|
|
b111fcfecc | ||
|
|
114693b7cd | ||
|
|
5a39dcb39c | ||
|
|
b04f887bc3 | ||
|
|
5c38561049 | ||
|
|
f40eb011c3 | ||
|
|
a08cf548e7 | ||
|
|
f12f0d7f7a | ||
|
|
0c53efcbbc | ||
|
|
1aeed8ad12 | ||
|
|
bcb136b692 | ||
|
|
8b670fd615 | ||
|
|
970bc8e973 | ||
|
|
007b06e9db | ||
|
|
4513dbf29d | ||
|
|
53bcc62a0c | ||
|
|
858c55c978 | ||
|
|
cedba089e1 | ||
|
|
cbf7811f7c | ||
|
|
ea13b322ca | ||
|
|
486a8cf1c0 | ||
|
|
bfe46432da | ||
|
|
272eae5f22 | ||
|
|
502104eba8 | ||
|
|
fa45c79bd2 | ||
|
|
ee4d1bf866 | ||
|
|
dcf7b60d37 | ||
|
|
0663a97941 | ||
|
|
f31ab4d6a8 | ||
|
|
f77388738b | ||
|
|
945175c533 | ||
|
|
7d37c6cfd8 | ||
|
|
496672b394 | ||
|
|
1ffe359573 | ||
|
|
23cd9b6a93 | ||
|
|
333ac8edd9 | ||
|
|
081cb20260 | ||
|
|
53f1da32be | ||
|
|
5544a2cc3e | ||
|
|
84c3008db1 | ||
|
|
d949d4d6a2 | ||
|
|
03669dc307 | ||
|
|
2a8fad7364 | ||
|
|
e62db11f01 | ||
|
|
8c8f2b95da | ||
|
|
576eb01187 | ||
|
|
8b18b2a20e | ||
|
|
f5c12a916d | ||
|
|
2f8a99c304 | ||
|
|
cd9a43c3ab | ||
|
|
f251ca5431 | ||
|
|
2c44c80f65 | ||
|
|
d9efeac0a1 | ||
|
|
f4a7d0b6ad | ||
|
|
bc5db1e46a | ||
|
|
8743148238 | ||
|
|
68db6723d0 | ||
|
|
9b1fa43792 | ||
|
|
5f2454831e | ||
|
|
140178bb47 | ||
|
|
f95b4b5c4b | ||
|
|
d3b3a79342 | ||
|
|
52398317bc | ||
|
|
7f2e4f54ff | ||
|
|
9f19ed5376 | ||
|
|
d49a7c415f | ||
|
|
8ffc9ede85 | ||
|
|
eba521563a | ||
|
|
ed71e106df | ||
|
|
050ae49f6b | ||
|
|
d5d9a897ae | ||
|
|
ddf200ffdd | ||
|
|
7fa5e2aa8c | ||
|
|
8bfae9deef | ||
|
|
e6c9f151c1 | ||
|
|
30a0935300 | ||
|
|
b4182d4519 | ||
|
|
93cc0399f1 | ||
|
|
5404dab5a3 | ||
|
|
d70da1d805 | ||
|
|
2225d5b7e8 | ||
|
|
270369bd65 | ||
|
|
a932d61a94 | ||
|
|
24b08663af | ||
|
|
bb6c9c84ba | ||
|
|
a1e185b0f6 | ||
|
|
e2a467ca5a | ||
|
|
4b28933298 | ||
|
|
6077acf134 | ||
|
|
8a4ffd21ab | ||
|
|
d1314124af | ||
|
|
36f018b6aa | ||
|
|
87ccb6e333 | ||
|
|
3432c365f6 | ||
|
|
b7d5aa344f | ||
|
|
7e768623e4 | ||
|
|
73ab2ee1fe | ||
|
|
122fed448c | ||
|
|
6e52bee91f | ||
|
|
cc26afad13 | ||
|
|
bf20449fb5 | ||
|
|
6af5fae8e9 | ||
|
|
e26a38ecaa | ||
|
|
1cdf68f1c0 | ||
|
|
2923dd1d96 | ||
|
|
9067508e1d | ||
|
|
385cc76e34 | ||
|
|
c14cb4b85e | ||
|
|
52644647e4 | ||
|
|
3bf9dd6743 | ||
|
|
aececa2199 | ||
|
|
b4e22a4ca7 | ||
|
|
9b8b4414c4 | ||
|
|
b8fd2c7a02 | ||
|
|
a94f5d74ca | ||
|
|
3829613c37 | ||
|
|
0762eaf0ab | ||
|
|
7fbdab6220 | ||
|
|
cf4d45befb | ||
|
|
dcd81a857d | ||
|
|
0cac723eac | ||
|
|
c6ba4d8155 | ||
|
|
201958f38c | ||
|
|
9326c9c79e | ||
|
|
1042fdb280 | ||
|
|
197056dbc5 | ||
|
|
895b5ee4ff | ||
|
|
c839fe6520 | ||
|
|
2678f85506 | ||
|
|
2b1b4af7a2 | ||
|
|
4218b8a2e8 | ||
|
|
fe7d73a4a4 | ||
|
|
81e86b07e3 | ||
|
|
910c04e373 | ||
|
|
205f1f5e89 | ||
|
|
a1a6d2b725 | ||
|
|
30da589ea0 | ||
|
|
c66e9547e1 | ||
|
|
73990e3fb7 | ||
|
|
f7920de3c2 | ||
|
|
3dd5069f5a | ||
|
|
1d363776ec | ||
|
|
c512eb564d | ||
|
|
7f332e91ff | ||
|
|
8e9d644bc6 | ||
|
|
fa5ce9cbba | ||
|
|
b7905daeb5 | ||
|
|
9da7c9468e | ||
|
|
9eee224e03 | ||
|
|
906d5f04ad | ||
|
|
654c3f7f67 | ||
|
|
c61e6b04a2 | ||
|
|
f893653090 | ||
|
|
579c1efcf6 | ||
|
|
662f9cdeb3 | ||
|
|
b4782425f8 | ||
|
|
2648423930 | ||
|
|
b62cea5073 | ||
|
|
c10ad11b8b | ||
|
|
4aa8a0dc63 | ||
|
|
e4569f9362 | ||
|
|
ed83bababc | ||
|
|
b746c83ed7 | ||
|
|
8e45462c2c | ||
|
|
9fdb375229 | ||
|
|
7e6d059ef1 | ||
|
|
856a3a6fdd | ||
|
|
f94c3e81e5 | ||
|
|
4bf9e2b18e | ||
|
|
112de29964 | ||
|
|
c5d761076a | ||
|
|
4bedefa494 | ||
|
|
a5e3a70921 | ||
|
|
f6f4368048 | ||
|
|
e700f1c83c | ||
|
|
dc5ac02952 | ||
|
|
b89371acd1 | ||
|
|
6c88325dad | ||
|
|
ecec966a85 | ||
|
|
c46ac04c0a | ||
|
|
25e6d05542 | ||
|
|
d3ead5d2f9 | ||
|
|
28a70fa550 | ||
|
|
cf31830cbc | ||
|
|
b4105ab5d0 | ||
|
|
1bb2b1318e | ||
|
|
65fa1c056b | ||
|
|
242945aa18 | ||
|
|
5e77be6e6d | ||
|
|
8c0d6b1a72 | ||
|
|
86436ac3ac | ||
|
|
ae228d6b0e | ||
|
|
410d1a9b37 | ||
|
|
f667a73dc1 | ||
|
|
4509c6b1ed | ||
|
|
d32559baf4 | ||
|
|
2639e799c5 | ||
|
|
46c66b7169 | ||
|
|
30ae435f33 | ||
|
|
4f4743807c | ||
|
|
7b7a492241 | ||
|
|
4af8e53315 | ||
|
|
1c6fa575f2 | ||
|
|
2430404e1f | ||
|
|
d433e0ea46 | ||
|
|
42591a5a87 | ||
|
|
65a62bf683 | ||
|
|
3e3f3c35e7 | ||
|
|
f4db7ca0bb | ||
|
|
b0e487cfbd | ||
|
|
23fd29ddf1 | ||
|
|
f21cac5d4f | ||
|
|
c2e5619f70 | ||
|
|
18e0ff7067 | ||
|
|
4119c02f0d | ||
|
|
8985d37aed | ||
|
|
23e035894f | ||
|
|
32b8fd0e26 | ||
|
|
4971db54c8 | ||
|
|
e417b3cde2 | ||
|
|
d23ca31e42 | ||
|
|
c9b71ae373 | ||
|
|
f06f21cf5e | ||
|
|
f8b97ff397 | ||
|
|
fc032c632b | ||
|
|
54534ea7f3 | ||
|
|
812dcbb4bb | ||
|
|
a3d4b57b94 | ||
|
|
61479d365a | ||
|
|
3ba9a52b0e | ||
|
|
518ba37fb2 | ||
|
|
fd6a7f64eb | ||
|
|
8b073ef10a | ||
|
|
6a7555055d | ||
|
|
eb31f1bfce | ||
|
|
2e4f99318a | ||
|
|
409c1d06b2 | ||
|
|
01f2881940 | ||
|
|
aef512a851 | ||
|
|
435e1f61fe | ||
|
|
0230e3e253 | ||
|
|
770364fd1a | ||
|
|
fbc2d70967 | ||
|
|
276e865f72 | ||
|
|
9ded3890d7 | ||
|
|
bfeb0cd667 | ||
|
|
119049b696 | ||
|
|
33ff113585 | ||
|
|
17e0953cad | ||
|
|
e3ca5d2419 | ||
|
|
a5f435dbcf | ||
|
|
aa1e021501 | ||
|
|
7ea6f16207 | ||
|
|
197852857d | ||
|
|
e7e6e00473 | ||
|
|
933c791d33 | ||
|
|
043c523c2a | ||
|
|
82247fd4e4 | ||
|
|
27f86548a6 | ||
|
|
7e8424328f | ||
|
|
923828ce87 | ||
|
|
e195f20981 | ||
|
|
86d0216159 | ||
|
|
a4698ea1b6 | ||
|
|
888384f7db | ||
|
|
817c946eeb | ||
|
|
1749c2cb4c | ||
|
|
3afd3c4530 | ||
|
|
e5f98f1b7a | ||
|
|
2e496c9e1e | ||
|
|
5975694538 | ||
|
|
03a42f7f6e | ||
|
|
84f1e05eb4 | ||
|
|
da20ced1ed | ||
|
|
1f1a6e2c04 | ||
|
|
6b83800a83 | ||
|
|
c344551e4d | ||
|
|
6b4aff7191 | ||
|
|
fc7fae35c9 | ||
|
|
7929d8c0b8 | ||
|
|
058766dd92 | ||
|
|
4fdb8a77b4 | ||
|
|
56be1fc047 | ||
|
|
192a946cf6 | ||
|
|
aa7b15fd6e | ||
|
|
cb74ef01e0 | ||
|
|
829dfcb013 | ||
|
|
25b6d2a5a0 | ||
|
|
14fbc3a955 | ||
|
|
e41da2f995 | ||
|
|
ea60e42a4d | ||
|
|
efce6b57e1 | ||
|
|
988e4c7386 | ||
|
|
9e1d7ab722 | ||
|
|
0c03a8b925 | ||
|
|
37a66f1ee2 | ||
|
|
a02673359d | ||
|
|
f9d13cbba7 | ||
|
|
f787483e30 | ||
|
|
9e33f36808 | ||
|
|
6a7e6caa66 | ||
|
|
5a4a0e3886 | ||
|
|
c3f586c461 | ||
|
|
99f7243d6c | ||
|
|
7026c00290 | ||
|
|
448d94a335 | ||
|
|
961a7ef7ea | ||
|
|
5cef1ad017 | ||
|
|
b814ca6e81 | ||
|
|
a24e6b6064 | ||
|
|
b751823abb | ||
|
|
f3cb7e2cfd | ||
|
|
31d7c6fed8 | ||
|
|
c5fb1dbe23 | ||
|
|
b7770a9617 | ||
|
|
41abf34ef6 | ||
|
|
89beaee0f6 | ||
|
|
5052afbd07 | ||
|
|
d89a58482c | ||
|
|
eb1bca805e | ||
|
|
9cb66b112f | ||
|
|
210901ee2d | ||
|
|
396fb49acd | ||
|
|
a83896f1ff | ||
|
|
3483372ae3 | ||
|
|
4e1f817ade | ||
|
|
d4139aa8ef | ||
|
|
a6cfed7c44 | ||
|
|
cc17ea8911 | ||
|
|
141f0a8b16 | ||
|
|
9dbd903a73 | ||
|
|
b8105190d1 | ||
|
|
ef3d911e19 | ||
|
|
31fd0b7ed5 | ||
|
|
26d1288757 | ||
|
|
1d49e5b341 | ||
|
|
4a0806e453 | ||
|
|
ab48f796c6 | ||
|
|
0cb8bb0415 | ||
|
|
471691c747 | ||
|
|
c86e6b3cf9 | ||
|
|
b399713a85 | ||
|
|
f8d4ad7f33 | ||
|
|
7984a9ccd1 | ||
|
|
27cda09523 | ||
|
|
20fc23c19c | ||
|
|
bac53a5d75 | ||
|
|
2e0690efa9 | ||
|
|
fdd9b1905c | ||
|
|
fc966618a6 | ||
|
|
669ba7837a | ||
|
|
0edf90056c | ||
|
|
6b27a9d280 | ||
|
|
2b0669c2ae | ||
|
|
9fc10e8e04 | ||
|
|
fb5eb0cdd2 | ||
|
|
3351882915 | ||
|
|
31c6d16e73 | ||
|
|
cd8c12a9a8 | ||
|
|
3207ae1f08 | ||
|
|
5fe532c393 | ||
|
|
93b9cbf9ac | ||
|
|
8a34d6050b | ||
|
|
ab3e6ccbf7 | ||
|
|
cc58fc8195 | ||
|
|
1c34c09f3c | ||
|
|
8544712448 | ||
|
|
5e22079366 | ||
|
|
903b0a3929 | ||
|
|
b18bc82b8a | ||
|
|
50de32af29 | ||
|
|
0b18189e62 | ||
|
|
0b6e73d729 | ||
|
|
3108076953 | ||
|
|
7ed4435ccc | ||
|
|
7aef4ff1bd | ||
|
|
5bcad17ae1 | ||
|
|
b1beb0b787 | ||
|
|
585eb2b57b | ||
|
|
2653ec50aa | ||
|
|
cb4432a588 | ||
|
|
4d93b70bf9 | ||
|
|
0b299edf0d | ||
|
|
cf10246783 | ||
|
|
babba914a0 | ||
|
|
0397140e0b | ||
|
|
82def2710e | ||
|
|
60ad417e1b | ||
|
|
3af1b574fd | ||
|
|
60c8683914 | ||
|
|
72263c0af0 | ||
|
|
f66316138d | ||
|
|
b403942491 | ||
|
|
baa3909c63 | ||
|
|
81f42f8e95 | ||
|
|
0377e3ec5c | ||
|
|
58f6c67d78 | ||
|
|
84f7fc5d81 | ||
|
|
ea02bebc6f | ||
|
|
da874d84a8 | ||
|
|
049cacad1c | ||
|
|
ced8c79458 | ||
|
|
a66edf8077 | ||
|
|
94591954b3 | ||
|
|
e611353163 | ||
|
|
e7811910e9 | ||
|
|
138b587ff7 | ||
|
|
8fc6c4c648 | ||
|
|
ebdc28e1cd | ||
|
|
51f79e769c | ||
|
|
c2a69714ca | ||
|
|
f3213e7b90 | ||
|
|
55de997297 | ||
|
|
65890f9777 | ||
|
|
41c1e7260c | ||
|
|
7d35789db4 | ||
|
|
d266d6d440 | ||
|
|
6d5374e66a | ||
|
|
8410de8831 | ||
|
|
4b0230e862 | ||
|
|
fa96f81f8c | ||
|
|
a5fea5e9be | ||
|
|
bafba0babf | ||
|
|
e4088c5fbe | ||
|
|
0405ceb96c | ||
|
|
ebf96c87bf | ||
|
|
fcaf11f262 | ||
|
|
05df47c0d7 | ||
|
|
a8892292fb | ||
|
|
e876ef8d87 | ||
|
|
315b39813b | ||
|
|
6d5e0c4766 | ||
|
|
a2ce17aec0 | ||
|
|
fcffa92c55 | ||
|
|
7fda8079c2 | ||
|
|
cca9bb4427 | ||
|
|
f45089240a | ||
|
|
8252a51545 | ||
|
|
c440c768cf | ||
|
|
c6ae501354 | ||
|
|
70e2b1c2ae | ||
|
|
211f28eea3 | ||
|
|
174fe46485 | ||
|
|
890cc6f66d | ||
|
|
2f0e5e6e46 | ||
|
|
54ba78218b | ||
|
|
ba16cea405 | ||
|
|
e81a61378c | ||
|
|
b4154031cc | ||
|
|
ecf5b56652 | ||
|
|
426c6c8111 | ||
|
|
9dbb69f4f4 | ||
|
|
83776a1eae | ||
|
|
6bc72ae6bb | ||
|
|
4fe2016891 | ||
|
|
7be4675d3e | ||
|
|
06b71781f5 | ||
|
|
55e4c7bc26 | ||
|
|
b3584a81b4 | ||
|
|
68da8944ed | ||
|
|
903ee35d63 | ||
|
|
658ee3d39f | ||
|
|
c074b7c457 | ||
|
|
528ad7c7fb | ||
|
|
c3f41f4157 | ||
|
|
33d104e6aa | ||
|
|
4bd3a0f293 | ||
|
|
54a4fd75f1 | ||
|
|
105f08cca1 | ||
|
|
01d9dd3fe8 | ||
|
|
f09b38c58c | ||
|
|
cb6d2e7ec0 | ||
|
|
89c0324e42 | ||
|
|
7b4215f4f8 | ||
|
|
e4cb5f0443 | ||
|
|
ec24374d72 | ||
|
|
cfba4d2deb | ||
|
|
0ab019ca2c | ||
|
|
8c9dae0f88 | ||
|
|
88a0c34d37 | ||
|
|
ce403e72a7 | ||
|
|
3c6a52da31 | ||
|
|
2806972032 | ||
|
|
acd6ba0a42 | ||
|
|
b386c9a5a8 | ||
|
|
c5536aaeec | ||
|
|
1b2bfc5df8 | ||
|
|
808004165c | ||
|
|
61eedb4e9a | ||
|
|
662ffdd070 | ||
|
|
13a5511318 | ||
|
|
0f9c98964e | ||
|
|
b87e6d90f6 | ||
|
|
166906a814 | ||
|
|
1733d2382c | ||
|
|
a6f9120905 | ||
|
|
32b599512b | ||
|
|
34fd24d620 | ||
|
|
f928923b5b | ||
|
|
1f928e65a4 | ||
|
|
d920d8eb76 | ||
|
|
23d2c64046 | ||
|
|
19d29cd836 | ||
|
|
f14c3e8cb4 | ||
|
|
b9ca8be95a | ||
|
|
d627bb47e2 | ||
|
|
d395c666fc | ||
|
|
939397acfc | ||
|
|
fecb5fa731 | ||
|
|
bdc9917811 | ||
|
|
afcd6859e0 | ||
|
|
fef87323b3 | ||
|
|
6909b20a9e | ||
|
|
c1a479e1f4 | ||
|
|
e06967ff4a | ||
|
|
156469ae0f | ||
|
|
1d1d479dda | ||
|
|
d185ea5962 | ||
|
|
2dbb5ea80d | ||
|
|
158ee9a081 | ||
|
|
b1410cc660 | ||
|
|
4c2e9ccacd | ||
|
|
29aa395cd4 | ||
|
|
8160d1f01c | ||
|
|
6fd76ff697 | ||
|
|
249cc5df49 | ||
|
|
2646e8c27f | ||
|
|
3eaf47fd70 | ||
|
|
9d64352771 | ||
|
|
aa7325b249 | ||
|
|
2839434773 | ||
|
|
de9823b69b | ||
|
|
15cab24848 | ||
|
|
b87e360ac7 | ||
|
|
82e68d7756 |
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
custom: https://ebean.io/sponsors
|
||||
@@ -3,6 +3,7 @@ sudo: required
|
||||
language: java
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
- openjdk11
|
||||
|
||||
git:
|
||||
depth: 3
|
||||
|
||||
@@ -1,8 +1,39 @@
|
||||
[](https://travis-ci.org/ebean-orm/ebean)
|
||||
[](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean)
|
||||
|
||||
# Sponsors
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.foconis.de/" target="_blank">
|
||||
<img width="222px" src="https://www.foconis.de/templates/yootheme/cache/foconis_logo_322-709da1de.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.payintech.com/" target="_blank">
|
||||
<img width="222px" src="https://ebean.io/images/sponsor_PayinTech-logo-noir.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.premium-minds.com" target="_blank">
|
||||
<img width="222px" src="https://ebean.io/images/logo-med-principal.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://timerbee.de" target="_blank">
|
||||
<img width="222px" src="https://ebean.io/images/logo-timerbee.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
# Need help?
|
||||
Post questions or issues to the Ebean google group - https://groups.google.com/forum/#!forum/ebean
|
||||
|
||||
# Documentation
|
||||
Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
|
||||
Goto [https://ebean.io/docs/](https://ebean.io/docs/)
|
||||
|
||||
|
||||
## Maven cental links:
|
||||
@@ -10,8 +41,7 @@ Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Web
|
||||
|
||||
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
|
||||
|
||||
## Current versions
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean) - ebean
|
||||
## Other versions
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent) - ebean-agent
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin) - ebean-maven-plugin
|
||||
|
||||
|
||||
@@ -151,3 +151,18 @@ In `InsertHandler.getPstmt` the `meta.getIdentityDbColumns()` contains
|
||||
TODO: not yet tested
|
||||
|
||||
|
||||
|
||||
'hana' platform
|
||||
--------------------
|
||||
|
||||
Requires an installed SAP HANA server - e.g. https://store.docker.com/images/sap-hana-express-edition
|
||||
|
||||
- Create a user `EBEAN_TEST` with password `Eb3an_test` in the tenant database `HXE`
|
||||
- Adjust the connection string and/or username in `ebean.properties`
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=hana`
|
||||
|
||||
Current status: PASS
|
||||
Tests run: 2486, Failures: 0, Errors: 0, Skipped: 84
|
||||
|
||||
|
||||
|
||||
@@ -9,20 +9,21 @@
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>11.22.8</version>
|
||||
<version>11.43.2</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
<url>http://ebean-orm.github.io/</url>
|
||||
|
||||
<properties>
|
||||
<jackson-core.version>2.9.5</jackson-core.version>
|
||||
<jackson-core.version>2.9.9</jackson-core.version>
|
||||
<jackson-databind.version>2.9.9.2</jackson-databind.version>
|
||||
<snakeyaml.version>1.21</snakeyaml.version>
|
||||
</properties>
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-11.22.8</tag>
|
||||
<tag>ebean-11.43.2</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
@@ -111,19 +112,25 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<version>2.2.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>4.2</version>
|
||||
<version>4.12</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-datasource</artifactId>
|
||||
<version>3.2.2</version>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-types</artifactId>
|
||||
<version>1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-datasource</artifactId>
|
||||
<version>4.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -135,13 +142,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>11.9.1</version>
|
||||
<version>11.20.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-runtime</artifactId>
|
||||
<version>4.7.1</version>
|
||||
<version>4.7.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
@@ -155,7 +162,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson-core.version}</version>
|
||||
<version>${jackson-databind.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -188,6 +195,21 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Provided scope to compile with java 11 -->
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
<version>2.4.0-b180830.0438</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
<version>1.3.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Provided scope for Postgres JSON/JSONB support -->
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
@@ -198,17 +220,24 @@
|
||||
|
||||
<!-- Test scope -->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.nuodb.jdbc</groupId>
|
||||
<artifactId>nuodb-jdbc</artifactId>
|
||||
<version>20.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>oracle</groupId>-->
|
||||
<!--<artifactId>oracle-jdbc</artifactId>-->
|
||||
<!--<version>7.0</version>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--<groupId>oracle</groupId>-->
|
||||
<!--<artifactId>oracle-jdbc</artifactId>-->
|
||||
<!--<version>7.0</version>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-docker-run</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<groupId>io.ebean.test</groupId>
|
||||
<artifactId>ebean-test-docker</artifactId>
|
||||
<version>2.10.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -219,26 +248,12 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-agentloader</artifactId>
|
||||
<version>2.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-agent</artifactId>
|
||||
<version>11.11.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Provided scope so that the H2HistoryTrigger can live in Ebean core
|
||||
and not require a separate module for it -->
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.196</version>
|
||||
<version>1.4.197</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -259,15 +274,28 @@
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
<version>6.4.0.jre8</version>
|
||||
<version>7.2.2.jre8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<!-- Do not upgrade to 6.0.6: https://bugs.mysql.com/bug.php?id=82896 -->
|
||||
<version>5.1.43</version>
|
||||
<version>8.0.17</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sap.cloud.db.jdbc</groupId>
|
||||
<artifactId>ngdbc</artifactId>
|
||||
<version>2.3.48</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -302,7 +330,7 @@
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>11.11.1</version>
|
||||
<version>11.43.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
@@ -320,9 +348,10 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<version>2.22.1</version>
|
||||
<configuration>
|
||||
<useSystemClassLoader>false</useSystemClassLoader>
|
||||
<trimStackTrace>false</trimStackTrace>
|
||||
<failIfNoTests>false</failIfNoTests>
|
||||
<includes>
|
||||
<include>**/Test*.java</include>
|
||||
@@ -364,7 +393,7 @@
|
||||
<overview>src/main/java/io/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
<excludePackageNames>io.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
|
||||
<excludePackageNames>io.ebeaninternal.*:io.ebeanservice:io.ebean.common:io.ebean.bean:io.ebean.service:io.ebean.metric:io.ebean.util:io.ebean.config.properties:io.ebean.config.dbplatform</excludePackageNames>
|
||||
<docletArtifact>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>pygments-doclet</artifactId>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@@ -37,4 +39,21 @@ public interface BackgroundExecutor {
|
||||
* </p>
|
||||
*/
|
||||
void executePeriodically(Runnable r, long delay, 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
|
||||
*/
|
||||
ScheduledFuture<?> schedule(Runnable r, 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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ import java.util.Optional;
|
||||
* public class CustomerFinder extends BeanFinder<Long,Customer> {
|
||||
*
|
||||
* @Inject
|
||||
* public CustomerFinder(EbeanServer server) {
|
||||
* super(Customer.class, server);
|
||||
* public CustomerFinder(Database database) {
|
||||
* super(Customer.class, database);
|
||||
* }
|
||||
*
|
||||
* // ... add customer specific finders
|
||||
@@ -29,25 +29,25 @@ import java.util.Optional;
|
||||
*/
|
||||
public abstract class BeanFinder<I,T> {
|
||||
|
||||
protected final EbeanServer server;
|
||||
protected final Database server;
|
||||
|
||||
protected final Class<T> type;
|
||||
|
||||
/**
|
||||
* Create with the given bean type and EbeanServer instance.
|
||||
* Create with the given bean type and Database instance.
|
||||
*
|
||||
* @param type The bean type
|
||||
* @param server The EbeanServer instance typically created via Spring factory or equivalent.
|
||||
* @param server The Database instance typically created via Spring factory or equivalent.
|
||||
*/
|
||||
protected BeanFinder(Class<T> type, EbeanServer server) {
|
||||
protected BeanFinder(Class<T> type, Database server) {
|
||||
this.type = type;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the EbeanServer to use.
|
||||
* Return the Database to use.
|
||||
*/
|
||||
public EbeanServer db() {
|
||||
public Database db() {
|
||||
return server;
|
||||
}
|
||||
|
||||
@@ -66,21 +66,20 @@ public abstract class BeanFinder<I,T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return typically a different EbeanServer to the default.
|
||||
* Return typically a different Database to the default.
|
||||
* <p>
|
||||
* This is equivalent to {@link Ebean#getServer(String)}
|
||||
* This is equivalent to {@link DB#byName(String)}
|
||||
*
|
||||
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is
|
||||
* returned.
|
||||
* @param server The name of the Database. If this is null then the default Database is returned.
|
||||
*/
|
||||
public EbeanServer db(String server) {
|
||||
return Ebean.getServer(server);
|
||||
public Database db(String server) {
|
||||
return DB.byName(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an entity reference for this ID.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
|
||||
* Equivalent to {@link Database#getReference(Class, Object)}
|
||||
*/
|
||||
@Nonnull
|
||||
public T ref(I id) {
|
||||
@@ -89,8 +88,6 @@ public abstract class BeanFinder<I,T> {
|
||||
|
||||
/**
|
||||
* Retrieves an entity by ID.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class, Object)}
|
||||
*/
|
||||
@Nullable
|
||||
public T findById(I id) {
|
||||
@@ -107,8 +104,6 @@ public abstract class BeanFinder<I,T> {
|
||||
|
||||
/**
|
||||
* Delete a bean by Id.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#delete(Class, Object)}
|
||||
*/
|
||||
public void deleteById(I id) {
|
||||
db().delete(type, id);
|
||||
@@ -138,7 +133,7 @@ public abstract class BeanFinder<I,T> {
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#update(Class)}
|
||||
* Equivalent to {@link Database#update(Class)}
|
||||
*/
|
||||
protected UpdateQuery<T> updateQuery() {
|
||||
return db().update(type);
|
||||
@@ -147,7 +142,7 @@ public abstract class BeanFinder<I,T> {
|
||||
/**
|
||||
* Creates a query.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class)}
|
||||
* Equivalent to {@link Database#find(Class)}
|
||||
*/
|
||||
protected Query<T> query() {
|
||||
return db().find(type);
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.util.Collection;
|
||||
* public class CustomerRepository extends BeanRepository<Long,Customer> {
|
||||
*
|
||||
* @Inject
|
||||
* public CustomerRepository(EbeanServer server) {
|
||||
* public CustomerRepository(Database server) {
|
||||
* super(Customer.class, server);
|
||||
* }
|
||||
*
|
||||
@@ -34,23 +34,23 @@ import java.util.Collection;
|
||||
public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
|
||||
/**
|
||||
* Create with the given bean type and EbeanServer instance.
|
||||
* Create with the given bean type and Database instance.
|
||||
* <p>
|
||||
* Typically users would extend BeanRepository rather than BeanFinder.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Inject
|
||||
* public CustomerRepository(EbeanServer server) {
|
||||
* public CustomerRepository(Database server) {
|
||||
* super(Customer.class, server);
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param type The bean type
|
||||
* @param server The EbeanServer instance typically created via Spring factory or equivalent
|
||||
* @param server The Database instance typically created via Spring factory or equivalent
|
||||
*/
|
||||
protected BeanRepository(Class<T> type, EbeanServer server) {
|
||||
protected BeanRepository(Class<T> type, Database server) {
|
||||
super(type, server);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see EbeanServer#markAsDirty(Object)
|
||||
* @see Database#markAsDirty(Object)
|
||||
*/
|
||||
public void markAsDirty(T bean) {
|
||||
db().markAsDirty(bean);
|
||||
@@ -111,7 +111,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
|
||||
* insert or an update based on that.
|
||||
*
|
||||
* @see EbeanServer#save(Object)
|
||||
* @see Database#save(Object)
|
||||
*/
|
||||
public void save(T bean) {
|
||||
db().save(bean);
|
||||
@@ -127,7 +127,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
/**
|
||||
* Update this entity.
|
||||
*
|
||||
* @see EbeanServer#update(Object)
|
||||
* @see Database#update(Object)
|
||||
*/
|
||||
public void update(T bean) {
|
||||
db().update(bean);
|
||||
@@ -136,7 +136,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
/**
|
||||
* Insert this entity.
|
||||
*
|
||||
* @see EbeanServer#insert(Object)
|
||||
* @see Database#insert(Object)
|
||||
*/
|
||||
public void insert(T bean) {
|
||||
db().insert(bean);
|
||||
@@ -157,7 +157,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
* deleted. Note that, if JDBC batch mode is used then this always returns true.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#delete(Object)
|
||||
* @see Database#delete(Object)
|
||||
*/
|
||||
public boolean delete(T bean) {
|
||||
return db().delete(bean);
|
||||
@@ -177,7 +177,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
* want to perform a hard/permanent delete.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#deletePermanent(Object)
|
||||
* @see Database#deletePermanent(Object)
|
||||
*/
|
||||
public boolean deletePermanent(T bean) {
|
||||
return db().deletePermanent(bean);
|
||||
@@ -189,7 +189,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
|
||||
* insert or an update based on that.
|
||||
*
|
||||
* @see EbeanServer#merge(Object)
|
||||
* @see Database#merge(Object)
|
||||
*/
|
||||
public void merge(T bean) {
|
||||
db().merge(bean);
|
||||
@@ -201,7 +201,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
|
||||
* insert or an update based on that.
|
||||
*
|
||||
* @see EbeanServer#merge(Object, MergeOptions)
|
||||
* @see Database#merge(Object, MergeOptions)
|
||||
*/
|
||||
public void merge(T bean, MergeOptions options) {
|
||||
db().merge(bean, options);
|
||||
@@ -210,7 +210,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
/**
|
||||
* Refreshes this entity from the database.
|
||||
*
|
||||
* @see EbeanServer#refresh(Object)
|
||||
* @see Database#refresh(Object)
|
||||
*/
|
||||
public void refresh(T bean) {
|
||||
db().refresh(bean);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -56,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
|
||||
* Ebean.getBeanState(user).setPropertyLoaded("email", false);
|
||||
* DB.getBeanState(user).setPropertyLoaded("email", false);
|
||||
*
|
||||
* user.update();
|
||||
*
|
||||
@@ -101,7 +102,7 @@ public interface BeanState {
|
||||
/**
|
||||
* Advanced - Used to programmatically build a partially or fully loaded
|
||||
* entity bean. First create an entity bean via
|
||||
* {@link EbeanServer#createEntityBean(Class)}, then populate its properties
|
||||
* {@link Database#createEntityBean(Class)}, then populate its properties
|
||||
* and then call this method specifying which properties where loaded or null
|
||||
* for a fully loaded entity bean.
|
||||
*/
|
||||
@@ -111,4 +112,10 @@ public interface BeanState {
|
||||
* Reset the bean putting it into NEW state such that a save() results in an insert.
|
||||
*/
|
||||
void resetForInsert();
|
||||
|
||||
/**
|
||||
* Returns a map with load erros.
|
||||
*/
|
||||
@Nullable
|
||||
Map<String, Exception> getLoadErrors();
|
||||
}
|
||||
|
||||
@@ -69,8 +69,8 @@ public enum CacheMode {
|
||||
*/
|
||||
GET(true, false);
|
||||
|
||||
private boolean get;
|
||||
private boolean put;
|
||||
private final boolean get;
|
||||
private final boolean put;
|
||||
|
||||
CacheMode(boolean get, boolean put) {
|
||||
this.get = get;
|
||||
|
||||
@@ -17,11 +17,11 @@ import java.sql.SQLException;
|
||||
*
|
||||
* String sql = "{call sp_order_mod(?,?)}";
|
||||
*
|
||||
* CallableSql cs = Ebean.createCallableSql(sql);
|
||||
* CallableSql cs = DB.createCallableSql(sql);
|
||||
* cs.setParameter(1, "turbo");
|
||||
* cs.registerOut(2, Types.INTEGER);
|
||||
*
|
||||
* Ebean.execute(cs);
|
||||
* DB.execute(cs);
|
||||
*
|
||||
* // read the out parameter
|
||||
* Integer returnValue = (Integer) cs.getObject(2);
|
||||
@@ -38,7 +38,7 @@ import java.sql.SQLException;
|
||||
*
|
||||
* String sql = "{call sp_insert_order(?,?)}";
|
||||
*
|
||||
* CallableSql cs = Ebean.createCallableSql(sql);
|
||||
* CallableSql cs = DB.createCallableSql(sql);
|
||||
*
|
||||
* // Inform Ebean this stored procedure inserts into the
|
||||
* // oe_order table and inserts + updates the oe_order_detail table.
|
||||
@@ -46,35 +46,33 @@ import java.sql.SQLException;
|
||||
* cs.addModification("oe_order", true, false, false);
|
||||
* cs.addModification("oe_order_detail", true, true, false);
|
||||
*
|
||||
* Transaction t = Ebean.startTransaction();
|
||||
*
|
||||
* // execute using JDBC batching 10 statements at a time
|
||||
* t.setBatchMode(true);
|
||||
* t.setBatchSize(10);
|
||||
* try {
|
||||
* try (Transaction t = DB.beginTransaction()) {
|
||||
*
|
||||
* // execute using JDBC batching 10 statements at a time
|
||||
* t.setBatchMode(true);
|
||||
* t.setBatchSize(10);
|
||||
*
|
||||
* cs.setParameter(1, "Was");
|
||||
* cs.setParameter(2, "Banana");
|
||||
* Ebean.execute(cs);
|
||||
* DB.execute(cs);
|
||||
*
|
||||
* cs.setParameter(1, "Here");
|
||||
* cs.setParameter(2, "Kumera");
|
||||
* Ebean.execute(cs);
|
||||
* DB.execute(cs);
|
||||
*
|
||||
* cs.setParameter(1, "More");
|
||||
* cs.setParameter(2, "Apple");
|
||||
* Ebean.execute(cs);
|
||||
* DB.execute(cs);
|
||||
*
|
||||
* // Ebean.externalModification("oe_order",true,false,false);
|
||||
* // Ebean.externalModification("oe_order_detail",true,true,false);
|
||||
* Ebean.commitTransaction();
|
||||
* // DB.externalModification("oe_order",true,false,false);
|
||||
* // DB.externalModification("oe_order_detail",true,true,false);
|
||||
* t.commit();
|
||||
*
|
||||
* } finally {
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @see SqlUpdate
|
||||
* @see Ebean#execute(CallableSql)
|
||||
*/
|
||||
public interface CallableSql {
|
||||
|
||||
@@ -173,7 +171,7 @@ public interface CallableSql {
|
||||
* Add table modification information to the TransactionEvent.
|
||||
* <p>
|
||||
* This would be similar to using the
|
||||
* <code>Ebean.externalModification()</code> method. It may be easier and make
|
||||
* <code>DB.externalModification()</code> method. It may be easier and make
|
||||
* more sense to set it here with the CallableSql.
|
||||
* </p>
|
||||
* <p>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,67 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.config.ContainerConfig;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
|
||||
/**
|
||||
* Creates Database instances.
|
||||
* <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 {
|
||||
|
||||
/**
|
||||
* Initialise the container with clustering configuration.
|
||||
* <p>
|
||||
* Call this prior to creating any Database instances or alternatively set the
|
||||
* ContainerConfig on the ServerConfig when creating the first Database instance.
|
||||
*/
|
||||
public static synchronized void initialiseContainer(ContainerConfig containerConfig) {
|
||||
EbeanServerFactory.initialiseContainer(containerConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using ebean.properties to configure the server.
|
||||
*/
|
||||
public static synchronized Database create(String name) {
|
||||
return EbeanServerFactory.create(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using the ServerConfig object to configure the server.
|
||||
*/
|
||||
public static synchronized Database create(DatabaseConfig config) {
|
||||
return EbeanServerFactory.create(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using the ServerConfig additionally specifying a classLoader to use as the context class loader.
|
||||
*/
|
||||
public static synchronized Database createWithContextClassLoader(DatabaseConfig config, ClassLoader classLoader) {
|
||||
return EbeanServerFactory.createWithContextClassLoader(config, classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 synchronized void shutdown() {
|
||||
EbeanServerFactory.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,7 +30,7 @@ import java.util.function.Predicate;
|
||||
* String sql = "select id, name from customer where name like :name and status_code = :status";
|
||||
*
|
||||
* List<CustomerDto> beans =
|
||||
* Ebean.findDto(CustomrDto.class, sql)
|
||||
* DB.findDto(CustomerDto.class, sql)
|
||||
* .setParameter("name", "Acme%")
|
||||
* .setParameter("status", "ACTIVE")
|
||||
* .findList();
|
||||
@@ -109,6 +109,12 @@ public interface DtoQuery<T> {
|
||||
*/
|
||||
DtoQuery<T> setLabel(String label);
|
||||
|
||||
/**
|
||||
* Set the profile location of this query. This is used to relate query execution metrics
|
||||
* back to a location like a specific line of code.
|
||||
*/
|
||||
DtoQuery<T> setProfileLocation(ProfileLocation profileLocation);
|
||||
|
||||
/**
|
||||
* Set a timeout on this query.
|
||||
* <p>
|
||||
|
||||
@@ -2,7 +2,9 @@ package io.ebean;
|
||||
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
import io.ebean.config.BeanNotEnhancedException;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.datasource.DataSourceConfigurationException;
|
||||
import io.ebean.plugin.Property;
|
||||
import io.ebean.text.csv.CsvReader;
|
||||
import io.ebean.text.json.JsonContext;
|
||||
@@ -22,113 +24,26 @@ import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* This Ebean object is effectively a singleton that holds a map of registered
|
||||
* {@link EbeanServer}s. It additionally provides a convenient way to use the
|
||||
* 'default' EbeanServer.
|
||||
* Ebean is a registry of {@link Database} by name. Ebean has now been renamed to {@link DB}.
|
||||
* <p>
|
||||
* If you are using a Dependency Injection framework such as
|
||||
* <strong>Spring</strong> or <strong>Guice</strong> you will probably
|
||||
* <strong>NOT</strong> use this Ebean singleton object. Instead you will
|
||||
* configure and construct EbeanServer instances using {@link ServerConfig} and
|
||||
* {@link EbeanServerFactory} and inject those EbeanServer instances into your
|
||||
* data access objects.
|
||||
* </p>
|
||||
* Ebean is effectively this is an alias for {@link DB} which is the new and improved name for Ebean.
|
||||
* <p>
|
||||
* In documentation "Ebean singleton" refers to this object.
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>There is one EbeanServer per Database (javax.sql.DataSource).</li>
|
||||
* <li>EbeanServers can be 'registered' with the Ebean singleton (put into its
|
||||
* map). Registered EbeanServer's can later be retrieved via
|
||||
* {@link #getServer(String)}.</li>
|
||||
* <li>One EbeanServer can be referred to as the 'default' EbeanServer. For
|
||||
* convenience, the Ebean singleton (this object) provides methods such as
|
||||
* {@link #find(Class)} that proxy through to the 'default' EbeanServer. This
|
||||
* can be useful for applications that use a single database.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For developer convenience Ebean has static methods that proxy through to the
|
||||
* methods on the <em>'default'</em> EbeanServer. These methods are provided for
|
||||
* developers who are mostly using a single database. Many developers will be
|
||||
* able to use the methods on Ebean rather than get a EbeanServer.
|
||||
* </p>
|
||||
* <p>
|
||||
* EbeanServers can be created and used without ever needing or using the Ebean
|
||||
* singleton. Refer to {@link ServerConfig#setRegister(boolean)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can either programmatically create/register EbeanServers via
|
||||
* {@link EbeanServerFactory} or they can automatically be created and
|
||||
* registered when you first use the Ebean singleton. When EbeanServers are
|
||||
* created automatically they are configured using information in the
|
||||
* ebean.properties file.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch shipped orders (and also their customer)
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .where()
|
||||
* .eq("status.code", Order.Status.SHIPPED)
|
||||
* .findList();
|
||||
*
|
||||
* // read/use the order list ...
|
||||
* for (Order order : list) {
|
||||
* Customer customer = order.getCustomer();
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch order 10, modify and save
|
||||
* Order order = Ebean.find(Order.class, 10);
|
||||
*
|
||||
* OrderStatus shipped = Ebean.getReference(OrderStatus.class,"SHIPPED");
|
||||
* order.setStatus(shipped);
|
||||
* order.setShippedDate(shippedDate);
|
||||
* ...
|
||||
*
|
||||
* // implicitly creates a transaction and commits
|
||||
* Ebean.save(order);
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* When you have multiple databases and need access to a specific one the
|
||||
* {@link #getServer(String)} method provides access to the EbeanServer for that
|
||||
* specific database.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Get access to the Human Resources EbeanServer/Database
|
||||
* EbeanServer hrDb = Ebean.getServer("hr");
|
||||
*
|
||||
* // fetch contact 3 from the HR database
|
||||
* Contact contact = hrDb.find(Contact.class, 3);
|
||||
*
|
||||
* contact.setName("I'm going to change");
|
||||
* ...
|
||||
*
|
||||
* // save the contact back to the HR database
|
||||
* hrDb.save(contact);
|
||||
*
|
||||
* }</pre>
|
||||
* The preference is to use DB and Database rather than Ebean and EbeanServer.
|
||||
*/
|
||||
public final class Ebean {
|
||||
private static final Logger logger = LoggerFactory.getLogger(Ebean.class);
|
||||
|
||||
static {
|
||||
EbeanVersion.getVersion(); // initalizes the version class and logs the version.
|
||||
EbeanVersion.getVersion(); // initialises the version class and logs the version.
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages creation and cache of EbeanServers.
|
||||
* Manages creation and cache of Databases.
|
||||
*/
|
||||
private static final Ebean.ServerManager serverMgr = new Ebean.ServerManager();
|
||||
|
||||
/**
|
||||
* Helper class for managing fast and safe access and creation of
|
||||
* EbeanServers.
|
||||
* Helper class for managing fast and safe access and creation of Databases.
|
||||
*/
|
||||
private static final class ServerManager {
|
||||
|
||||
@@ -145,7 +60,7 @@ public final class Ebean {
|
||||
private final Object monitor = new Object();
|
||||
|
||||
/**
|
||||
* The 'default' EbeanServer.
|
||||
* The 'default' Database.
|
||||
*/
|
||||
private EbeanServer defaultServer;
|
||||
|
||||
@@ -160,15 +75,24 @@ public final class Ebean {
|
||||
defaultServer = getWithCreate(defaultName.trim());
|
||||
}
|
||||
}
|
||||
} catch (BeanNotEnhancedException e) {
|
||||
throw e;
|
||||
|
||||
} catch (DataSourceConfigurationException e) {
|
||||
String msg = "Configuration error creating DataSource for the default Database." +
|
||||
" This typically means a missing application-test.yaml or missing ebean-test-config dependency." +
|
||||
" See https://ebean.io/docs/trouble-shooting#datasource";
|
||||
throw new DataSourceConfigurationException(msg, e);
|
||||
|
||||
} catch (Throwable e) {
|
||||
logger.error("Error trying to create the default EbeanServer", e);
|
||||
logger.error("Error trying to create the default Database", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private EbeanServer getDefaultServer() {
|
||||
if (defaultServer == null) {
|
||||
String msg = "The default EbeanServer has not been defined?";
|
||||
String msg = "The default Database has not been defined?";
|
||||
msg += " This is normally set via the ebean.datasource.default property.";
|
||||
msg += " Otherwise it should be registered programmatically via registerServer()";
|
||||
throw new PersistenceException(msg);
|
||||
@@ -190,7 +114,7 @@ public final class Ebean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronized read, create and put of EbeanServers.
|
||||
* Synchronized read, create and put of Databases.
|
||||
*/
|
||||
private EbeanServer getWithCreate(String name) {
|
||||
|
||||
@@ -229,7 +153,7 @@ public final class Ebean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the EbeanServer for a given DataSource. If name is null this will
|
||||
* Get the Database for a given DataSource. If name is null this will
|
||||
* return the 'default' EbeanServer.
|
||||
* <p>
|
||||
* This is provided to access EbeanServer for databases other than the
|
||||
@@ -620,7 +544,8 @@ public final class Ebean {
|
||||
* Customer customer = new Customer();
|
||||
* customer.setId(7);
|
||||
* customer.setName("ModifiedNameNoOCC");
|
||||
* ebeanServer.update(customer);
|
||||
*
|
||||
* DB.update(customer);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
@@ -1120,10 +1045,9 @@ public final class Ebean {
|
||||
*
|
||||
* String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
|
||||
*
|
||||
* Query<Customer> query = ebeanServer.findNative(Customer.class, sql);
|
||||
* query.setParameter(1, "Rob%");
|
||||
*
|
||||
* List<Customer> customers = query.findList();
|
||||
* List<Customer> customers = DB.findNative(Customer.class, sql)
|
||||
* .setParameter(1, "Rob%")
|
||||
* .findList()
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,8 +22,8 @@ package io.ebean;
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
* List<Customer> list =
|
||||
* Ebean.find(Customer.class)
|
||||
* List<Customer> list =
|
||||
* DB.find(Customer.class)
|
||||
* .where()
|
||||
* // pass the bean into the where() clause
|
||||
* .exampleLike(example)
|
||||
@@ -46,7 +46,7 @@ package io.ebean;
|
||||
* .includeZeros();
|
||||
*
|
||||
* List<Customer> list =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .where()
|
||||
* .add(qbe)
|
||||
* .findList();
|
||||
|
||||
@@ -13,27 +13,15 @@ import java.util.Map;
|
||||
* {@link Query#where()}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This provides a convenient way to create expressions for the 'Default'
|
||||
* server. It is actually a short cut for using the ExpressionFactory of the
|
||||
* 'default' EbeanServer.
|
||||
* This provides a convenient way to create expressions for the default
|
||||
* database.
|
||||
* <p>
|
||||
* See also {@link Ebean#getExpressionFactory()}
|
||||
* See also {@link DB#getExpressionFactory()}
|
||||
* </p>
|
||||
* <p>
|
||||
* Creates standard common expressions for using in a Query Where or Having
|
||||
* clause.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Example: Using an Expr.or() method
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.where(
|
||||
* Expr.or(Expr.eq("status", Order.NEW),
|
||||
* Expr.gt("orderDate", lastWeek));
|
||||
*
|
||||
* List<Order> list = query.findList();
|
||||
* ...
|
||||
* }</pre>
|
||||
*
|
||||
* @see Query#where()
|
||||
*/
|
||||
@@ -64,11 +52,20 @@ public class Expr {
|
||||
return Ebean.getExpressionFactory().ieq(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* In Range - property >= value1 and property < value2.
|
||||
* <p>
|
||||
* Unlike Between inRange is "half open" and usually more useful for use with dates or timestamps.
|
||||
* </p>
|
||||
*/
|
||||
public static Expression inRange(String propertyName, Object value1, Object value2) {
|
||||
return Ebean.getExpressionFactory().inRange(propertyName, value1, value2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
public static Expression between(String propertyName, Object value1, Object value2) {
|
||||
|
||||
return Ebean.getExpressionFactory().between(propertyName, value1, value2);
|
||||
}
|
||||
|
||||
@@ -76,7 +73,6 @@ public class Expr {
|
||||
* Between - value between two given properties.
|
||||
*/
|
||||
public static Expression between(String lowProperty, String highProperty, Object value) {
|
||||
|
||||
return Ebean.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
|
||||
}
|
||||
|
||||
@@ -242,6 +238,43 @@ public class Expr {
|
||||
return Ebean.getExpressionFactory().in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* In where null or empty values means that no predicate is added to the query.
|
||||
* <p>
|
||||
* That is, only add the IN predicate if the values are not null or empty.
|
||||
* <p>
|
||||
* Without this we typically need to code an <code>if</code> block to only add
|
||||
* the IN predicate if the collection is not empty like:
|
||||
* </p>
|
||||
*
|
||||
* <h3>Without inOrEmpty()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where() // add some predicates
|
||||
* .eq("status", Status.NEW);
|
||||
*
|
||||
* if (ids != null && !ids.isEmpty()) {
|
||||
* query.where().in("customer.id", ids);
|
||||
* }
|
||||
*
|
||||
* query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Using inOrEmpty()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where()
|
||||
* .eq("status", Status.NEW)
|
||||
* .inOrEmpty("customer.id", ids)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static Expression inOrEmpty(String propertyName, Collection<?> values) {
|
||||
return Ebean.getExpressionFactory().inOrEmpty(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Id Equal to - ID property is equal to the value.
|
||||
*/
|
||||
|
||||
@@ -30,9 +30,9 @@ import java.util.Map;
|
||||
* Expr.or(Expr.eq("status", Order.Status.NEW),
|
||||
* Expr.gt("orderDate", lastWeek));
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.where().add(newOrLastWeek);
|
||||
* List<Order> list = query.findList();
|
||||
* List<Order> list = DB.find(Order.class)
|
||||
* .where().add(newOrLastWeek)
|
||||
* .findList();
|
||||
* ...
|
||||
* }</pre>
|
||||
*
|
||||
@@ -122,6 +122,11 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression eq(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Equal To or Null - property equal to the given value or null.
|
||||
*/
|
||||
Expression eqOrNull(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Not Equal To - property not equal to the given value.
|
||||
*/
|
||||
@@ -133,11 +138,49 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression ieq(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case Insensitive Not Equal To - property not equal to the given value (typically
|
||||
* using a lower() function to make it case insensitive).
|
||||
*/
|
||||
Expression ine(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case Insensitive Equal To that allows for named parameter use.
|
||||
*/
|
||||
Expression ieqObject(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Case Insensitive Not Equal To that allows for named parameter use.
|
||||
*/
|
||||
Expression ineObject(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* In Range - property >= value1 and property < value2.
|
||||
* <p>
|
||||
* Unlike Between inRange is "half open" and usually more useful for use with dates or timestamps.
|
||||
* </p>
|
||||
*/
|
||||
Expression inRange(String propertyName, Object value1, Object value2);
|
||||
|
||||
/**
|
||||
* Value in Range between 2 properties.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* .startDate.inRangeWith(endDate, now)
|
||||
*
|
||||
* // which equates to
|
||||
* startDate <= now and (endDate > now or endDate is null)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* This is a convenience expression combining a number of simple expressions.
|
||||
* The most common use of this could be called "effective dating" where 2 date or
|
||||
* timestamp columns represent the date range in which
|
||||
*/
|
||||
Expression inRangeWith(String lowProperty, String highProperty, Object value);
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
@@ -148,6 +191,14 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression betweenProperties(String lowProperty, String highProperty, Object value);
|
||||
|
||||
/**
|
||||
* Greater Than Or Null - property greater than the given value or null.
|
||||
* <p>
|
||||
* A convenient expression combining GT and Is Null. Most often useful for range
|
||||
* expressions where the top range value is nullable.
|
||||
*/
|
||||
Expression gtOrNull(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Greater Than - property greater than the given value.
|
||||
*/
|
||||
@@ -159,6 +210,14 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression ge(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than or Null - property less than the given value or null.
|
||||
* <p>
|
||||
* A convenient expression combining LT and Is Null. Most often useful for range
|
||||
* expressions where the bottom range value is nullable.
|
||||
*/
|
||||
Expression ltOrNull(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than - property less than the given value.
|
||||
*/
|
||||
@@ -266,6 +325,41 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression in(String propertyName, Collection<?> values);
|
||||
|
||||
/**
|
||||
* In where null or empty values means that no predicate is added to the query.
|
||||
* <p>
|
||||
* That is, only add the IN predicate if the values are not null or empty.
|
||||
* <p>
|
||||
* Without this we typically need to code an <code>if</code> block to only add
|
||||
* the IN predicate if the collection is not empty like:
|
||||
* </p>
|
||||
*
|
||||
* <h3>Without inOrEmpty()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where() // add some predicates
|
||||
* .eq("status", Status.NEW);
|
||||
*
|
||||
* if (ids != null && !ids.isEmpty()) {
|
||||
* query.where().in("customer.id", ids);
|
||||
* }
|
||||
*
|
||||
* query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Using inOrEmpty()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where()
|
||||
* .eq("status", Status.NEW)
|
||||
* .inOrEmpty("customer.id", ids)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Expression inOrEmpty(String propertyName, Collection<?> values);
|
||||
|
||||
/**
|
||||
* Not In - property has a value in the array of values.
|
||||
*/
|
||||
@@ -442,4 +536,12 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
<T> Junction<T> junction(Junction.Type type, Query<T> query, ExpressionList<T> parent);
|
||||
|
||||
/**
|
||||
* Add the expressions to the given expression list.
|
||||
*
|
||||
* @param where The expression list to add the expressions to
|
||||
* @param expressions The expressions that are parsed
|
||||
* @param params Bind parameters to match ? or ?1 bind positions.
|
||||
*/
|
||||
<T> void where(ExpressionList<T> where, String expressions, Object[] params);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import io.ebean.search.TextSimple;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -128,6 +129,38 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
<D> DtoQuery<D> asDto(Class<D> dtoClass);
|
||||
|
||||
/**
|
||||
* Return the underlying query as an UpdateQuery.
|
||||
* <p>
|
||||
* Typically this is used with query beans to covert a query bean
|
||||
* query into an UpdateQuery like the examples below.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rowsUpdated = new QCustomer()
|
||||
* .name.startsWith("Rob")
|
||||
* .asUpdate()
|
||||
* .set("active", false)
|
||||
* .update();;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rowsUpdated = new QContact()
|
||||
* .notes.note.startsWith("Make Inactive")
|
||||
* .email.endsWith("@foo.com")
|
||||
* .customer.id.equalTo(42)
|
||||
* .asUpdate()
|
||||
* .set("inactive", true)
|
||||
* .setRaw("email = lower(email)")
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
UpdateQuery<T> asUpdate();
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause which results in the DB locking the record.
|
||||
*/
|
||||
@@ -154,6 +187,16 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Query<T> setIncludeSoftDeletes();
|
||||
|
||||
/**
|
||||
* Execute the query using the given transaction.
|
||||
*/
|
||||
Query<T> usingTransaction(Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query using the given connection.
|
||||
*/
|
||||
Query<T> usingConnection(Connection connection);
|
||||
|
||||
/**
|
||||
* Execute as a delete query deleting the 'root level' beans that match the predicates
|
||||
* in the query.
|
||||
@@ -166,6 +209,18 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
int delete();
|
||||
|
||||
/**
|
||||
* Execute as a delete query deleting the 'root level' beans that match the predicates
|
||||
* in the query.
|
||||
* <p>
|
||||
* Note that if the query includes joins then the generated delete statement may not be
|
||||
* optimal depending on the database platform.
|
||||
* </p>
|
||||
*
|
||||
* @return the number of rows that were deleted.
|
||||
*/
|
||||
int delete(Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute as a update query.
|
||||
*
|
||||
@@ -174,6 +229,40 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
int update();
|
||||
|
||||
/**
|
||||
* Execute as a update query with the given transaction.
|
||||
*
|
||||
* @return the number of rows that were updated.
|
||||
* @see UpdateQuery
|
||||
*/
|
||||
int update(Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query returning true if a row is found.
|
||||
* <p>
|
||||
* The query is executed using max rows of 1 and will only select the id property.
|
||||
* This method is really just a convenient way to optimise a query to perform a
|
||||
* 'does a row exist in the db' check.
|
||||
* </p>
|
||||
*
|
||||
* <h2>Example:</h2>
|
||||
* <pre>{@code
|
||||
*
|
||||
* boolean userExists = query().where().eq("email", "rob@foo.com").exists();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h2>Example using a query bean:</h2>
|
||||
* <pre>{@code
|
||||
*
|
||||
* boolean userExists = new QContact().email.equalTo("rob@foo.com").exists();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @return True if the query finds a matching row in the database
|
||||
*/
|
||||
boolean exists();
|
||||
|
||||
/**
|
||||
* Execute the query iterating over the results.
|
||||
*
|
||||
@@ -238,23 +327,23 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Execute the query returning a list of values for a single property.
|
||||
* <p>
|
||||
*
|
||||
* <h3>Example 1:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .select("name")
|
||||
* .orderBy().asc("name")
|
||||
* .findSingleAttributeList();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
*
|
||||
* <h3>Example 2:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .where().eq("status", Customer.Status.NEW)
|
||||
@@ -271,11 +360,10 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Execute a query returning a single value of a single property/column.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* String name =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .select("name")
|
||||
* .where().eq("id", 42)
|
||||
* .findSingleAttribute();
|
||||
@@ -356,10 +444,9 @@ public interface ExpressionList<T> {
|
||||
* If maxRows is not set on the query prior to calling findPagedList() then a
|
||||
* PersistenceException is thrown.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Order> pagedList = Ebean.find(Order.class)
|
||||
* PagedList<Order> pagedList = DB.find(Order.class)
|
||||
* .setFirstRow(50)
|
||||
* .setMaxRows(20)
|
||||
* .findPagedList();
|
||||
@@ -402,7 +489,26 @@ public interface ExpressionList<T> {
|
||||
* Add some filter predicate expressions to the many property.
|
||||
*/
|
||||
@Nonnull
|
||||
ExpressionList<T> filterMany(String prop);
|
||||
ExpressionList<T> filterMany(String manyProperty);
|
||||
|
||||
/**
|
||||
* Add filter expressions to the many property.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* DB.find(Customer.class)
|
||||
* .where()
|
||||
* .eq("name", "Rob")
|
||||
* .filterMany("orders", "status = ?", Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param manyProperty The many property
|
||||
* @param expressions Filter expressions with and, or and ? or ?1 type bind parameters
|
||||
* @param params Bind parameters used in the expressions
|
||||
*/
|
||||
Query<T> filterMany(String manyProperty, String expressions, Object... params);
|
||||
|
||||
/**
|
||||
* Specify specific properties to fetch on the main/root bean (aka partial
|
||||
@@ -426,7 +532,7 @@ public interface ExpressionList<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name") // only select the customer name
|
||||
* .findList();
|
||||
@@ -495,12 +601,11 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Extended version for setDistinct in conjunction with "findSingleAttributeList";
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<CountedValue<Order.Status>> orderStatusCount =
|
||||
*
|
||||
* Ebean.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .select("status")
|
||||
* .where()
|
||||
* .gt("orderDate", LocalDate.now().minusMonths(3))
|
||||
@@ -577,6 +682,14 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> where();
|
||||
|
||||
/**
|
||||
* Add the expressions to this expression list.
|
||||
*
|
||||
* @param expressions The expressions that are parsed and added to this expression list
|
||||
* @param params Bind parameters to match ? or ?1 bind positions.
|
||||
*/
|
||||
ExpressionList<T> where(String expressions, Object... params);
|
||||
|
||||
/**
|
||||
* Path exists - for the given path in a JSON document.
|
||||
* <pre>{@code
|
||||
@@ -605,7 +718,6 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Equal to expression for the value at the given path in the JSON document.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonEqualTo("content", "path.other", 34)
|
||||
@@ -620,7 +732,6 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Not Equal to - for the given path in a JSON document.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonNotEqualTo("content", "path.other", 34)
|
||||
@@ -635,7 +746,6 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Greater than - for the given path in a JSON document.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonGreaterThan("content", "path.other", 34)
|
||||
@@ -646,7 +756,6 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Greater than or equal to - for the given path in a JSON document.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonGreaterOrEqual("content", "path.other", 34)
|
||||
@@ -657,7 +766,6 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Less than - for the given path in a JSON document.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonLessThan("content", "path.other", 34)
|
||||
@@ -668,7 +776,6 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Less than or equal to - for the given path in a JSON document.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonLessOrEqualTo("content", "path.other", 34)
|
||||
@@ -679,7 +786,6 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Between - for the given path in a JSON document.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonBetween("content", "orderDate", lowerDateTime, upperDateTime)
|
||||
@@ -690,21 +796,6 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Add an Expression to the list.
|
||||
* <p>
|
||||
* This returns the list so that add() can be chained.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Customer> query = Ebean.find(Customer.class);
|
||||
* query.where()
|
||||
* .like("name","Rob%")
|
||||
* .eq("status", Customer.ACTIVE);
|
||||
*
|
||||
* List<Customer> list = query.findList();
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> add(Expression expr);
|
||||
|
||||
@@ -718,6 +809,11 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> eq(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Equal To or Null - property is equal to a given value or null.
|
||||
*/
|
||||
ExpressionList<T> eqOrNull(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Not Equal To - property not equal to the given value.
|
||||
*/
|
||||
@@ -729,6 +825,39 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> ieq(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case Insensitive Not Equal To - property not equal to the given value (typically
|
||||
* using a lower() function to make it case insensitive).
|
||||
*/
|
||||
ExpressionList<T> ine(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Value in Range between 2 properties.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* .startDate.inRangeWith(endDate, now)
|
||||
*
|
||||
* // which equates to
|
||||
* startDate <= now and (endDate > now or endDate is null)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* This is a convenience expression combining a number of simple expressions.
|
||||
* The most common use of this could be called "effective dating" where 2 date or
|
||||
* timestamp columns represent the date range in which
|
||||
*/
|
||||
ExpressionList<T> inRangeWith(String lowProperty, String highProperty, Object value);
|
||||
|
||||
/**
|
||||
* In Range - property >= value1 and property < value2.
|
||||
* <p>
|
||||
* Unlike Between inRange is "half open" and usually more useful for use with dates or timestamps.
|
||||
* </p>
|
||||
*/
|
||||
ExpressionList<T> inRange(String propertyName, Object value1, Object value2);
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
@@ -744,6 +873,11 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> gt(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Greater Than or Null - property greater than the given value or null.
|
||||
*/
|
||||
ExpressionList<T> gtOrNull(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Greater Than or Equal to - property greater than or equal to the given
|
||||
* value.
|
||||
@@ -755,6 +889,11 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> lt(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than or Null - property less than the given value or null.
|
||||
*/
|
||||
ExpressionList<T> ltOrNull(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than or Equal to - property less than or equal to the given value.
|
||||
*/
|
||||
@@ -784,7 +923,6 @@ public interface ExpressionList<T> {
|
||||
* To get control over the options you can create an ExampleExpression and set
|
||||
* those options such as case insensitive etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // create an example bean and set the properties
|
||||
@@ -793,16 +931,15 @@ public interface ExpressionList<T> {
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
* List<Customer> list = Ebean.find(Customer.class).where()
|
||||
* // pass the bean into the where() clause
|
||||
* .exampleLike(example)
|
||||
* // you can add other expressions to the same query
|
||||
* .gt("id", 2).findList();
|
||||
* List<Customer> list =
|
||||
* DB.find(Customer.class)
|
||||
* .where().exampleLike(example)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Similarly you can create an ExampleExpression
|
||||
* <p>
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer example = new Customer();
|
||||
@@ -812,7 +949,7 @@ public interface ExpressionList<T> {
|
||||
* // create a ExampleExpression with more control
|
||||
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO).includeZeros();
|
||||
*
|
||||
* List<Customer> list = Ebean.find(Customer.class).where().add(qbe).findList();
|
||||
* List<Customer> list = DB.find(Customer.class).where().add(qbe).findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@@ -889,6 +1026,41 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> in(String propertyName, Collection<?> values);
|
||||
|
||||
/**
|
||||
* In where null or empty values means that no predicate is added to the query.
|
||||
* <p>
|
||||
* That is, only add the IN predicate if the values are not null or empty.
|
||||
* <p>
|
||||
* Without this we typically need to code an <code>if</code> block to only add
|
||||
* the IN predicate if the collection is not empty like:
|
||||
* </p>
|
||||
*
|
||||
* <h3>Without inOrEmpty()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where() // add some predicates
|
||||
* .eq("status", Status.NEW);
|
||||
*
|
||||
* if (ids != null && !ids.isEmpty()) {
|
||||
* query.where().in("customer.id", ids);
|
||||
* }
|
||||
*
|
||||
* query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Using inOrEmpty()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where()
|
||||
* .eq("status", Status.NEW)
|
||||
* .inOrEmpty("customer.id", ids)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> inOrEmpty(String propertyName, Collection<?> values);
|
||||
|
||||
/**
|
||||
* In - using a subQuery.
|
||||
* <p>
|
||||
@@ -1024,7 +1196,6 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Add expression for ALL of the given bit flags to be set.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().bitwiseAll("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
|
||||
@@ -1038,7 +1209,6 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Add expression for the given bit flags to be NOT set.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().bitwiseNot("flags", BwFlags.HAS_COLOUR)
|
||||
@@ -1089,6 +1259,13 @@ public interface ExpressionList<T> {
|
||||
* raw("add_days(orderDate, 10) < ?", someDate)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h4>Subquery example:</h4>
|
||||
* <pre>{@code
|
||||
*
|
||||
* .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds)
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> raw(String raw, Object value);
|
||||
|
||||
@@ -1113,15 +1290,83 @@ public interface ExpressionList<T> {
|
||||
* then they are not translated. logical property name names (not fully
|
||||
* qualified) will still be translated to their physical name.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* raw("orderQty < shipQty")
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h4>Subquery example:</h4>
|
||||
* <pre>{@code
|
||||
*
|
||||
* .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds)
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> raw(String raw);
|
||||
|
||||
/**
|
||||
* Only add the raw expression if the values is not null or empty.
|
||||
* <p>
|
||||
* This is a pure convenience expression to make it nicer to deal with the pattern where we use
|
||||
* raw() expression with a subquery and only want to add the subquery predicate when the collection
|
||||
* of values is not empty.
|
||||
* </p>
|
||||
* <h3>Without inOrEmpty()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where() // add some predicates
|
||||
* .eq("status", Status.NEW);
|
||||
*
|
||||
* // common pattern - we can use rawOrEmpty() instead
|
||||
* if (orderIds != null && !orderIds.isEmpty()) {
|
||||
* query.where().raw("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds);
|
||||
* }
|
||||
*
|
||||
* query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Using rawOrEmpty()</h3>
|
||||
* Note that in the example below we use the <code>?1</code> bind parameter to get "parameter expansion"
|
||||
* for each element in the collection.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where()
|
||||
* .eq("status", Status.NEW)
|
||||
* // only add the expression if orderIds is not empty
|
||||
* .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds);
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Postgres ANY</h3>
|
||||
* With Postgres we would often use the SQL <code>ANY</code> expression and array parameter binding
|
||||
* rather than <code>IN</code>.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where()
|
||||
* .eq("status", Status.NEW)
|
||||
* .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id = any(?))", orderIds);
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Note that we need to cast the Postgres array for UUID types like:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* " ... = any(?::uuid[])"
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param raw The raw expression that is typically a subquery
|
||||
* @param values The values which is typically a list or set of id values.
|
||||
*/
|
||||
ExpressionList<T> rawOrEmpty(String raw, Collection<?> values);
|
||||
|
||||
/**
|
||||
* Add a match expression.
|
||||
*
|
||||
@@ -1192,12 +1437,10 @@ public interface ExpressionList<T> {
|
||||
* typically you only explicitly need to use the and() junction
|
||||
* when it is nested inside an or() or not() junction.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Example: Nested and()
|
||||
*
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .and() // nested and
|
||||
@@ -1218,16 +1461,27 @@ public interface ExpressionList<T> {
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
* This is exactly the same as disjunction();
|
||||
* <p>
|
||||
* <p>
|
||||
* Use endOr() or endJunction() to end the OR junction.
|
||||
* </p>
|
||||
* <p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Example: (status active OR anniversary is null)
|
||||
*
|
||||
* .where()
|
||||
* .or()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .isNull("anniversary")
|
||||
* .orderBy().asc("name")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Example: Use or() to join
|
||||
* // two nested and() expressions
|
||||
*
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .and()
|
||||
@@ -1251,8 +1505,8 @@ public interface ExpressionList<T> {
|
||||
* Use endNot() or endJunction() to end expressions being added to the
|
||||
* NOT expression list.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>@{code
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* .where()
|
||||
* .not()
|
||||
@@ -1261,12 +1515,11 @@ public interface ExpressionList<T> {
|
||||
* .endNot()
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <pre>@{code
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Example: nested not()
|
||||
*
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .not()
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
@@ -12,7 +15,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* The extended API for EbeanServer.
|
||||
* The extended API for Database.
|
||||
* <p>
|
||||
* This provides the finder methods that take an explicit transaction rather than obtaining
|
||||
* the transaction from the usual mechanism (which is ThreadLocal based).
|
||||
@@ -23,7 +26,7 @@ import java.util.function.Predicate;
|
||||
* the transaction to use.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that in all cases the transaction supplied can be null and in this case the EbeanServer
|
||||
* Note that in all cases the transaction supplied can be null and in this case the Database
|
||||
* will use the normal mechanism to obtain the transaction to use.
|
||||
* </p>
|
||||
*/
|
||||
@@ -42,6 +45,32 @@ public interface ExtendedServer {
|
||||
*/
|
||||
void setClock(Clock clock);
|
||||
|
||||
/**
|
||||
* Execute the query returning true if a row is found.
|
||||
* <p>
|
||||
* The query is executed using max rows of 1 and will only select the id property.
|
||||
* This method is really just a convenient way to optimise a query to perform a
|
||||
* 'does a row exist in the db' check.
|
||||
* </p>
|
||||
*
|
||||
* <h2>Example:</h2>
|
||||
* <pre>{@code
|
||||
*
|
||||
* boolean userExists = query().where().eq("email", "rob@foo.com").exists();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h2>Example using a query bean:</h2>
|
||||
* <pre>{@code
|
||||
*
|
||||
* boolean userExists = new QContact().email.equalTo("rob@foo.com").exists();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @return True if the query finds a matching row in the database
|
||||
*/
|
||||
<T> boolean exists(SpiQuery<?> ormQuery, SpiTransaction transaction);
|
||||
|
||||
/**
|
||||
* Return the number of 'top level' or 'root' entities this query should return.
|
||||
*
|
||||
@@ -92,7 +121,7 @@ public interface ExtendedServer {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* ebeanServer.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .findEach((Order order) -> {
|
||||
@@ -126,7 +155,7 @@ public interface ExtendedServer {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* ebeanServer.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .findEachWhile((Order order) -> {
|
||||
@@ -165,8 +194,7 @@ public interface ExtendedServer {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* .where().ilike("name", "rob%")
|
||||
* .findList();
|
||||
*
|
||||
@@ -243,7 +271,7 @@ public interface ExtendedServer {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Order> pagedList = Ebean.find(Order.class)
|
||||
* PagedList<Order> pagedList = DB.find(Order.class)
|
||||
* .setFirstRow(50)
|
||||
* .setMaxRows(20)
|
||||
* .findPagedList();
|
||||
@@ -272,8 +300,7 @@ public interface ExtendedServer {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Set<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* Set<Customer> customers = DB.find(Customer.class)
|
||||
* .where().ilike("name", "rob%")
|
||||
* .findSet();
|
||||
*
|
||||
@@ -312,7 +339,7 @@ public interface ExtendedServer {
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .select("name")
|
||||
* .orderBy().asc("name")
|
||||
* .findSingleAttributeList();
|
||||
@@ -322,7 +349,7 @@ public interface ExtendedServer {
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .where().eq("status", Customer.Status.NEW)
|
||||
@@ -384,7 +411,7 @@ public interface ExtendedServer {
|
||||
/**
|
||||
* Execute the update query returning the number of rows updated.
|
||||
* <p>
|
||||
* The update query must be created using {@link EbeanServer#update(Class)}.
|
||||
* The update query must be created using {@link Database#update(Class)}.
|
||||
* </p>
|
||||
*
|
||||
* @param query the update query to execute
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.io.Serializable;
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
* // Normal fetch join results in a single SQL query
|
||||
* List<Order> list = Ebean.find(Order.class).fetch("details").findList();
|
||||
* List<Order> list = DB.find(Order.class).fetch("details").findList();
|
||||
*
|
||||
* // Find Orders join details using a single SQL query
|
||||
* }</pre>
|
||||
@@ -36,7 +36,7 @@ import java.io.Serializable;
|
||||
*
|
||||
* // This will use 2 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .findList();
|
||||
*
|
||||
@@ -52,7 +52,7 @@ import java.io.Serializable;
|
||||
*
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("customer", new FetchConfig().queryFirst(5))
|
||||
* .findList();
|
||||
@@ -70,7 +70,7 @@ import java.io.Serializable;
|
||||
* <pre>{@code
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .select("status, shipDate")
|
||||
* .fetch("details", "quantity, price", new FetchConfig().query())
|
||||
* .fetch("details.product", "sku, name")
|
||||
@@ -100,7 +100,7 @@ import java.io.Serializable;
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .fetch("customer", new FetchConfig().query(10).lazy(5))
|
||||
* .findList();
|
||||
*
|
||||
@@ -121,7 +121,7 @@ import java.io.Serializable;
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* List<Order> list = DB.find(Order.class)
|
||||
* .fetch("customer","name", new FetchConfig().lazy(5))
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.shippingAddress")
|
||||
@@ -148,6 +148,8 @@ public class FetchConfig implements Serializable {
|
||||
|
||||
private boolean queryAll;
|
||||
|
||||
private boolean cache;
|
||||
|
||||
/**
|
||||
* Construct the fetch configuration object.
|
||||
*/
|
||||
@@ -188,6 +190,17 @@ public class FetchConfig implements Serializable {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
@@ -247,6 +260,13 @@ public class FetchConfig implements Serializable {
|
||||
return queryAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this uses L2 bean cache.
|
||||
*/
|
||||
public boolean isCache() {
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -255,6 +275,7 @@ public class FetchConfig implements Serializable {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -263,6 +284,7 @@ public class FetchConfig implements Serializable {
|
||||
int result = lazyBatchSize;
|
||||
result = 92821 * result + queryBatchSize;
|
||||
result = 92821 * result + (queryAll ? 1 : 0);
|
||||
result = 92821 * result + (cache ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.service.SpiFetchGroupQuery;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
@@ -10,7 +12,7 @@ import javax.annotation.Nonnull;
|
||||
* that can be defined separately from the query and combined with other FetchGroups.
|
||||
* </p>
|
||||
*
|
||||
* <h3>Select example</h3>*
|
||||
* <h3>Select example</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* FetchGroup<Customer> fetchGroup = FetchGroup.of(Customer.class, "name, status");
|
||||
@@ -111,4 +113,11 @@ public interface FetchGroup<T> {
|
||||
return XServiceProvider.fetchGroupOf(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a query to be used by query beans for constructing FetchGroup.
|
||||
*/
|
||||
static <T> SpiFetchGroupQuery<T> queryFor(Class<T> beanType) {
|
||||
return XServiceProvider.fetchGroupQueryFor(beanType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -67,12 +67,26 @@ public interface FetchGroupBuilder<T> {
|
||||
@Nonnull
|
||||
FetchGroupBuilder<T> fetchQuery(String path);
|
||||
|
||||
/**
|
||||
* Fetch the path including all its properties using L2 cache.
|
||||
* Cache misses fallback to fetchQuery().
|
||||
*/
|
||||
@Nonnull
|
||||
FetchGroupBuilder<T> fetchCache(String path);
|
||||
|
||||
/**
|
||||
* Fetch the path including specified properties using a query join.
|
||||
*/
|
||||
@Nonnull
|
||||
FetchGroupBuilder<T> fetchQuery(String path, String properties);
|
||||
|
||||
/**
|
||||
* Fetch the path including specified properties using L2 cache.
|
||||
* Cache misses fallback to fetchQuery().
|
||||
*/
|
||||
@Nonnull
|
||||
FetchGroupBuilder<T> fetchCache(String path, String properties);
|
||||
|
||||
/**
|
||||
* Fetch the path including all its properties lazily.
|
||||
*/
|
||||
|
||||
@@ -25,14 +25,14 @@ import java.util.Set;
|
||||
* // get a list of entities (query execution statistics in this case)
|
||||
*
|
||||
* List<MetaQueryStatistic> list =
|
||||
* Ebean.find(MetaQueryStatistic.class).findList();
|
||||
* DB.find(MetaQueryStatistic.class).findList();
|
||||
*
|
||||
* long nowMinus24Hrs = System.currentTimeMillis() - 24 * (1000 * 60 * 60);
|
||||
*
|
||||
* // sort and filter the list returning a filtered list...
|
||||
*
|
||||
* List<MetaQueryStatistic> filteredList =
|
||||
* Ebean.filter(MetaQueryStatistic.class)
|
||||
* DB.filter(MetaQueryStatistic.class)
|
||||
* .sort("avgTimeMicros desc")
|
||||
* .gt("executionCount", 0)
|
||||
* .gt("lastQueryTime", nowMinus24Hrs)
|
||||
@@ -63,12 +63,12 @@ import java.util.Set;
|
||||
* // get a list of entities (query execution statistics)
|
||||
*
|
||||
* List<Order> orders =
|
||||
* Ebean.find(Order.class).findList();
|
||||
* DB.find(Order.class).findList();
|
||||
*
|
||||
* // Apply a filter...
|
||||
*
|
||||
* List<Order> filteredOrders =
|
||||
* Ebean.filter(Order.class)
|
||||
* DB.filter(Order.class)
|
||||
* .startsWith("customer.name", "Rob")
|
||||
* .eq("customer.shippingAddress.city", "Auckland")
|
||||
* .filter(orders);
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.ebean;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -14,8 +13,7 @@ import java.util.List;
|
||||
* </p>
|
||||
* <h3>Testing</h3>
|
||||
* <p>
|
||||
* For testing the mocki-ebean project has the ability to replace the finder implementation
|
||||
* <p>
|
||||
* For testing the mocki-ebean project has the ability to replace the finder implementation.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
@@ -25,7 +23,7 @@ import java.util.List;
|
||||
* super(Customer.class);
|
||||
* }
|
||||
*
|
||||
* // Add your customer finder methods ...
|
||||
* // Add finder methods ...
|
||||
*
|
||||
* public Customer byName(String name) {
|
||||
* return query().eq("name", name).findOne();
|
||||
@@ -46,6 +44,15 @@ import java.util.List;
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* When the Finder is registered as a field on Customer it can then be used like:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer rob = Customer.find.byName("Rob");
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
public class Finder<I, T> {
|
||||
|
||||
@@ -55,9 +62,9 @@ public class Finder<I, T> {
|
||||
private final Class<T> type;
|
||||
|
||||
/**
|
||||
* The name of the EbeanServer, null for the default server.
|
||||
* The name of the database this finder will use, null for the default database.
|
||||
*/
|
||||
private final String serverName;
|
||||
private final String _$dbName;
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean.
|
||||
@@ -82,15 +89,15 @@ public class Finder<I, T> {
|
||||
*/
|
||||
public Finder(Class<T> type) {
|
||||
this.type = type;
|
||||
this.serverName = null;
|
||||
this._$dbName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean and specific server name.
|
||||
* Create with the type of the entity bean and specific database name.
|
||||
*/
|
||||
public Finder(Class<T> type, String serverName) {
|
||||
public Finder(Class<T> type, String databaseName) {
|
||||
this.type = type;
|
||||
this.serverName = serverName;
|
||||
this._$dbName = databaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,30 +115,27 @@ public class Finder<I, T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' EbeanServer.
|
||||
* <p>
|
||||
* This provides full access to the API such as explicit transaction demarcation etc.
|
||||
* Return the Database this finder will use.
|
||||
*/
|
||||
public EbeanServer db() {
|
||||
return Ebean.getServer(serverName);
|
||||
public Database db() {
|
||||
return DB.byName(_$dbName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return typically a different EbeanServer to the default.
|
||||
* Return typically a different Database to the default.
|
||||
* <p>
|
||||
* This is equivalent to {@link Ebean#getServer(String)}
|
||||
* This is equivalent to {@link DB#byName(String)}
|
||||
*
|
||||
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is
|
||||
* returned.
|
||||
* @param databaseName The name of the Database. If this is null then the default database is returned.
|
||||
*/
|
||||
public EbeanServer db(String server) {
|
||||
return Ebean.getServer(server);
|
||||
public Database db(String databaseName) {
|
||||
return DB.byName(databaseName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an entity reference for this ID.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
|
||||
* Equivalent to {@link Database#getReference(Class, Object)}
|
||||
*/
|
||||
@Nonnull
|
||||
public T ref(I id) {
|
||||
@@ -141,7 +145,7 @@ public class Finder<I, T> {
|
||||
/**
|
||||
* Retrieves an entity by ID.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class, Object)}
|
||||
* Equivalent to {@link Database#find(Class, Object)}
|
||||
*/
|
||||
@Nullable
|
||||
public T byId(I id) {
|
||||
@@ -151,7 +155,7 @@ public class Finder<I, T> {
|
||||
/**
|
||||
* Delete a bean by Id.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#delete(Class, Object)}
|
||||
* Equivalent to {@link Database#delete(Class, Object)}
|
||||
*/
|
||||
public void deleteById(I id) {
|
||||
db().delete(type, id);
|
||||
@@ -181,7 +185,7 @@ public class Finder<I, T> {
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#update(Class)}
|
||||
* Equivalent to {@link Database#update(Class)}
|
||||
*/
|
||||
public UpdateQuery<T> update() {
|
||||
return db().update(type);
|
||||
@@ -190,7 +194,7 @@ public class Finder<I, T> {
|
||||
/**
|
||||
* Creates a query.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class)}
|
||||
* Equivalent to {@link Database#find(Class)}
|
||||
*/
|
||||
public Query<T> query() {
|
||||
return db().find(type);
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.util.concurrent.TimeoutException;
|
||||
* <pre>{@code
|
||||
*
|
||||
* // create a query to find all orders
|
||||
* Query<Order> query = Ebean.find(Order.class);
|
||||
* Query<Order> query = DB.find(Order.class);
|
||||
*
|
||||
* // execute the query in a background thread
|
||||
* // immediately returning the futureList
|
||||
|
||||
@@ -11,7 +11,7 @@ package io.ebean;
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* Query q =
|
||||
* Ebean.find(Person.class)
|
||||
* DB.find(Person.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .like("name", "Rob%")
|
||||
@@ -30,7 +30,7 @@ package io.ebean;
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query q =
|
||||
* Ebean.find(Person.class)
|
||||
* DB.find(Person.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .like("name", "Rob%")
|
||||
@@ -50,7 +50,7 @@ package io.ebean;
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* Query<Customer> q =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .and()
|
||||
|
||||
@@ -78,6 +78,7 @@ public class MergeOptionsBuilder {
|
||||
this.deletePermanent = deletePermanent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> paths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.ebean;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
/**
|
||||
* A MappedSuperclass base class that provides convenience methods for inserting, updating and
|
||||
@@ -12,15 +11,15 @@ import javax.persistence.MappedSuperclass;
|
||||
* Ebean users.
|
||||
* <p>
|
||||
* Note that there is a ebean-mocker project that enables you to use Mockito or similar
|
||||
* tools to still mock out the underlying 'default EbeanServer' for testing purposes.
|
||||
* tools to still mock out the underlying 'default Database' for testing purposes.
|
||||
* <p>
|
||||
* You may choose not use this Model mapped superclass if you don't like the 'Active Record' style
|
||||
* or if you believe it 'pollutes' your entity beans.
|
||||
* <p>
|
||||
* You can use Dependency Injection like Guice or Spring to construct and wire a EbeanServer instance
|
||||
* You can use Dependency Injection like Guice or Spring to construct and wire a Database instance
|
||||
* and have that same instance used with this Model and Finder. The way that works is that when the
|
||||
* DI container creates the EbeanServer instance it can be registered with the Ebean singleton. In this
|
||||
* way the EbeanServer instance can be injected as per normal Guice / Spring dependency injection and
|
||||
* DI container creates the Database instance it can be registered with DB. In this
|
||||
* way the Database instance can be injected as per normal Guice / Spring dependency injection and
|
||||
* that same instance also used to support the Model and Finder active record style.
|
||||
* <p>
|
||||
* If you choose to use the Model mapped superclass you will probably also chose to additionally add
|
||||
@@ -74,19 +73,36 @@ import javax.persistence.MappedSuperclass;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public abstract class Model {
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' EbeanServer.
|
||||
* The name of the database this entity will use, null for the default database.
|
||||
*/
|
||||
private final String _$dbName;
|
||||
|
||||
/**
|
||||
* Create using the default database.
|
||||
*/
|
||||
public Model() {
|
||||
this._$dbName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with a named database (typically not the default database).
|
||||
*/
|
||||
public Model(String dbName) {
|
||||
this._$dbName = dbName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' Database.
|
||||
* <p>
|
||||
* This provides full access to the API such as explicit transaction demarcation etc.
|
||||
* <p>
|
||||
* Example:
|
||||
* <pre>{@code
|
||||
*
|
||||
* Transaction transaction = Customer.db().beginTransaction();
|
||||
* try {
|
||||
* try (Transaction transaction = Customer.db().beginTransaction()) {
|
||||
*
|
||||
* // turn off cascade persist for this transaction
|
||||
* transaction.setPersistCascade(false);
|
||||
@@ -106,26 +122,12 @@ public abstract class Model {
|
||||
*
|
||||
* transaction.commit();
|
||||
*
|
||||
* } finally {
|
||||
* transaction.end();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static EbeanServer db() {
|
||||
return Ebean.getDefaultServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a named EbeanServer that is typically different to the default server.
|
||||
* <p>
|
||||
* If you are using multiple databases then each database has a name and maps to a single
|
||||
* EbeanServer. You can use this method to get an EbeanServer for another database.
|
||||
*
|
||||
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is returned.
|
||||
*/
|
||||
public static EbeanServer db(String server) {
|
||||
return Ebean.getServer(server);
|
||||
public Database db() {
|
||||
return DB.byName(_$dbName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,7 +150,7 @@ public abstract class Model {
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see EbeanServer#markAsDirty(Object)
|
||||
* @see Database#markAsDirty(Object)
|
||||
*/
|
||||
public void markAsDirty() {
|
||||
db().markAsDirty(this);
|
||||
@@ -184,7 +186,7 @@ public abstract class Model {
|
||||
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
|
||||
* insert or an update based on that.
|
||||
*
|
||||
* @see EbeanServer#save(Object)
|
||||
* @see Database#save(Object)
|
||||
*/
|
||||
public void save() {
|
||||
db().save(this);
|
||||
@@ -204,7 +206,7 @@ public abstract class Model {
|
||||
/**
|
||||
* Update this entity.
|
||||
*
|
||||
* @see EbeanServer#update(Object)
|
||||
* @see Database#update(Object)
|
||||
*/
|
||||
public void update() {
|
||||
db().update(this);
|
||||
@@ -213,7 +215,7 @@ public abstract class Model {
|
||||
/**
|
||||
* Insert this entity.
|
||||
*
|
||||
* @see EbeanServer#insert(Object)
|
||||
* @see Database#insert(Object)
|
||||
*/
|
||||
public void insert() {
|
||||
db().insert(this);
|
||||
@@ -234,7 +236,7 @@ public abstract class Model {
|
||||
* deleted. Note that, if JDBC batch mode is used then this always returns true.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#delete(Object)
|
||||
* @see Database#delete(Object)
|
||||
*/
|
||||
public boolean delete() {
|
||||
return db().delete(this);
|
||||
@@ -247,37 +249,16 @@ public abstract class Model {
|
||||
* want to perform a hard/permanent delete.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#deletePermanent(Object)
|
||||
* @see Database#deletePermanent(Object)
|
||||
*/
|
||||
public boolean deletePermanent() {
|
||||
return db().deletePermanent(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an update using this entity against the specified server.
|
||||
*/
|
||||
public void update(String server) {
|
||||
db(server).update(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an insert using this entity against the specified server.
|
||||
*/
|
||||
public void insert(String server) {
|
||||
db(server).insert(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a delete using this entity against the specified server.
|
||||
*/
|
||||
public boolean delete(String server) {
|
||||
return db(server).delete(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes this entity from the database.
|
||||
*
|
||||
* @see EbeanServer#refresh(Object)
|
||||
* @see Database#refresh(Object)
|
||||
*/
|
||||
public void refresh() {
|
||||
db().refresh(this);
|
||||
|
||||
@@ -4,7 +4,6 @@ import io.ebean.util.StringHelper;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -81,7 +80,6 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Add a property with ascending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> asc(String propertyName, String collation) {
|
||||
|
||||
list.add(new Property(propertyName, true, collation));
|
||||
return query;
|
||||
}
|
||||
@@ -90,7 +88,6 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Add a property with descending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> desc(String propertyName) {
|
||||
|
||||
list.add(new Property(propertyName, false));
|
||||
return query;
|
||||
}
|
||||
@@ -99,7 +96,6 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Add a property with descending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> desc(String propertyName, String collation) {
|
||||
|
||||
list.add(new Property(propertyName, false, collation));
|
||||
return query;
|
||||
}
|
||||
@@ -109,7 +105,6 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Return true if the property is known to be contained in the order by clause.
|
||||
*/
|
||||
public boolean containsProperty(String propertyName) {
|
||||
|
||||
for (Property aList : list) {
|
||||
if (propertyName.equals(aList.getProperty())) {
|
||||
return true;
|
||||
@@ -162,10 +157,9 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Return a copy of the OrderBy.
|
||||
*/
|
||||
public OrderBy<T> copy() {
|
||||
|
||||
OrderBy<T> copy = new OrderBy<>();
|
||||
for (Property aList : list) {
|
||||
copy.add(aList.copy());
|
||||
for (Property property : list) {
|
||||
copy.add(property.copy());
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
@@ -242,6 +236,18 @@ public final class OrderBy<T> implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this order by can be used in select clause.
|
||||
*/
|
||||
public boolean supportsSelect() {
|
||||
for (Property property : list) {
|
||||
if (!property.supportsSelect()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A property and its ascending descending order.
|
||||
*/
|
||||
@@ -402,6 +408,12 @@ public final class OrderBy<T> implements Serializable {
|
||||
this.ascending = ascending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support use in select clause if no collation or nulls ordering.
|
||||
*/
|
||||
boolean supportsSelect() {
|
||||
return nulls == null;
|
||||
}
|
||||
}
|
||||
|
||||
private void parse(String orderByClause) {
|
||||
@@ -412,15 +424,15 @@ public final class OrderBy<T> implements Serializable {
|
||||
|
||||
String[] chunks = orderByClause.split(",");
|
||||
for (String chunk : chunks) {
|
||||
String[] pairs = chunk.split(" ");
|
||||
Property p = parseProperty(pairs);
|
||||
Property p = parseProperty(chunk);
|
||||
if (p != null) {
|
||||
list.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Property parseProperty(String[] pairs) {
|
||||
private Property parseProperty(String chunk) {
|
||||
String[] pairs = chunk.split(" ");
|
||||
if (pairs.length == 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -446,8 +458,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
boolean asc = isAscending(wordList.get(1));
|
||||
return new Property(wordList.get(0), asc, wordList.get(2), wordList.get(3));
|
||||
}
|
||||
String m = "Expecting a 1, 2 or 4 words in [" + Arrays.toString(pairs) + "] but got " + wordList;
|
||||
throw new RuntimeException(m);
|
||||
return new Property(chunk.trim(), true);
|
||||
}
|
||||
|
||||
private boolean isAscending(String s) {
|
||||
|
||||
@@ -24,8 +24,7 @@ import java.util.concurrent.Future;
|
||||
* // We want to find the first 50 new orders
|
||||
* // ... so we don't really need setFirstRow(0)
|
||||
*
|
||||
* PagedList<Order> pagedList
|
||||
* = ebeanServer.find(Order.class)
|
||||
* PagedList<Order> pagedList = DB.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .setFirstRow(0)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -25,7 +26,7 @@ import java.util.List;
|
||||
* pairs.add("sj2", 1001);
|
||||
* pairs.add("pf3", 1000);
|
||||
*
|
||||
* List<OCachedNatKeyBean3> list = Ebean.find(OCachedNatKeyBean3.class)
|
||||
* List<OCachedNatKeyBean3> list = DB.find(OCachedNatKeyBean3.class)
|
||||
* .where()
|
||||
* .eq("store", "def")
|
||||
* .inPairs(pairs) // IN clause with 'pairs' of values
|
||||
@@ -125,7 +126,7 @@ public class Pairs {
|
||||
* Return all the value pairs.
|
||||
*/
|
||||
public List<Entry> getEntries() {
|
||||
return entries;
|
||||
return Collections.unmodifiableList(entries);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,11 @@ public interface ProfileLocation {
|
||||
*/
|
||||
String shortDescription();
|
||||
|
||||
/**
|
||||
* Return the short label.
|
||||
*/
|
||||
String label();
|
||||
|
||||
/**
|
||||
* Add execution time.
|
||||
*/
|
||||
|
||||
+213
-102
@@ -3,6 +3,7 @@ package io.ebean;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -19,10 +20,7 @@ import java.util.function.Predicate;
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> orderList =
|
||||
* ebeanServer.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .fetch("details")
|
||||
* List<Order> orderList = DB.find(Order.class)
|
||||
* .where()
|
||||
* .like("customer.name","rob%")
|
||||
* .gt("orderDate",lastWeek)
|
||||
@@ -38,29 +36,14 @@ import java.util.function.Predicate;
|
||||
* <pre>{@code
|
||||
*
|
||||
* String oql =
|
||||
* +" fetch customer "
|
||||
* +" fetch details "
|
||||
* +" where customer.name like :custName and orderDate > :minOrderDate "
|
||||
* +" order by customer.id, id desc "
|
||||
* +" limit 50 ";
|
||||
*
|
||||
* Query<Order> query = ebeanServer.createQuery(Order.class, oql);
|
||||
* query.setParameter("custName", "Rob%");
|
||||
* query.setParameter("minOrderDate", lastWeek);
|
||||
*
|
||||
* List<Order> orderList = query.findList();
|
||||
* ...
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using a named query called "with.cust.and.details"
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Order> query = ebeanServer.createNamedQuery(Order.class,"with.cust.and.details");
|
||||
* query.setParameter("custName", "Rob%");
|
||||
* query.setParameter("minOrderDate", lastWeek);
|
||||
*
|
||||
* List<Order> orderList = query.findList();
|
||||
* List<Order> orderList = DB.createQuery(Order.class, oql)
|
||||
* .setParameter("custName", "Rob%")
|
||||
* .setParameter("minOrderDate", lastWeek)
|
||||
* .findList();
|
||||
* ...
|
||||
* }</pre>
|
||||
* <h3>AutoTune</h3>
|
||||
@@ -244,6 +227,38 @@ public interface Query<T> {
|
||||
*/
|
||||
<D> DtoQuery<D> asDto(Class<D> dtoClass);
|
||||
|
||||
/**
|
||||
* Convert the query to a UpdateQuery.
|
||||
* <p>
|
||||
* Typically this is used with query beans to covert a query bean
|
||||
* query into an UpdateQuery like the examples below.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rowsUpdated = new QCustomer()
|
||||
* .name.startsWith("Rob")
|
||||
* .asUpdate()
|
||||
* .set("active", false)
|
||||
* .update();;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rowsUpdated = new QContact()
|
||||
* .notes.note.startsWith("Make Inactive")
|
||||
* .email.endsWith("@foo.com")
|
||||
* .customer.id.equalTo(42)
|
||||
* .asUpdate()
|
||||
* .set("inactive", true)
|
||||
* .setRaw("email = lower(email)")
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
UpdateQuery<T> asUpdate();
|
||||
|
||||
/**
|
||||
* Cancel the query execution if supported by the underlying database and
|
||||
* driver.
|
||||
@@ -340,6 +355,27 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> setAutoTune(boolean autoTune);
|
||||
|
||||
/**
|
||||
* Execute the query allowing properties with invalid JSON to be collected and not fail the query.
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch a bean with JSON content
|
||||
* EBasicJsonList bean= DB.find(EBasicJsonList.class)
|
||||
* .setId(42)
|
||||
* .setAllowLoadErrors() // collect errors into bean state if we have invalid JSON
|
||||
* .findOne();
|
||||
*
|
||||
*
|
||||
* // get the invalid JSON errors from the bean state
|
||||
* Map<String, Exception> errors = server().getBeanState(bean).getLoadErrors();
|
||||
*
|
||||
* // If this map is not empty tell we have invalid JSON
|
||||
* // and should try and fix the JSON content or inform the user
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Query<T> setAllowLoadErrors();
|
||||
|
||||
/**
|
||||
* Set the default lazy loading batch size to use.
|
||||
* <p>
|
||||
@@ -383,8 +419,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* // Only fetch the customer id, name and status.
|
||||
* // This is described as a "Partial Object"
|
||||
* .select("name, status")
|
||||
@@ -412,8 +447,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // query orders...
|
||||
* List<Order> orders =
|
||||
* ebeanServer.find(Order.class)
|
||||
* List<Order> orders = DB.find(Order.class)
|
||||
* // fetch the customer...
|
||||
* // ... getting the customers name and phone number
|
||||
* .fetch("customer", "name, phoneNumber")
|
||||
@@ -428,8 +462,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch customers (their id, name and status)
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* .select("name, status")
|
||||
* .fetch("contacts", "firstName,lastName,email")
|
||||
* .findList();
|
||||
@@ -468,6 +501,14 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> fetchQuery(String path, String fetchProperties);
|
||||
|
||||
/**
|
||||
* Fetch the path and properties using L2 bean cache.
|
||||
*
|
||||
* @param path The path of the beans we are fetching from L2 cache.
|
||||
* @param fetchProperties The properties that should be loaded.
|
||||
*/
|
||||
Query<T> fetchCache(String path, String fetchProperties);
|
||||
|
||||
/**
|
||||
* Fetch the path and properties lazily (via batch lazy loading).
|
||||
* <p>
|
||||
@@ -498,8 +539,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch customers (their id, name and status)
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* .select("name, status")
|
||||
* .fetch("contacts", "firstName,lastName,email", new FetchConfig().lazy(10))
|
||||
* .findList();
|
||||
@@ -520,8 +560,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch customers (their id, name and status)
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* // eager fetch the contacts
|
||||
* .fetch("contacts")
|
||||
* .findList();
|
||||
@@ -556,6 +595,11 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> fetchQuery(String path);
|
||||
|
||||
/**
|
||||
* Fetch the path eagerly using L2 cache.
|
||||
*/
|
||||
Query<T> fetchCache(String path);
|
||||
|
||||
/**
|
||||
* Fetch the path lazily (via batch lazy loading).
|
||||
* <p>
|
||||
@@ -584,8 +628,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch customers (their id, name and status)
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* // lazy fetch contacts with a batch size of 100
|
||||
* .fetch("contacts", new FetchConfig().lazy(100))
|
||||
* .findList();
|
||||
@@ -602,10 +645,20 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> apply(FetchPath fetchPath);
|
||||
|
||||
/**
|
||||
* Execute the query using the given transaction.
|
||||
*/
|
||||
Query<T> usingTransaction(Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query using the given connection.
|
||||
*/
|
||||
Query<T> usingConnection(Connection connection);
|
||||
|
||||
/**
|
||||
* Execute the query returning the list of Id's.
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* This query will execute against the Database that was used to create it.
|
||||
* </p>
|
||||
*/
|
||||
@Nonnull
|
||||
@@ -627,24 +680,21 @@ public interface Query<T> {
|
||||
* the jdbc statement and resultSet are closed at the end of the iteration.
|
||||
* </p>
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* This query will execute against the Database that was used to create it.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Customer> query =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* Query<Customer> query = DB.find(Customer.class)
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id");
|
||||
*
|
||||
* QueryIterator<Customer> it = query.findIterate();
|
||||
* try {
|
||||
* // use try with resources to ensure QueryIterator is closed
|
||||
*
|
||||
* try (QueryIterator<Customer> it = query.findIterate()) {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer ...
|
||||
* }
|
||||
* } finally {
|
||||
* // close the underlying resources
|
||||
* it.close();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
@@ -681,7 +731,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* ebeanServer.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .findEach((Customer customer) -> {
|
||||
@@ -710,7 +760,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* ebeanServer.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id")
|
||||
@@ -733,12 +783,11 @@ public interface Query<T> {
|
||||
/**
|
||||
* Execute the query returning the list of objects.
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* This query will execute against the Database that was used to create it.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* .where().ilike("name", "rob%")
|
||||
* .findList();
|
||||
*
|
||||
@@ -750,12 +799,11 @@ public interface Query<T> {
|
||||
/**
|
||||
* Execute the query returning the set of objects.
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* This query will execute against the Database that was used to create it.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Set<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* Set<Customer> customers = DB.find(Customer.class)
|
||||
* .where().ilike("name", "rob%")
|
||||
* .findSet();
|
||||
*
|
||||
@@ -767,7 +815,7 @@ public interface Query<T> {
|
||||
/**
|
||||
* Execute the query returning a map of the objects.
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* This query will execute against the Database that was used to create it.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can use setMapKey() so specify the property values to be used as keys
|
||||
@@ -775,8 +823,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Map<String, Product> map =
|
||||
* ebeanServer.find(Product.class)
|
||||
* Map<String, Product> map = DB.find(Product.class)
|
||||
* .setMapKey("sku")
|
||||
* .findMap();
|
||||
*
|
||||
@@ -792,7 +839,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .select("name")
|
||||
* .orderBy().asc("name")
|
||||
* .findSingleAttributeList();
|
||||
@@ -803,7 +850,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .where().eq("status", Customer.Status.NEW)
|
||||
@@ -824,7 +871,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* String name =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .select("name")
|
||||
* .where().eq("id", 42)
|
||||
* .findSingleAttribute();
|
||||
@@ -838,6 +885,37 @@ public interface Query<T> {
|
||||
*/
|
||||
boolean isCountDistinct();
|
||||
|
||||
/**
|
||||
* Execute the query returning true if a row is found.
|
||||
* <p>
|
||||
* The query is executed using max rows of 1 and will only select the id property.
|
||||
* This method is really just a convenient way to optimise a query to perform a
|
||||
* 'does a row exist in the db' check.
|
||||
* </p>
|
||||
*
|
||||
* <h2>Example using a query bean:</h2>
|
||||
* <pre>{@code
|
||||
*
|
||||
* boolean userExists =
|
||||
* new QContact()
|
||||
* .email.equalTo("rob@foo.com")
|
||||
* .exists();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h2>Example:</h2>
|
||||
* <pre>{@code
|
||||
*
|
||||
* boolean userExists = query()
|
||||
* .where().eq("email", "rob@foo.com")
|
||||
* .exists();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @return True if the query finds a matching row in the database
|
||||
*/
|
||||
boolean exists();
|
||||
|
||||
/**
|
||||
* Execute the query returning either a single bean or null (if no matching
|
||||
* bean is found).
|
||||
@@ -852,8 +930,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // assuming the sku of products is unique...
|
||||
* Product product =
|
||||
* ebeanServer.find(Product.class)
|
||||
* Product product = DB.find(Product.class)
|
||||
* .where().eq("sku", "aa113")
|
||||
* .findOne();
|
||||
* ...
|
||||
@@ -865,8 +942,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Fetch order 1 and additionally fetch join its order details...
|
||||
* Order order =
|
||||
* ebeanServer.find(Order.class)
|
||||
* Order order = DB.find(Order.class)
|
||||
* .setId(1)
|
||||
* .fetch("details")
|
||||
* .findOne();
|
||||
@@ -924,11 +1000,31 @@ public interface Query<T> {
|
||||
*/
|
||||
int delete();
|
||||
|
||||
/**
|
||||
* Execute as a delete query returning the number of rows deleted using the given transaction.
|
||||
* <p>
|
||||
* Note that if the query includes joins then the generated delete statement may not be
|
||||
* optimal depending on the database platform.
|
||||
* </p>
|
||||
*
|
||||
* @return the number of beans/rows that were deleted.
|
||||
*/
|
||||
int delete(Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the UpdateQuery returning the number of rows updated.
|
||||
*
|
||||
* @return the number of beans/rows updated.
|
||||
*/
|
||||
int update();
|
||||
|
||||
/**
|
||||
* Execute the UpdateQuery returning the number of rows updated using the given transaction.
|
||||
*
|
||||
* @return the number of beans/rows updated.
|
||||
*/
|
||||
int update(Transaction transaction);
|
||||
|
||||
/**
|
||||
* Return the count of entities this query should return.
|
||||
* <p>
|
||||
@@ -987,7 +1083,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Order> pagedList = Ebean.find(Order.class)
|
||||
* PagedList<Order> pagedList = DB.find(Order.class)
|
||||
* .setFirstRow(50)
|
||||
* .setMaxRows(20)
|
||||
* .findPagedList();
|
||||
@@ -1012,11 +1108,9 @@ public interface Query<T> {
|
||||
* // a query with a named parameter
|
||||
* String oql = "find order where status = :orderStatus";
|
||||
*
|
||||
* Query<Order> query = ebeanServer.find(Order.class, oql);
|
||||
*
|
||||
* // bind the named parameter
|
||||
* query.bind("orderStatus", OrderStatus.NEW);
|
||||
* List<Order> list = query.findList();
|
||||
* List<Order> list = DB.find(Order.class, oql)
|
||||
* .setParameter("orderStatus", OrderStatus.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
@@ -1034,12 +1128,9 @@ public interface Query<T> {
|
||||
* // a query with a positioned parameter
|
||||
* String oql = "where status = ? order by id desc";
|
||||
*
|
||||
* Query<Order> query = ebeanServer.createQuery(Order.class, oql);
|
||||
*
|
||||
* // bind the parameter
|
||||
* query.setParameter(1, OrderStatus.NEW);
|
||||
*
|
||||
* List<Order> list = query.findList();
|
||||
* List<Order> list = DB.createQuery(Order.class, oql)
|
||||
* .setParameter(1, OrderStatus.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
@@ -1056,8 +1147,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Order order =
|
||||
* ebeanServer.find(Order.class)
|
||||
* Order order = DB.find(Order.class)
|
||||
* .setId(1)
|
||||
* .fetch("details")
|
||||
* .findOne();
|
||||
@@ -1078,8 +1168,7 @@ public interface Query<T> {
|
||||
* Add a single Expression to the where clause returning the query.
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> newOrders =
|
||||
* ebeanServer.find(Order.class)
|
||||
* List<Order> newOrders = DB.find(Order.class)
|
||||
* .where().eq("status", Order.NEW)
|
||||
* .findList();
|
||||
* ...
|
||||
@@ -1094,8 +1183,7 @@ public interface Query<T> {
|
||||
* where clause.
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> orders =
|
||||
* ebeanServer.find(Order.class)
|
||||
* List<Order> orders = DB.find(Order.class)
|
||||
* .where()
|
||||
* .eq("status", Order.NEW)
|
||||
* .ilike("customer.name","rob%")
|
||||
@@ -1141,10 +1229,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> list =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* // .fetch("orders", new FetchConfig().lazy())
|
||||
* // .fetch("orders", new FetchConfig().query())
|
||||
* List<Customer> list = DB.find(Customer.class)
|
||||
* .fetch("orders")
|
||||
* .where().ilike("name", "rob%")
|
||||
* .filterMany("orders").eq("status", Order.Status.NEW).gt("orderDate", lastWeek)
|
||||
@@ -1158,8 +1243,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
*
|
||||
* @param propertyName the name of the many property that you want to have a filter on.
|
||||
* @return the expression list that you add filter expressions for the many
|
||||
* to.
|
||||
* @return the expression list that you add filter expressions for the many to.
|
||||
*/
|
||||
ExpressionList<T> filterMany(String propertyName);
|
||||
|
||||
@@ -1273,7 +1357,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .findList();
|
||||
@@ -1289,7 +1373,7 @@ public interface Query<T> {
|
||||
*
|
||||
* List<CountedValue<Order.Status>> orderStatusCount =
|
||||
*
|
||||
* Ebean.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .select("status")
|
||||
* .where()
|
||||
* .gt("orderDate", LocalDate.now().minusMonths(3))
|
||||
@@ -1309,7 +1393,6 @@ public interface Query<T> {
|
||||
* count:1 orderStatus:COMPLETE
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
Query<T> setCountDistinct(CountDistinctOrder orderBy);
|
||||
|
||||
@@ -1346,10 +1429,8 @@ public interface Query<T> {
|
||||
*
|
||||
* // Assuming sku is unique for products...
|
||||
*
|
||||
* Map<String,Product> productMap =
|
||||
* ebeanServer.find(Product.class)
|
||||
* // use sku for keys...
|
||||
* .setMapKey("sku")
|
||||
* Map<String,Product> productMap = DB.find(Product.class)
|
||||
* .setMapKey("sku") // sku map keys...
|
||||
* .findMap();
|
||||
*
|
||||
* }</pre>
|
||||
@@ -1485,15 +1566,6 @@ public interface Query<T> {
|
||||
*/
|
||||
String getGeneratedSql();
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to forUpdate().
|
||||
*
|
||||
* executed the select with "for update" which should lock the record
|
||||
* "on read"
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> setForUpdate(boolean forUpdate);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause which results in the DB locking the record.
|
||||
*/
|
||||
@@ -1530,11 +1602,50 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> alias(String alias);
|
||||
|
||||
/**
|
||||
* Set the base table to use for this query.
|
||||
* <p>
|
||||
* Typically this is used when a table has partitioning and we wish to specify a specific
|
||||
* partition/table to query against.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* QOrder()
|
||||
* .setBaseTable("order_2019_05")
|
||||
* .status.equalTo(Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Query<T> setBaseTable(String baseTable);
|
||||
|
||||
/**
|
||||
* Return the type of beans being queried.
|
||||
*/
|
||||
Class<T> getBeanType();
|
||||
|
||||
/**
|
||||
* Restrict the query to only return subtypes of the given inherit type.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Animal> animals =
|
||||
* new QAnimal()
|
||||
* .name.startsWith("Fluffy")
|
||||
* .setInheritType(Cat.class)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param type An inheritance subtype of the
|
||||
*/
|
||||
Query<T> setInheritType(Class<? extends T> type);
|
||||
|
||||
/**
|
||||
* Returns the inherit type. This is normally the same as getBeanType() returns as long as no other type is set.
|
||||
*/
|
||||
Class<? extends T> getInheritType();
|
||||
|
||||
/**
|
||||
* Return the type of query being executed.
|
||||
*/
|
||||
|
||||
@@ -87,7 +87,7 @@ package io.ebean;
|
||||
* // .columnMapping("sum(d.order_qty*d.unit_price)", "totalAmount")
|
||||
* .create();
|
||||
*
|
||||
* List<OrderAggregate> list = Ebean.find(OrderAggregate.class)
|
||||
* List<OrderAggregate> list = DB.find(OrderAggregate.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .where().gt("order.id", 0)
|
||||
* .having().gt("totalAmount", 20)
|
||||
@@ -114,7 +114,7 @@ package io.ebean;
|
||||
* .columnMappingIgnore("'ignoreMe'")
|
||||
* .create();
|
||||
*
|
||||
* List<OrderAggregate> orders = Ebean.find(OrderAggregate.class)
|
||||
* List<OrderAggregate> orders = DB.find(OrderAggregate.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .fetch("order", "status,orderDate", new FetchConfig().query())
|
||||
* .fetch("order.customer", "name")
|
||||
@@ -146,7 +146,7 @@ package io.ebean;
|
||||
* .tableAliasMapping("p", "details.product")
|
||||
* .create();
|
||||
*
|
||||
* List<Order> ordersFromRaw = Ebean.find(Order.class)
|
||||
* List<Order> ordersFromRaw = DB.find(Order.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .setParameter("maxOrderId", 2)
|
||||
* .setParameter("productId", 1)
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.sql.SQLException;
|
||||
*
|
||||
* String sql = "select id, name, status from o_customer order by name desc";
|
||||
*
|
||||
* Ebean.createSqlQuery(sql)
|
||||
* DB.sqlQuery(sql)
|
||||
* .findEachRow((resultSet, rowNum) -> {
|
||||
*
|
||||
* // read directly from ResultSet
|
||||
|
||||
@@ -40,7 +40,7 @@ import java.sql.SQLException;
|
||||
*
|
||||
* String sql = "select id, name, status from o_customer where name = ?";
|
||||
*
|
||||
* CustomerDto rob = Ebean.createSqlQuery(sql)
|
||||
* CustomerDto rob = DB.sqlQuery(sql)
|
||||
* .setParameter(1, "Rob")
|
||||
* .findOne(CUSTOMER_MAPPER);
|
||||
*
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Runs DDL and SQL scripts.
|
||||
* <p/>
|
||||
* Typically these are scripts used for testing such as seed SQL scripts or truncate SQL scripts.
|
||||
* <p/>
|
||||
* Scripts are executed in their own transaction and committed on successful completion.
|
||||
*
|
||||
* <h3>Example of simple use</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Database database = DB.getDefault();
|
||||
* database.script().run("/scripts/test-script.sql");
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public interface ScriptRunner {
|
||||
|
||||
/**
|
||||
* Run a script given the resource path (that should start with "/").
|
||||
*/
|
||||
void run(String path);
|
||||
|
||||
/**
|
||||
* Run a script given the resource path (that should start with "/") and place holders.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Map<String,String> placeholders = new HashMap<>();
|
||||
* placeholders.put("tableName", "e_basic");
|
||||
*
|
||||
* Database database = DB.getDefault();
|
||||
* database.script().run("/scripts/test-script.sql", placeholders);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
void run(String path, Map<String, String> placeholderMap);
|
||||
|
||||
/**
|
||||
* Run a DDL or SQL script given the resource.
|
||||
*/
|
||||
void run(URL resource);
|
||||
|
||||
/**
|
||||
* Run a DDL or SQL script given the resource and place holders.
|
||||
*/
|
||||
void run(URL resource, Map<String, String> placeholderMap);
|
||||
|
||||
}
|
||||
@@ -10,34 +10,30 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Query object for performing native SQL queries that return SqlRow's.
|
||||
* <p>
|
||||
* Firstly note that you can use your own sql queries with <em>entity beans</em>
|
||||
* by using the SqlSelect annotation. This should be your first approach when
|
||||
* wanting to use your own SQL queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* If ORM Mapping is too tight and constraining for your problem then SqlQuery
|
||||
* could be a good approach.
|
||||
* </p>
|
||||
* Query object for performing native SQL queries that return SqlRow or directly read
|
||||
* ResultSet using a RowMapper.
|
||||
* <p>
|
||||
* The returned SqlRow objects are similar to a LinkedHashMap with some type
|
||||
* conversion support added.
|
||||
* </p>
|
||||
* <p>
|
||||
* Refer to {@link DtoQuery} for native sql queries returning DTO beans.
|
||||
* </p>
|
||||
* <p>
|
||||
* Refer to {@link Database#findNative(Class, String)} for native sql queries returning entity beans.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // its typically a good idea to use a named query
|
||||
* // and put the sql in the orm.xml instead of in your code
|
||||
* // example using named parameters
|
||||
*
|
||||
* String sql = "select id, name from customer where name like :name and status_code = :status";
|
||||
*
|
||||
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
|
||||
* sqlQuery.setParameter("name", "Acme%");
|
||||
* sqlQuery.setParameter("status", "ACTIVE");
|
||||
*
|
||||
* // execute the query returning a List of MapBean objects
|
||||
* List<SqlRow> list = sqlQuery.findList();
|
||||
* List<SqlRow> list =
|
||||
* DB.sqlQuery(sql)
|
||||
* .setParameter("name", "Acme%")
|
||||
* .setParameter("status", "ACTIVE")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@@ -104,7 +100,7 @@ public interface SqlQuery extends Serializable {
|
||||
*
|
||||
* String sql = "select id, name, status from customer order by name desc";
|
||||
*
|
||||
* Ebean.createSqlQuery(sql)
|
||||
* DB.sqlQuery(sql)
|
||||
* .findEachRow((resultSet, rowNum) -> {
|
||||
*
|
||||
* // read directly from ResultSet
|
||||
@@ -134,7 +130,7 @@ public interface SqlQuery extends Serializable {
|
||||
*
|
||||
* String sql = "select max(unit_price) from o_order_detail where order_qty > ?";
|
||||
*
|
||||
* BigDecimal maxPrice = Ebean.createSqlQuery(sql)
|
||||
* BigDecimal maxPrice = DB.sqlQuery(sql)
|
||||
* .setParameter(1, 2)
|
||||
* .findSingleAttribute(BigDecimal.class);
|
||||
*
|
||||
@@ -176,9 +172,10 @@ public interface SqlQuery extends Serializable {
|
||||
* " order by (unit_price * order_qty) desc";
|
||||
*
|
||||
* //
|
||||
* List<BigDecimal> lineAmounts = Ebean.createSqlQuery(sql)
|
||||
* .setParameter(1, 3)
|
||||
* .findSingleAttributeList(BigDecimal.class);
|
||||
* List<BigDecimal> lineAmounts =
|
||||
* DB.sqlQuery(sql)
|
||||
* .setParameter(1, 3)
|
||||
* .findSingleAttributeList(BigDecimal.class);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
@@ -195,6 +192,33 @@ public interface SqlQuery extends Serializable {
|
||||
*/
|
||||
SqlQuery setParameter(String name, Object value);
|
||||
|
||||
/**
|
||||
* Set one of more positioned parameters.
|
||||
* <p>
|
||||
* This is a convenient alternative to multiple calls setParameter().
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = "select id, name from customer where name like ? and status = ?";
|
||||
*
|
||||
* List<SqlRow> list =
|
||||
* DB.sqlQuery(sql)
|
||||
* .setParams("Rob", Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
*
|
||||
* // is the same as ...
|
||||
*
|
||||
* List<SqlRow> list =
|
||||
* DB.sqlQuery(sql)
|
||||
* .setParameter(1, "Rob")
|
||||
* .setParameter(2, "Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
SqlQuery setParams(Object... values);
|
||||
|
||||
/**
|
||||
* The same as bind for positioned parameters.
|
||||
*/
|
||||
|
||||
@@ -16,20 +16,33 @@ package io.ebean;
|
||||
* notify Ebean of external changes and enable Ebean to maintain it's "L2"
|
||||
* server cache.
|
||||
* </p>
|
||||
* <p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // example that uses 'named' parameters
|
||||
* // example using 'positioned' parameters
|
||||
*
|
||||
* String s = "UPDATE f_topic set post_count = :count where id = :id";
|
||||
* String sql = "insert into audit_log (group, title, description) values (?, ?, ?);
|
||||
*
|
||||
* SqlUpdate update = Ebean.createSqlUpdate(s);
|
||||
* update.setParameter("id", 1);
|
||||
* update.setParameter("count", 50);
|
||||
* int rows =
|
||||
* DB.sqlUpdate(sql)
|
||||
* .setParams("login", "new user", "user rob was created")
|
||||
* .executeNow();
|
||||
*
|
||||
* int modifiedCount = update.execute();
|
||||
* }</pre>
|
||||
*
|
||||
* String msg = "There were " + modifiedCount + " rows updated";
|
||||
* <pre>{@code
|
||||
*
|
||||
* // example using 'named' parameters
|
||||
*
|
||||
* String sql = "update topic set post_count = :count where id = :id";
|
||||
*
|
||||
* int rows =
|
||||
* DB.sqlUpdate(sql)
|
||||
* .setParameter("id", 1)
|
||||
* .setParameter("count", 50)
|
||||
* .execute();
|
||||
*
|
||||
* String msg = "There were " + rows + " rows updated";
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -37,9 +50,10 @@ package io.ebean;
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = "insert into audit_log (id, description, modified_description) values (?,?,?)";
|
||||
* SqlUpdate insert = Ebean.createSqlUpdate(sql);
|
||||
*
|
||||
* try (Transaction txn = Ebean.beginTransaction()) {
|
||||
* SqlUpdate insert = DB.sqlUpdate(sql);
|
||||
*
|
||||
* try (Transaction txn = DB.beginTransaction()) {
|
||||
* txn.setBatchMode(true);
|
||||
*
|
||||
* insert.setNextParameter(10000);
|
||||
@@ -65,7 +79,7 @@ package io.ebean;
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* try (Transaction txn = Ebean.beginTransaction()) {
|
||||
* try (Transaction txn = DB.beginTransaction()) {
|
||||
*
|
||||
* insert.setNextParameter(10000);
|
||||
* insert.setNextParameter("hello");
|
||||
@@ -98,6 +112,11 @@ public interface SqlUpdate {
|
||||
/**
|
||||
* Execute the update returning the number of rows modified.
|
||||
* <p>
|
||||
* Note that if the transaction has batch mode on then this update will use JDBC batch and may not execute until
|
||||
* later - at commit time or a transaction flush. In this case this method returns -1 indicating that the
|
||||
* update has been batched for later execution.
|
||||
* </p>
|
||||
* <p>
|
||||
* After you have executed the SqlUpdate you can bind new variables using
|
||||
* {@link #setParameter(String, Object)} etc and then execute the SqlUpdate
|
||||
* again.
|
||||
@@ -112,6 +131,11 @@ public interface SqlUpdate {
|
||||
*/
|
||||
int execute();
|
||||
|
||||
/**
|
||||
* Execute the statement now regardless of the JDBC batch mode of the transaction.
|
||||
*/
|
||||
int executeNow();
|
||||
|
||||
/**
|
||||
* Execute when addBatch() has been used to batch multiple bind executions.
|
||||
*
|
||||
@@ -207,6 +231,33 @@ public interface SqlUpdate {
|
||||
*/
|
||||
SqlUpdate setTimeout(int secs);
|
||||
|
||||
/**
|
||||
* Set one of more positioned parameters.
|
||||
* <p>
|
||||
* This is a convenient alternative to multiple setParameter() calls.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = "insert into audit_log (id, name, version) values (?,?,?)";
|
||||
*
|
||||
* DB.sqlUpdate(sql)
|
||||
* .setParams(UUID.randomUUID(), "Hello", 1)
|
||||
* .executeNow();
|
||||
*
|
||||
*
|
||||
* // is the same as ...
|
||||
*
|
||||
* DB.sqlUpdate(sql)
|
||||
* .setParameter(1, UUID.randomUUID())
|
||||
* .setParameter(2, "Hello")
|
||||
* .setParameter(3, 1)
|
||||
* .executeNow();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
SqlUpdate setParams(Object... values);
|
||||
|
||||
/**
|
||||
* Set the next positioned parameter.
|
||||
*
|
||||
|
||||
@@ -14,18 +14,17 @@ import java.sql.Connection;
|
||||
public interface Transaction extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* Return the current transaction (of the default server) or null if there is
|
||||
* Return the current transaction (of the default database) or null if there is
|
||||
* no current transaction in scope.
|
||||
* <p>
|
||||
* This is the same as <code>Ebean.currentTransaction()</code>
|
||||
* This is the same as <code>DB.currentTransaction()</code>
|
||||
* </p>
|
||||
* <p>
|
||||
* This returns the current transaction for the 'default server'. If you are using
|
||||
* multiple EbeanServer's then use {@link EbeanServer#currentTransaction()}.
|
||||
* This returns the current transaction for the default database.
|
||||
* </p>
|
||||
*
|
||||
* @see Ebean#currentTransaction()
|
||||
* @see EbeanServer#currentTransaction()
|
||||
* @see DB#currentTransaction()
|
||||
* @see Database#currentTransaction()
|
||||
*/
|
||||
static Transaction current() {
|
||||
return Ebean.currentTransaction();
|
||||
@@ -84,7 +83,7 @@ public interface Transaction extends AutoCloseable {
|
||||
* <p>
|
||||
* This is similar to commit() but leaves the transaction "Active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <h3>Functions</h3>
|
||||
* <ul>
|
||||
* <li>Flush the JDBC batch buffer</li>
|
||||
* <li>Call commit on the underlying JDBC connection</li>
|
||||
@@ -100,7 +99,7 @@ public interface Transaction extends AutoCloseable {
|
||||
* This performs commit and completes the transaction closing underlying resources and
|
||||
* marking the transaction as "In active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <h3>Functions</h3>
|
||||
* <ul>
|
||||
* <li>Flush the JDBC batch buffer</li>
|
||||
* <li>Call commit on the underlying JDBC connection</li>
|
||||
@@ -117,7 +116,7 @@ public interface Transaction extends AutoCloseable {
|
||||
* <p>
|
||||
* This performs rollback, closes underlying resources and marks the transaction as "In active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <h3>Functions</h3>
|
||||
* <ul>
|
||||
* <li>Call rollback on the underlying JDBC connection</li>
|
||||
* <li>Trigger any registered TransactionCallbacks</li>
|
||||
@@ -244,8 +243,7 @@ public interface Transaction extends AutoCloseable {
|
||||
*
|
||||
* // assume Customer has L2 bean caching enabled ...
|
||||
*
|
||||
* Transaction transaction = Ebean.beginTransaction();
|
||||
* try {
|
||||
* try (Transaction transaction = DB.beginTransaction()) {
|
||||
*
|
||||
* // this uses L2 bean cache as the transaction
|
||||
* // ... is considered "query only" at this point
|
||||
@@ -253,7 +251,7 @@ public interface Transaction extends AutoCloseable {
|
||||
*
|
||||
* // transaction no longer "query only" once
|
||||
* // ... a bean has been saved etc
|
||||
* Ebean.save(someBean);
|
||||
* someBean.save();
|
||||
*
|
||||
* // will NOT use L2 bean cache as the transaction
|
||||
* // ... is no longer considered "query only"
|
||||
@@ -273,8 +271,7 @@ public interface Transaction extends AutoCloseable {
|
||||
* Customer.find.byId(99); // skips l2 bean cache
|
||||
*
|
||||
*
|
||||
* } finally {
|
||||
* transaction.end();
|
||||
* transaction.commit();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
@@ -290,36 +287,66 @@ public interface Transaction extends AutoCloseable {
|
||||
boolean isSkipCache();
|
||||
|
||||
/**
|
||||
* Turn on or off statement batching. Statement batching can be transparent
|
||||
* for drivers and databases that support getGeneratedKeys. Otherwise you may
|
||||
* wish to specifically control when batching is used via this method.
|
||||
* <p>
|
||||
* Refer to <code>java.sql.PreparedStatement.addBatch();</code>
|
||||
* <p>
|
||||
* Note that you may also wish to use the setPersistCascade method to stop
|
||||
* save and delete cascade behaviour. You may do this to have full control
|
||||
* over the order of execution rather than the normal cascading fashion.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that the <em>execution order</em> in batch mode may be different from
|
||||
* non batch mode execution order. Also note that <em>insert behaviour</em>
|
||||
* may be different depending on the JDBC driver and its support for
|
||||
* getGeneratedKeys. That is, for JDBC drivers that do not support
|
||||
* getGeneratedKeys you may not get back the generated IDs (used for inserting
|
||||
* associated detail beans etc).
|
||||
* </p>
|
||||
* Turn on or off use of JDBC statement batching.
|
||||
* <p>
|
||||
* Calls to save(), delete(), insert() and execute() all support batch
|
||||
* processing. This includes normal beans, MapBean, CallableSql and UpdateSql.
|
||||
* processing. This includes normal beans, CallableSql and UpdateSql.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* try (Transaction transaction = server.beginTransaction()) {
|
||||
*
|
||||
* // turn on JDBC batch
|
||||
* transaction.setBatchMode(true);
|
||||
*
|
||||
* // tune the batch size
|
||||
* transaction.setBatchSize(50);
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* transaction.commit();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>getGeneratedKeys</h3>
|
||||
* <p>
|
||||
* The flushing of the batched statements is automatic but you can call
|
||||
* batchFlush when you like. Note that flushing occurs when a query is
|
||||
* executed or when you mix UpdateSql and CallableSql with save and delete of
|
||||
* Often with large batch inserts we want to turn off getGeneratedKeys. We do
|
||||
* this via {@link #setBatchGetGeneratedKeys(boolean)}.
|
||||
* Also note that some JDBC drivers do not support getGeneratedKeys in JDBC batch mode.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* try (Transaction transaction = server.beginTransaction()) {
|
||||
*
|
||||
* transaction.setBatchMode(true);
|
||||
* transaction.setBatchSize(100);
|
||||
* // insert but don't bother getting back the generated keys
|
||||
* transaction.setBatchGetGeneratedKeys(false);
|
||||
*
|
||||
*
|
||||
* // perform lots of inserts ...
|
||||
* ...
|
||||
*
|
||||
* transaction.commit();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Flush</h3>
|
||||
* <p>
|
||||
* 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>
|
||||
* Example: batch processing executing every 3 rows
|
||||
* We use {@link #flush()} to explicitly flush the batch and we can use
|
||||
* {@link #setBatchFlushOnQuery(boolean)} and {@link #setBatchFlushOnMixed(boolean)}
|
||||
* to control the automatic flushing behaviour.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example: batch processing of CallableSql executing every 10 rows
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
@@ -334,53 +361,27 @@ public interface Transaction extends AutoCloseable {
|
||||
* CallableSql cs = new CallableSql(sql);
|
||||
* cs.registerOut(2, Types.INTEGER);
|
||||
*
|
||||
* // (optional) inform eBean this stored procedure
|
||||
* // (optional) inform Ebean this stored procedure
|
||||
* // inserts into a table called sp_test
|
||||
* cs.addModification("sp_test", true, false, false);
|
||||
*
|
||||
* Transaction txn = ebeanServer.beginTransaction();
|
||||
* txn.setBatchMode(true);
|
||||
* txn.setBatchSize(3);
|
||||
* try {
|
||||
* try (Transaction txn = DB.beginTransaction()) {
|
||||
* txn.setBatchMode(true);
|
||||
* txn.setBatchSize(10);
|
||||
*
|
||||
* for (int i = 0; i < da.length;) {
|
||||
* cs.setParameter(1, da[i]);
|
||||
* ebeanServer.execute(cs);
|
||||
* DB.execute(cs);
|
||||
* }
|
||||
*
|
||||
* // NB: commit implicitly flushes
|
||||
* // Note: commit implicitly flushes
|
||||
* txn.commit();
|
||||
*
|
||||
* } finally {
|
||||
* txn.end();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
void setBatchMode(boolean useBatch);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to {@link #setBatchMode(boolean)}.
|
||||
* <p>
|
||||
* Set the JDBC batch mode to use for this transaction.
|
||||
* </p>
|
||||
* <p>
|
||||
* If this is NONE then JDBC batch can still be used for each request - save(), insert(), update() or delete()
|
||||
* and this would be useful if the request cascades to detail beans.
|
||||
* </p>
|
||||
*
|
||||
* @param persistBatchMode the batch mode to use for this transaction
|
||||
* @see io.ebean.config.ServerConfig#setPersistBatch(PersistBatch)
|
||||
*/
|
||||
@Deprecated
|
||||
void setBatch(PersistBatch persistBatchMode);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to {@link #isBatchMode()}.
|
||||
* Return the batch mode at the transaction level.
|
||||
*/
|
||||
@Deprecated
|
||||
PersistBatch getBatch();
|
||||
|
||||
/**
|
||||
* Return the batch mode at the transaction level.
|
||||
*/
|
||||
@@ -405,22 +406,6 @@ public interface Transaction extends AutoCloseable {
|
||||
*/
|
||||
void setBatchOnCascade(boolean batchMode);
|
||||
|
||||
/**
|
||||
* Set the batch mode when cascading.
|
||||
* <p>
|
||||
* Deprecated in favour of {@link #setBatchOnCascade(boolean)}
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
void setBatchOnCascade(PersistBatch batchOnCascadeMode);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to {@link #isBatchMode()}.
|
||||
* Return the batch mode at the request level (for each save(), insert(), update() or delete()).
|
||||
*/
|
||||
@Deprecated
|
||||
PersistBatch getBatchOnCascade();
|
||||
|
||||
/**
|
||||
* Return the batch mode at the request level.
|
||||
*/
|
||||
|
||||
@@ -432,4 +432,11 @@ public final class TxScope {
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isBatchMode() {
|
||||
return PersistBatch.ALL.equals(batch);
|
||||
}
|
||||
|
||||
public boolean isBatchOnCascade() {
|
||||
return PersistBatch.ALL.equals(batchOnCascade);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ package io.ebean;
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Update<Topic> update = Ebean.createUpdate(Topic.class, "incrementPostCount");
|
||||
* Update<Topic> update = DB.createUpdate(Topic.class, "incrementPostCount");
|
||||
* update.setParameter("id", 1);
|
||||
* int rows = update.execute();
|
||||
*
|
||||
|
||||
@@ -12,8 +12,7 @@ package io.ebean;
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* int rows = DB.update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
@@ -39,8 +38,7 @@ package io.ebean;
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* int rows = DB.update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
@@ -73,8 +71,7 @@ public interface UpdateQuery<T> {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* int rows = DB.update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
@@ -93,8 +90,7 @@ public interface UpdateQuery<T> {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* int rows = DB.update(Customer.class)
|
||||
* .setNull("notes")
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
@@ -114,8 +110,7 @@ public interface UpdateQuery<T> {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* int rows = DB.update(Customer.class)
|
||||
* .setRaw("status = coalesce(status, 'A')")
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
@@ -134,8 +129,7 @@ public interface UpdateQuery<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* int rows = DB.update(Customer.class)
|
||||
* .setRaw("status = coalesce(status, ?)", Customer.Status.ACTIVE)
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
@@ -154,9 +148,19 @@ public interface UpdateQuery<T> {
|
||||
*/
|
||||
UpdateQuery<T> setProfileLocation(ProfileLocation profileLocation);
|
||||
|
||||
/**
|
||||
* Set the label on the update query.
|
||||
*/
|
||||
UpdateQuery<T> setLabel(String label);
|
||||
|
||||
/**
|
||||
* Return the query expression list to add predicates to.
|
||||
*/
|
||||
ExpressionList<T> where();
|
||||
|
||||
/**
|
||||
* Execute the update returning the number of rows updated.
|
||||
*/
|
||||
int update();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.service.SpiFetchGroupQuery;
|
||||
import io.ebean.service.SpiFetchGroupService;
|
||||
import io.ebean.service.SpiProfileLocationFactory;
|
||||
import io.ebean.service.SpiRawSqlService;
|
||||
@@ -71,4 +72,11 @@ class XServiceProvider {
|
||||
static <T> FetchGroupBuilder<T> fetchGroupOf(Class<T> cls) {
|
||||
return fetchGroupService.of(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the FetchGroup Query for building fetch groups via query beans.
|
||||
*/
|
||||
static <T> SpiFetchGroupQuery<T> fetchGroupQueryFor(Class<T> cls) {
|
||||
return fetchGroupService.queryFor(cls);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ package io.ebean.bean;
|
||||
public interface BeanCollectionLoader {
|
||||
|
||||
/**
|
||||
* Return the name of the associated EbeanServer.
|
||||
* Return the name of the associated Database.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ package io.ebean.bean;
|
||||
public interface BeanLoader {
|
||||
|
||||
/**
|
||||
* Return the name of the associated EbeanServer.
|
||||
* Return the name of the associated Database.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* A call origin for query execution profiling to collect graph use (for query tuning).
|
||||
*/
|
||||
public interface CallOrigin {
|
||||
|
||||
/**
|
||||
* Return the top element. Typically the top stack element with class and line.
|
||||
*/
|
||||
String getTopElement();
|
||||
|
||||
/**
|
||||
* Return the full description of the call origin.
|
||||
*/
|
||||
String getFullDescription();
|
||||
|
||||
/**
|
||||
* Compute and return an origin key based on the query hash.
|
||||
*/
|
||||
String getOriginKey(int queryHash);
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package io.ebean.bean;
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static io.ebean.util.EncodeB64.enc;
|
||||
|
||||
/**
|
||||
* Represent the call stack (stack trace elements).
|
||||
* <p>
|
||||
@@ -17,15 +19,15 @@ import java.util.Arrays;
|
||||
* Note the call stack is trimmed to remove the common ebean internal elements.
|
||||
* </p>
|
||||
*/
|
||||
public final class CallStack implements Serializable {
|
||||
public final class CallStack implements Serializable, CallOrigin {
|
||||
|
||||
private static final long serialVersionUID = -8590644046907438579L;
|
||||
|
||||
private static final String NEWLINE = "\n";
|
||||
|
||||
private final String zeroHash;
|
||||
private final String pathHash;
|
||||
|
||||
private final StackTraceElement[] callStack;
|
||||
|
||||
private final int hc;
|
||||
|
||||
public CallStack(StackTraceElement[] callStack, int zeroHash, int pathHash) {
|
||||
@@ -37,12 +39,17 @@ public final class CallStack implements Serializable {
|
||||
|
||||
private int computeHashCode() {
|
||||
int hc = 0;
|
||||
for (StackTraceElement aCallStack : callStack) {
|
||||
hc = 92821 * hc + aCallStack.hashCode();
|
||||
for (StackTraceElement element : callStack) {
|
||||
hc = 92821 * hc + element.hashCode();
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return zeroHash + ":" + pathHash + ":" + callStack[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hc;
|
||||
@@ -63,73 +70,29 @@ public final class CallStack implements Serializable {
|
||||
/**
|
||||
* Return the first element of the call stack.
|
||||
*/
|
||||
public StackTraceElement getFirstStackTraceElement() {
|
||||
return callStack[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the call stack.
|
||||
*/
|
||||
public StackTraceElement[] getCallStack() {
|
||||
return callStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash for the first stack element.
|
||||
*/
|
||||
public String getZeroHash() {
|
||||
return zeroHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash for the stack elements (excluding first stack element).
|
||||
*/
|
||||
public String getPathHash() {
|
||||
return pathHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return zeroHash + ":" + pathHash + ":" + callStack[0];
|
||||
public String getTopElement() {
|
||||
return callStack[0].toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the call stack lines appended with the given newLine string.
|
||||
*/
|
||||
public String description(String newLine) {
|
||||
@Override
|
||||
public String getFullDescription() {
|
||||
StringBuilder sb = new StringBuilder(400);
|
||||
for (StackTraceElement aCallStack : callStack) {
|
||||
sb.append(aCallStack.toString()).append(newLine);
|
||||
for (int i = 0; i < callStack.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(NEWLINE);
|
||||
}
|
||||
sb.append(callStack[i].toString());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOriginKey(int queryHash) {
|
||||
return enc(queryHash) + "." + zeroHash + "." + pathHash;
|
||||
}
|
||||
|
||||
private static final int radix = 1 << 6;
|
||||
private static final int mask = radix - 1;
|
||||
|
||||
/**
|
||||
* Convert the integer to unsigned base 64.
|
||||
*/
|
||||
public static String enc(int i) {
|
||||
char[] buf = new char[32];
|
||||
int charPos = 32;
|
||||
do {
|
||||
buf[--charPos] = intToBase64[i & mask];
|
||||
i >>>= 6;
|
||||
} while (i != 0);
|
||||
|
||||
return new String(buf, charPos, (32 - charPos));
|
||||
}
|
||||
|
||||
private static final char intToBase64[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,12 +16,16 @@ public interface EntityBean extends Serializable {
|
||||
/**
|
||||
* Return all the property names in defined order.
|
||||
*/
|
||||
String[] _ebean_getPropertyNames();
|
||||
default String[] _ebean_getPropertyNames() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property name at the given position.
|
||||
*/
|
||||
String _ebean_getPropertyName(int pos);
|
||||
default String _ebean_getPropertyName(int pos) {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the enhancement marker value.
|
||||
@@ -30,28 +34,38 @@ public interface EntityBean extends Serializable {
|
||||
* entity classes are enhanced (specifically not just a super class).
|
||||
* </p>
|
||||
*/
|
||||
String _ebean_getMarker();
|
||||
default String _ebean_getMarker() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new entity bean instance.
|
||||
*/
|
||||
Object _ebean_newInstance();
|
||||
default Object _ebean_newInstance() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated method that sets the loaded state on all the embedded beans on
|
||||
* this entity bean by using EntityBeanIntercept.setEmbeddedLoaded(Object o);
|
||||
*/
|
||||
void _ebean_setEmbeddedLoaded();
|
||||
default void _ebean_setEmbeddedLoaded() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if any embedded beans are new or dirty.
|
||||
*/
|
||||
boolean _ebean_isEmbeddedNewOrDirty();
|
||||
default boolean _ebean_isEmbeddedNewOrDirty() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the intercept for this object.
|
||||
*/
|
||||
EntityBeanIntercept _ebean_getIntercept();
|
||||
default EntityBeanIntercept _ebean_getIntercept() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to _ebean_getIntercept() except it checks to see if the intercept
|
||||
@@ -66,7 +80,9 @@ public interface EntityBean extends Serializable {
|
||||
* frameworks that can't take into account our ebean fields.
|
||||
* </p>
|
||||
*/
|
||||
EntityBeanIntercept _ebean_intercept();
|
||||
default EntityBeanIntercept _ebean_intercept() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a field of an entity bean of this type.
|
||||
@@ -75,12 +91,16 @@ public interface EntityBean extends Serializable {
|
||||
* on entity beans. That means lazy loading and oldValues creation.
|
||||
* </p>
|
||||
*/
|
||||
void _ebean_setField(int fieldIndex, Object value);
|
||||
default void _ebean_setField(int fieldIndex, Object value) {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field value with interception.
|
||||
*/
|
||||
void _ebean_setFieldIntercept(int fieldIndex, Object value);
|
||||
default void _ebean_setFieldIntercept(int fieldIndex, Object value) {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of a field from an entity bean of this type.
|
||||
@@ -89,11 +109,15 @@ public interface EntityBean extends Serializable {
|
||||
* on entity beans. That means lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
Object _ebean_getField(int fieldIndex);
|
||||
default Object _ebean_getField(int fieldIndex) {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the field value with interception.
|
||||
*/
|
||||
Object _ebean_getFieldIntercept(int fieldIndex);
|
||||
default Object _ebean_getFieldIntercept(int fieldIndex) {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -95,11 +95,10 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
private final byte[] flags;
|
||||
|
||||
private boolean fullyLoadedBean;
|
||||
|
||||
private boolean loadedFromCache;
|
||||
private Object[] origValues;
|
||||
|
||||
private Exception[] loadErrors;
|
||||
private int lazyLoadProperty = -1;
|
||||
|
||||
private Object ownerId;
|
||||
private int sortOrder;
|
||||
|
||||
@@ -114,6 +113,14 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
this.flags = new byte[owner._ebean_getPropertyNames().length];
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL - Constructor only for use by serialization frameworks.
|
||||
*/
|
||||
public EntityBeanIntercept() {
|
||||
this.owner = null;
|
||||
this.flags = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the 'owning' entity bean.
|
||||
*/
|
||||
@@ -301,6 +308,22 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set true when the bean has been loaded from L2 bean cache.
|
||||
* The effect of this is that we should skip the cache if there
|
||||
* is subsequent lazy loading (bean cache partially populated).
|
||||
*/
|
||||
public void setLoadedFromCache(boolean loadedFromCache) {
|
||||
this.loadedFromCache = loadedFromCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this bean was loaded from L2 bean cache.
|
||||
*/
|
||||
public boolean isLoadedFromCache() {
|
||||
return loadedFromCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the bean should be treated as readOnly. If a setter method
|
||||
* is called when it is readOnly an Exception is thrown.
|
||||
@@ -770,7 +793,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
|
||||
public boolean[] getLoaded() {
|
||||
boolean[] ret= new boolean[flags.length];
|
||||
boolean[] ret = new boolean[flags.length];
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
ret[i] = (flags[i] & FLAG_LOADED_PROP) != 0;
|
||||
}
|
||||
@@ -829,7 +852,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
|
||||
if (lazyLoadFailure) {
|
||||
// failed when batch lazy loaded by another bean in the batch
|
||||
throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted");
|
||||
throw new EntityNotFoundException("(Lazy) loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted");
|
||||
}
|
||||
|
||||
if (lazyLoadProperty == -1) {
|
||||
@@ -1115,4 +1138,36 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public void setSortOrder(int sortOrder) {
|
||||
this.sortOrder = sortOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the load error that happened on this property.
|
||||
*/
|
||||
public void setLoadError(int propertyIndex, Exception t) {
|
||||
if (loadErrors == null) {
|
||||
loadErrors = new Exception[owner._ebean_getPropertyNames().length];
|
||||
}
|
||||
loadErrors[propertyIndex] = t;
|
||||
flags[propertyIndex] |= FLAG_LOADED_PROP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the loadErrors.
|
||||
*/
|
||||
public Map<String, Exception> getLoadErrors() {
|
||||
if (loadErrors == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Exception> ret = null;
|
||||
int len = getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
Exception loadError = loadErrors[i];
|
||||
if (loadError != null) {
|
||||
if (ret == null) {
|
||||
ret = new LinkedHashMap<>();
|
||||
}
|
||||
ret.put(getProperty(i), loadError);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* This exception is thrown, when the default implementation of EntityBean is not or not properly overwritten by enhancer.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*
|
||||
*/
|
||||
public class NotEnhancedException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Identifies a unique node of an object graph.
|
||||
@@ -85,8 +86,7 @@ public final class ObjectGraphNode implements Serializable {
|
||||
}
|
||||
|
||||
ObjectGraphNode e = (ObjectGraphNode) obj;
|
||||
//noinspection StringEquality
|
||||
return ((e.path == path) || (e.path != null && e.path.equals(path)))
|
||||
return (Objects.equals(e.path, path))
|
||||
&& e.originQueryPoint.equals(originQueryPoint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public final class ObjectGraphOrigin implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 410937765287968708L;
|
||||
|
||||
private final CallStack callStack;
|
||||
private final CallOrigin callOrigin;
|
||||
|
||||
private final String beanType;
|
||||
|
||||
@@ -24,11 +24,11 @@ public final class ObjectGraphOrigin implements Serializable {
|
||||
|
||||
private final String key;
|
||||
|
||||
public ObjectGraphOrigin(int queryHash, CallStack callStack, String beanType) {
|
||||
this.callStack = callStack;
|
||||
public ObjectGraphOrigin(int queryHash, CallOrigin callOrigin, String beanType) {
|
||||
this.callOrigin = callOrigin;
|
||||
this.beanType = beanType;
|
||||
this.queryHash = queryHash;
|
||||
this.key = callStack.getOriginKey(queryHash);
|
||||
this.key = callOrigin.getOriginKey(queryHash);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,22 +49,22 @@ public final class ObjectGraphOrigin implements Serializable {
|
||||
/**
|
||||
* The call stack involved.
|
||||
*/
|
||||
public CallStack getCallStack() {
|
||||
return callStack;
|
||||
public CallOrigin getCallOrigin() {
|
||||
return callOrigin;
|
||||
}
|
||||
|
||||
public String getFirstStackElement() {
|
||||
return callStack.getFirstStackTraceElement().toString();
|
||||
public String getTopElement() {
|
||||
return callOrigin.getTopElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "key[" + key + "] type[" + beanType + "] " + callStack.getFirstStackTraceElement() + " ";
|
||||
return "key[" + key + "] type[" + beanType + "] " + callOrigin.getTopElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc = 92821 * callStack.hashCode();
|
||||
int hc = 92821 * callOrigin.hashCode();
|
||||
hc = 92821 * hc + beanType.hashCode();
|
||||
hc = 92821 * hc + queryHash;
|
||||
return hc;
|
||||
@@ -82,6 +82,6 @@ public final class ObjectGraphOrigin implements Serializable {
|
||||
ObjectGraphOrigin e = (ObjectGraphOrigin) obj;
|
||||
return e.queryHash == queryHash
|
||||
&& e.beanType.equals(beanType)
|
||||
&& e.callStack.equals(callStack);
|
||||
&& e.callOrigin.equals(callOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -79,4 +81,11 @@ public interface ServerCache {
|
||||
* @param reset if true the statistics are reset.
|
||||
*/
|
||||
ServerCacheStatistics getStatistics(boolean reset);
|
||||
|
||||
/**
|
||||
* Visit the metrics for the cache.
|
||||
*/
|
||||
default void visit(MetricVisitor visitor) {
|
||||
// do nothing by default
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -9,13 +9,15 @@ public class ServerCacheConfig {
|
||||
|
||||
private final ServerCacheType type;
|
||||
private final String cacheKey;
|
||||
private final String shortName;
|
||||
private final ServerCacheOptions cacheOptions;
|
||||
private final CurrentTenantProvider tenantProvider;
|
||||
private final QueryCacheEntryValidate queryCacheEntryValidate;
|
||||
|
||||
public ServerCacheConfig(ServerCacheType type, String cacheKey, ServerCacheOptions cacheOptions, CurrentTenantProvider tenantProvider, QueryCacheEntryValidate queryCacheEntryValidate) {
|
||||
public ServerCacheConfig(ServerCacheType type, String cacheKey, String shortName, ServerCacheOptions cacheOptions, CurrentTenantProvider tenantProvider, QueryCacheEntryValidate queryCacheEntryValidate) {
|
||||
this.type = type;
|
||||
this.cacheKey = cacheKey;
|
||||
this.shortName = shortName;
|
||||
this.cacheOptions = cacheOptions;
|
||||
this.tenantProvider = tenantProvider;
|
||||
this.queryCacheEntryValidate = queryCacheEntryValidate;
|
||||
@@ -35,6 +37,13 @@ public class ServerCacheConfig {
|
||||
return cacheKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the short name for the cache.
|
||||
*/
|
||||
public String getShortName() {
|
||||
return shortName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tuning options.
|
||||
*/
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
|
||||
/**
|
||||
* Defines method for constructing caches for beans and queries.
|
||||
*/
|
||||
public interface ServerCacheFactory {
|
||||
|
||||
/**
|
||||
* Visit the metrics for the cache.
|
||||
*/
|
||||
default void visit(MetricVisitor visitor) {
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the cache for the given type with options.
|
||||
*/
|
||||
|
||||
+36
-2
@@ -1,10 +1,19 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The cache service for server side caching of beans and query results.
|
||||
*/
|
||||
public interface ServerCacheManager {
|
||||
|
||||
/**
|
||||
* Visit the metrics for all the server caches.
|
||||
*/
|
||||
void visitMetrics(MetricVisitor visitor);
|
||||
|
||||
/**
|
||||
* Return true if the L2 caching is local.
|
||||
* <p>
|
||||
@@ -14,6 +23,31 @@ public interface ServerCacheManager {
|
||||
*/
|
||||
boolean isLocalL2Caching();
|
||||
|
||||
/**
|
||||
* Return all the cache regions.
|
||||
*/
|
||||
List<ServerCacheRegion> allRegions();
|
||||
|
||||
/**
|
||||
* Set the regions that are enabled.
|
||||
* <p>
|
||||
* Typically this is set on startup and at runtime (via dynamic configuration).
|
||||
* </p>
|
||||
*
|
||||
* @param regions A region name or comma delimited list of region names.
|
||||
*/
|
||||
void setEnabledRegions(String regions);
|
||||
|
||||
/**
|
||||
* Enable or disable all the cache regions.
|
||||
*/
|
||||
void setAllRegionsEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Return the cache region by name. Typically to enable or disable the region.
|
||||
*/
|
||||
ServerCacheRegion getRegion(String name);
|
||||
|
||||
/**
|
||||
* Return the cache for mapping natural keys to id values.
|
||||
*/
|
||||
@@ -46,7 +80,7 @@ public interface ServerCacheManager {
|
||||
|
||||
/**
|
||||
* Clear all the local caches.
|
||||
*
|
||||
* <p>
|
||||
* This is used when the L2 Cache is based on clustered near-caches (Like Ebean-K8s-L2Cache).
|
||||
* It is not used when the L2 cache is a distributed cache such as HazelCast or Ignite etc.
|
||||
*/
|
||||
@@ -54,7 +88,7 @@ public interface ServerCacheManager {
|
||||
|
||||
/**
|
||||
* Clear the local caches for this bean type.
|
||||
*
|
||||
* <p>
|
||||
* This is used when the L2 Cache is based on clustered near-caches (Like Ebean-K8s-L2Cache).
|
||||
* It is not used when the L2 cache is a distributed cache such as HazelCast or Ignite etc.
|
||||
*/
|
||||
|
||||
@@ -10,17 +10,15 @@ import java.util.Set;
|
||||
*/
|
||||
public class ServerCacheNotification {
|
||||
|
||||
private final long modifyTimestamp;
|
||||
|
||||
private final Set<String> dependentTables;
|
||||
|
||||
public ServerCacheNotification(long modifyTimestamp, Set<String> dependentTables) {
|
||||
this.modifyTimestamp = modifyTimestamp;
|
||||
public ServerCacheNotification(Set<String> dependentTables) {
|
||||
this.dependentTables = dependentTables;
|
||||
}
|
||||
|
||||
public long getModifyTimestamp() {
|
||||
return modifyTimestamp;
|
||||
@Override
|
||||
public String toString() {
|
||||
return "tables:" + dependentTables;
|
||||
}
|
||||
|
||||
public Set<String> getDependentTables() {
|
||||
|
||||
@@ -12,6 +12,7 @@ public class ServerCacheOptions {
|
||||
private int maxIdleSecs;
|
||||
private int maxSecsToLive;
|
||||
private int trimFrequency;
|
||||
private boolean nearCache;
|
||||
|
||||
/**
|
||||
* Construct with no set options.
|
||||
@@ -40,6 +41,14 @@ public class ServerCacheOptions {
|
||||
this.trimFrequency = cacheTuning.trimFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with nearCache option.
|
||||
*/
|
||||
public ServerCacheOptions(boolean nearCache, CacheBeanTuning tuning) {
|
||||
this(tuning);
|
||||
this.nearCache = nearCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any settings from the default settings that have not already been
|
||||
* specifically set.
|
||||
@@ -70,9 +79,33 @@ public class ServerCacheOptions {
|
||||
copy.maxIdleSecs = maxIdleSecs;
|
||||
copy.maxSecsToLive = maxSecsToLive;
|
||||
copy.trimFrequency = trimFrequency;
|
||||
copy.nearCache = this.nearCache;
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this object with nearCache option.
|
||||
*/
|
||||
public ServerCacheOptions copy(boolean nearCache) {
|
||||
ServerCacheOptions copy = copy();
|
||||
copy.nearCache = nearCache;
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if nearCache was explicitly turned on.
|
||||
*/
|
||||
public boolean isNearCache() {
|
||||
return nearCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn on nearCache option.
|
||||
*/
|
||||
public void setNearCache(boolean nearCache) {
|
||||
this.nearCache = nearCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum cache size.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
/**
|
||||
* Cache region can be enabled independently.
|
||||
*/
|
||||
public interface ServerCacheRegion {
|
||||
|
||||
/**
|
||||
* Return the region name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return true if the cache region is enabled.
|
||||
*/
|
||||
boolean isEnabled();
|
||||
|
||||
/**
|
||||
* Set to true to enable the cache region.
|
||||
*/
|
||||
void setEnabled(boolean enabled);
|
||||
|
||||
}
|
||||
+12
-96
@@ -21,23 +21,13 @@ public class ServerCacheStatistics {
|
||||
|
||||
protected long missCount;
|
||||
|
||||
protected long insertCount;
|
||||
|
||||
protected long updateCount;
|
||||
protected long putCount;
|
||||
|
||||
protected long removeCount;
|
||||
|
||||
protected long clearCount;
|
||||
|
||||
protected long evictionRunCount;
|
||||
|
||||
protected long evictionRunMicros;
|
||||
|
||||
protected long evictByIdle;
|
||||
|
||||
protected long evictByTTL;
|
||||
|
||||
protected long evictByLRU;
|
||||
protected long evictCount;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -49,15 +39,10 @@ public class ServerCacheStatistics {
|
||||
sb.append(" hitRatio:").append(getHitRatio());
|
||||
sb.append(" hit:").append(hitCount);
|
||||
sb.append(" miss:").append(missCount);
|
||||
sb.append(" insert:").append(insertCount);
|
||||
sb.append(" update:").append(updateCount);
|
||||
sb.append(" put:").append(putCount);
|
||||
sb.append(" remove:").append(removeCount);
|
||||
sb.append(" clear:").append(clearCount);
|
||||
sb.append(" evictByIdle:").append(evictByIdle);
|
||||
sb.append(" evictByTTL:").append(evictByTTL);
|
||||
sb.append(" evictByLRU:").append(evictByLRU);
|
||||
sb.append(" evictionRunCount:").append(evictionRunCount);
|
||||
sb.append(" evictionRunMicros:").append(evictionRunMicros);
|
||||
sb.append(" evict:").append(evictCount);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -153,29 +138,15 @@ public class ServerCacheStatistics {
|
||||
/**
|
||||
* Set the put insert count.
|
||||
*/
|
||||
public void setInsertCount(long insertCount) {
|
||||
this.insertCount = insertCount;
|
||||
public void setPutCount(long putCount) {
|
||||
this.putCount = putCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the put insert count.
|
||||
*/
|
||||
public long getInsertCount() {
|
||||
return insertCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the put update count.
|
||||
*/
|
||||
public void setUpdateCount(long updateCount) {
|
||||
this.updateCount = updateCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the put update count.
|
||||
*/
|
||||
public long getUpdateCount() {
|
||||
return updateCount;
|
||||
public long getPutCount() {
|
||||
return putCount;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,73 +177,18 @@ public class ServerCacheStatistics {
|
||||
return clearCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the eviction run count.
|
||||
*/
|
||||
public void setEvictionRunCount(long evictCount) {
|
||||
this.evictionRunCount = evictCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the eviction run count.
|
||||
*/
|
||||
public long getEvictionRunCount() {
|
||||
return evictionRunCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the eviction run time in micros.
|
||||
*/
|
||||
public void setEvictionRunMicros(long evictionRunMicros) {
|
||||
this.evictionRunMicros = evictionRunMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the eviction run time in micros.
|
||||
*/
|
||||
public long getEvictionRunMicros() {
|
||||
return evictionRunMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count of entries evicted due to idle time.
|
||||
*/
|
||||
public void setEvictByIdle(long evictByIdle) {
|
||||
this.evictByIdle = evictByIdle;
|
||||
public void setEvictCount(long evictCount) {
|
||||
this.evictCount = evictCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of entries evicted due to idle time.
|
||||
*/
|
||||
public long getEvictByIdle() {
|
||||
return evictByIdle;
|
||||
public long getEvictCount() {
|
||||
return evictCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count of entries evicted due to time to live.
|
||||
*/
|
||||
public void setEvictByTTL(long evictByTTL) {
|
||||
this.evictByTTL = evictByTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of entries evicted due to time to live.
|
||||
*/
|
||||
public long getEvictByTTL() {
|
||||
return evictByTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count of entries evicted due to time least recently used.
|
||||
*/
|
||||
public void setEvictByLRU(long evictByLRU) {
|
||||
this.evictByLRU = evictByLRU;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of entries evicted due to time least recently used.
|
||||
*/
|
||||
public long getEvictByLRU() {
|
||||
return evictByLRU;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public enum ServerCacheType {
|
||||
*/
|
||||
QUERY("_Q");
|
||||
|
||||
private String code;
|
||||
private final String code;
|
||||
|
||||
ServerCacheType(String code) {
|
||||
this.code = code;
|
||||
|
||||
@@ -20,7 +20,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
protected boolean disableLazyLoad;
|
||||
|
||||
/**
|
||||
* The EbeanServer this is associated with. (used for lazy fetch).
|
||||
* The Database this is associated with. (used for lazy fetch).
|
||||
*/
|
||||
protected transient BeanCollectionLoader loader;
|
||||
|
||||
@@ -219,7 +219,6 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
/**
|
||||
* Copies all relevant properties for a clone. See {@link #getShallowCopy()}
|
||||
* @param other
|
||||
*/
|
||||
protected void setFromOriginal(AbstractBeanCollection<E> other) {
|
||||
this.disableLazyLoad = other.disableLazyLoad;
|
||||
|
||||
@@ -123,7 +123,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
private void initClear() {
|
||||
synchronized (this) {
|
||||
if (map == null) {
|
||||
if (modifyListening) {
|
||||
if (!disableLazyLoad && modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
} else {
|
||||
map = new LinkedHashMap<>();
|
||||
@@ -135,7 +135,11 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
private void init() {
|
||||
synchronized (this) {
|
||||
if (map == null) {
|
||||
lazyLoadCollection(false);
|
||||
if (disableLazyLoad) {
|
||||
map = new LinkedHashMap<>();
|
||||
} else {
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,7 +237,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public Set<Entry<K, E>> entrySet() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
|
||||
@@ -116,7 +116,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
private void initClear() {
|
||||
synchronized (this) {
|
||||
if (set == null) {
|
||||
if (modifyListening) {
|
||||
if (!disableLazyLoad && modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
} else {
|
||||
set = new LinkedHashSet<>();
|
||||
@@ -128,7 +128,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
private void init() {
|
||||
synchronized (this) {
|
||||
if (set == null) {
|
||||
lazyLoadCollection(true);
|
||||
if (disableLazyLoad) {
|
||||
set = new LinkedHashSet<>();
|
||||
} else {
|
||||
lazyLoadCollection(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -377,7 +381,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
throw new IllegalStateException("This collection is in ReadOnly mode");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BeanCollection<E> getShallowCopy() {
|
||||
BeanSet<E> copy = new BeanSet<>(new LinkedHashSet<>(set));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.config;
|
||||
|
||||
/**
|
||||
* Used to provide some automatic configuration early in the creation of an EbeanServer.
|
||||
* Used to provide some automatic configuration early in the creation of a Database.
|
||||
*/
|
||||
public interface AutoConfigure {
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package io.ebean.config;
|
||||
|
||||
/**
|
||||
* Defines the AutoTune behaviour for a EbeanServer.
|
||||
* Defines the AutoTune behaviour for a Database.
|
||||
*/
|
||||
public class AutoTuneConfig {
|
||||
|
||||
private AutoTuneMode mode = AutoTuneMode.DEFAULT_ON;
|
||||
private AutoTuneMode mode = AutoTuneMode.DEFAULT_OFF;
|
||||
|
||||
private String queryTuningFile = "ebean-autotune.xml";
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.ebean.config;
|
||||
|
||||
/**
|
||||
* Throw when an processing an entity bean that is not bytecode enhanced.
|
||||
*
|
||||
* Refer: https://ebean.io/docs/trouble-shooting#not-enhanced
|
||||
*/
|
||||
public class BeanNotEnhancedException extends IllegalStateException {
|
||||
|
||||
private static final long serialVersionUID = 3008101919425876799L;
|
||||
|
||||
public BeanNotEnhancedException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.ebean.config;
|
||||
|
||||
/**
|
||||
* Throw when an processing thinks a bean is not registered.
|
||||
*
|
||||
* Refer: https://ebean.io/docs/trouble-shooting#not-registered
|
||||
*/
|
||||
public class BeanNotRegisteredException extends IllegalStateException {
|
||||
|
||||
private static final long serialVersionUID = -1411298126011136552L;
|
||||
|
||||
public BeanNotRegisteredException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package io.ebean.config;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Configuration for the container that holds the EbeanServer instances.
|
||||
* Configuration for the container that holds the Database instances.
|
||||
* <p>
|
||||
* Provides configuration for cluster communication (if clustering is used). The cluster communication is
|
||||
* used to invalidate appropriate parts of the L2 cache across the cluster.
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import io.ebean.DatabaseFactory;
|
||||
|
||||
/**
|
||||
* The configuration used for creating a Database.
|
||||
* <p>
|
||||
* Used to programmatically construct an Database and optionally register it
|
||||
* with the DB singleton.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you just use DB thout this programmatic configuration Ebean will read
|
||||
* the application.properties file and take the configuration from there. This usually
|
||||
* includes searching the class path and automatically registering any entity
|
||||
* classes and listeners etc.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* DatabaseConfig config = new DatabaseConfig();
|
||||
*
|
||||
* // read the ebean.properties and load
|
||||
* // those settings into this serverConfig object
|
||||
* config.loadFromProperties();
|
||||
*
|
||||
* // explicitly register the entity beans to avoid classpath scanning
|
||||
* config.addClass(Customer.class);
|
||||
* config.addClass(User.class);
|
||||
*
|
||||
* Database db = DatabaseFactory.create(config);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Note that ServerConfigProvider provides a standard Java ServiceLoader mechanism that can
|
||||
* be used to apply configuration to the DatabaseConfig.
|
||||
* </p>
|
||||
*
|
||||
* @author emcgreal
|
||||
* @author rbygrave
|
||||
* @see DatabaseFactory
|
||||
*/
|
||||
public class DatabaseConfig extends ServerConfig {
|
||||
|
||||
}
|
||||
@@ -5,7 +5,6 @@ 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;
|
||||
|
||||
@@ -28,39 +27,13 @@ public class DbMigrationConfig {
|
||||
*/
|
||||
protected Platform platform;
|
||||
|
||||
/**
|
||||
* Set to true if the DB migration should be generated on server start.
|
||||
*/
|
||||
protected boolean generate;
|
||||
|
||||
/**
|
||||
* The migration version name (typically FlywayDb compatible).
|
||||
* <p>
|
||||
* Example: 1.1.1_2
|
||||
* <p>
|
||||
* The version is expected to be the combination of the current pom version plus
|
||||
* a 'feature' id. The combined version must be unique and ordered to work with
|
||||
* FlywayDb so each developer sets a unique version so that the migration script
|
||||
* generated is unique (typically just prior to being submitted as a merge request).
|
||||
*/
|
||||
protected String version;
|
||||
|
||||
/**
|
||||
* Description text that can be appended to the version to become the ddl script file name.
|
||||
* <p>
|
||||
* So if the name is "a foo table" then the ddl script file could be:
|
||||
* "1.1.1_2__a-foo-table.sql"
|
||||
* <p>
|
||||
* When the DB migration relates to a git feature (merge request) then this description text
|
||||
* is a short description of the feature.
|
||||
*/
|
||||
protected String name;
|
||||
|
||||
/**
|
||||
* Resource path for the migration xml and sql.
|
||||
*/
|
||||
protected String migrationPath = "dbmigration";
|
||||
|
||||
protected String migrationInitPath = "dbinit";
|
||||
|
||||
/**
|
||||
* Subdirectory the model xml files go into.
|
||||
*/
|
||||
@@ -75,13 +48,6 @@ public class DbMigrationConfig {
|
||||
|
||||
protected String modelSuffix = ".model.xml";
|
||||
|
||||
protected boolean includeGeneratedFileComment;
|
||||
|
||||
/**
|
||||
* The version of a pending drop that should be generated as the next migration.
|
||||
*/
|
||||
protected String generatePendingDrop;
|
||||
|
||||
/**
|
||||
* For running migration the DB table that holds migration execution status.
|
||||
*/
|
||||
@@ -153,6 +119,15 @@ public class DbMigrationConfig {
|
||||
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.
|
||||
*/
|
||||
@@ -165,7 +140,7 @@ public class DbMigrationConfig {
|
||||
* <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 EbeanServer applications in the single classpath.
|
||||
* in the case there are multiple Database applications in the single classpath.
|
||||
* </p>
|
||||
*/
|
||||
public void setMigrationPath(String migrationPath) {
|
||||
@@ -228,52 +203,6 @@ public class DbMigrationConfig {
|
||||
this.applyPrefix = applyPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the generated file comment should be included.
|
||||
*/
|
||||
public boolean isIncludeGeneratedFileComment() {
|
||||
return includeGeneratedFileComment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the generated file comment should be included.
|
||||
*/
|
||||
public void setIncludeGeneratedFileComment(boolean includeGeneratedFileComment) {
|
||||
this.includeGeneratedFileComment = includeGeneratedFileComment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the migration version (or "next") to generate pending drops for.
|
||||
*/
|
||||
public String getGeneratePendingDrop() {
|
||||
return generatePendingDrop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the migration version (or "next") to generate pending drops for.
|
||||
*/
|
||||
public void setGeneratePendingDrop(String generatePendingDrop) {
|
||||
this.generatePendingDrop = generatePendingDrop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the migration version.
|
||||
* <p>
|
||||
* Note that version set via System property or environment variable <code>ddl.migration.version</code> takes precedence.
|
||||
*/
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the migration name.
|
||||
* <p>
|
||||
* Note that name set via System property or environment variable <code>ddl.migration.name</code> takes precedence.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the table name that holds the migration run details
|
||||
* (used by DB Migration runner only).
|
||||
@@ -500,18 +429,13 @@ public class DbMigrationConfig {
|
||||
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);
|
||||
includeGeneratedFileComment = properties.getBoolean("migration.includeGeneratedFileComment", includeGeneratedFileComment);
|
||||
generatePendingDrop = properties.get("migration.generatePendingDrop", generatePendingDrop);
|
||||
|
||||
platform = properties.getEnum(Platform.class, "migration.platform", platform);
|
||||
|
||||
generate = properties.getBoolean("migration.generate", generate);
|
||||
version = properties.get("migration.version", version);
|
||||
name = properties.get("migration.name", name);
|
||||
patchInsertOn = properties.get("migration.patchInsertOn", patchInsertOn);
|
||||
patchResetChecksumOn = properties.get("migration.patchResetChecksumOn", patchResetChecksumOn);
|
||||
|
||||
@@ -532,44 +456,6 @@ public class DbMigrationConfig {
|
||||
ddlHeader = properties.get("ddl.header", ddlHeader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the migration version (typically FlywayDb compatible).
|
||||
* <p>
|
||||
* Example: 1.1.1_2
|
||||
* <p>
|
||||
* The version is expected to be the combination of the current pom version plus
|
||||
* a 'feature' id. The combined version must be unique and ordered to work with
|
||||
* FlywayDb so each developer sets a unique version so that the migration script
|
||||
* generated is unique (typically just prior to being submitted as a merge request).
|
||||
*/
|
||||
public String getVersion() {
|
||||
String envVersion = readEnvironment("ddl.migration.version");
|
||||
if (!isEmpty(envVersion)) {
|
||||
return envVersion.trim();
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the migration name which is short description text that can be appended to
|
||||
* the migration version to become the ddl script file name.
|
||||
* <p>
|
||||
* So if the name is "a foo table" then the ddl script file could be:
|
||||
* "1.1.1_2__a-foo-table.sql"
|
||||
* </p>
|
||||
* <p>
|
||||
* When the DB migration relates to a git feature (merge request) then this description text
|
||||
* is a short description of the feature.
|
||||
* </p>
|
||||
*/
|
||||
public String getName() {
|
||||
String envName = readEnvironment("ddl.migration.name");
|
||||
if (!isEmpty(envName)) {
|
||||
return envName.trim();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the system or environment property.
|
||||
*/
|
||||
@@ -597,6 +483,7 @@ public class DbMigrationConfig {
|
||||
runnerConfig.setMetaTable(metaTable);
|
||||
runnerConfig.setApplySuffix(applySuffix);
|
||||
runnerConfig.setMigrationPath(migrationPath);
|
||||
runnerConfig.setMigrationInitPath(migrationInitPath);
|
||||
runnerConfig.setRunPlaceholderMap(runPlaceholderMap);
|
||||
runnerConfig.setRunPlaceholders(runPlaceholders);
|
||||
runnerConfig.setDbUsername(getDbUsername());
|
||||
|
||||
@@ -5,6 +5,22 @@ package io.ebean.config;
|
||||
*/
|
||||
public abstract class JsonConfig {
|
||||
|
||||
/**
|
||||
* Defined the format used for Date types.
|
||||
*/
|
||||
public enum Date {
|
||||
|
||||
/**
|
||||
* Format as epoch millis.
|
||||
*/
|
||||
MILLIS,
|
||||
|
||||
/**
|
||||
* Format as ISO-8601 date format.
|
||||
*/
|
||||
ISO8601
|
||||
}
|
||||
|
||||
/**
|
||||
* Defined the format used for DateTime types.
|
||||
*/
|
||||
|
||||
@@ -47,6 +47,13 @@ public class PlatformConfig {
|
||||
*/
|
||||
private DbUuid dbUuid = DbUuid.AUTO_VARCHAR;
|
||||
|
||||
/**
|
||||
* Set to true to force InetAddress to map to Varchar (for Postgres rather than INET)
|
||||
*/
|
||||
private boolean databaseInetAddressVarchar;
|
||||
|
||||
private boolean caseSensitiveCollation = true;
|
||||
|
||||
/**
|
||||
* Modify the default mapping of standard types such as default precision for DECIMAL etc.
|
||||
*/
|
||||
@@ -69,6 +76,10 @@ public class PlatformConfig {
|
||||
this.idType = platformConfig.idType;
|
||||
this.geometrySRID = platformConfig.geometrySRID;
|
||||
this.dbUuid = platformConfig.dbUuid;
|
||||
this.caseSensitiveCollation = platformConfig.caseSensitiveCollation;
|
||||
this.allQuotedIdentifiers = platformConfig.allQuotedIdentifiers;
|
||||
this.databaseInetAddressVarchar = platformConfig.databaseInetAddressVarchar;
|
||||
this.customDbTypeMappings = platformConfig.customDbTypeMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,6 +96,20 @@ public class PlatformConfig {
|
||||
this.allQuotedIdentifiers = allQuotedIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the collation is case sensitive.
|
||||
*/
|
||||
public boolean isCaseSensitiveCollation() {
|
||||
return caseSensitiveCollation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to false to indicate that the collation is case insensitive.
|
||||
*/
|
||||
public void setCaseSensitiveCollation(boolean caseSensitiveCollation) {
|
||||
this.caseSensitiveCollation = caseSensitiveCollation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a value used to represent TRUE in the database.
|
||||
* <p>
|
||||
@@ -181,6 +206,20 @@ public class PlatformConfig {
|
||||
this.idType = idType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if InetAddress should map to varchar column (rather than Postgres INET).
|
||||
*/
|
||||
public boolean isDatabaseInetAddressVarchar() {
|
||||
return databaseInetAddressVarchar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to force InetAddress to map to varchar column.
|
||||
*/
|
||||
public void setDatabaseInetAddressVarchar(boolean databaseInetAddressVarchar) {
|
||||
this.databaseInetAddressVarchar = databaseInetAddressVarchar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom type mapping.
|
||||
* <p>
|
||||
@@ -235,6 +274,8 @@ public class PlatformConfig {
|
||||
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
|
||||
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
|
||||
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
|
||||
databaseInetAddressVarchar = p.getBoolean("databaseInetAddressVarchar", databaseInetAddressVarchar);
|
||||
caseSensitiveCollation = p.getBoolean("caseSensitiveCollation", caseSensitiveCollation);
|
||||
|
||||
DbUuid dbUuid = p.getEnum(DbUuid.class, "dbuuid", null);
|
||||
if (dbUuid != null) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import io.ebean.EbeanServerFactory;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.Transaction;
|
||||
@@ -14,6 +14,7 @@ import io.ebean.config.dbplatform.DbEncrypt;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.properties.PropertiesLoader;
|
||||
import io.ebean.datasource.DataSourceConfig;
|
||||
import io.ebean.event.BeanFindController;
|
||||
import io.ebean.event.BeanPersistController;
|
||||
import io.ebean.event.BeanPersistListener;
|
||||
@@ -30,8 +31,8 @@ import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.meta.MetaInfoManager;
|
||||
import io.ebean.migration.MigrationRunner;
|
||||
import io.ebean.util.StringHelper;
|
||||
import org.avaje.datasource.DataSourceConfig;
|
||||
|
||||
import javax.persistence.EnumType;
|
||||
import javax.sql.DataSource;
|
||||
import java.time.Clock;
|
||||
import java.util.ArrayList;
|
||||
@@ -44,30 +45,30 @@ import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* The configuration used for creating a EbeanServer.
|
||||
* The configuration used for creating a Database.
|
||||
* <p>
|
||||
* Used to programmatically construct an EbeanServer and optionally register it
|
||||
* with the Ebean singleton.
|
||||
* Used to programmatically construct a Database and optionally register it
|
||||
* with the DB singleton.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you just use Ebean without this programmatic configuration Ebean will read
|
||||
* the ebean.properties file and take the configuration from there. This usually
|
||||
* If you just use DB without this programmatic configuration DB will read
|
||||
* the application.properties file and take the configuration from there. This usually
|
||||
* includes searching the class path and automatically registering any entity
|
||||
* classes and listeners etc.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* ServerConfig c = new ServerConfig();
|
||||
* ServerConfig config = new ServerConfig();
|
||||
*
|
||||
* // read the ebean.properties and load
|
||||
* // those settings into this serverConfig object
|
||||
* c.loadFromProperties();
|
||||
* config.loadFromProperties();
|
||||
*
|
||||
* // explicitly register the entity beans to avoid classpath scanning
|
||||
* c.addClass(Customer.class);
|
||||
* c.addClass(User.class);
|
||||
* config.addClass(Customer.class);
|
||||
* config.addClass(User.class);
|
||||
*
|
||||
* EbeanServer server = EbeanServerFactory.create(c);
|
||||
* Database database = DatabaseFactory.create(config);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
@@ -78,12 +79,12 @@ import java.util.ServiceLoader;
|
||||
*
|
||||
* @author emcgreal
|
||||
* @author rbygrave
|
||||
* @see EbeanServerFactory
|
||||
* @see DatabaseFactory
|
||||
*/
|
||||
public class ServerConfig {
|
||||
|
||||
/**
|
||||
* The EbeanServer name.
|
||||
* The Database name.
|
||||
*/
|
||||
private String name = "db";
|
||||
|
||||
@@ -106,12 +107,12 @@ public class ServerConfig {
|
||||
private String resourceDirectory;
|
||||
|
||||
/**
|
||||
* Set to true to register this EbeanServer with the Ebean singleton.
|
||||
* Set to true to register this Database with the DB singleton.
|
||||
*/
|
||||
private boolean register = true;
|
||||
|
||||
/**
|
||||
* Set to true if this is the default/primary server.
|
||||
* Set to true if this is the default/primary database.
|
||||
*/
|
||||
private boolean defaultServer = true;
|
||||
|
||||
@@ -150,7 +151,7 @@ public class ServerConfig {
|
||||
private DocStoreConfig docStoreConfig = new DocStoreConfig();
|
||||
|
||||
/**
|
||||
* Set to true when the EbeanServer only uses Document store.
|
||||
* Set to true when the Database only uses Document store.
|
||||
*/
|
||||
private boolean docStoreOnly;
|
||||
|
||||
@@ -168,7 +169,12 @@ public class ServerConfig {
|
||||
/**
|
||||
* The JSON format used for DateTime types. Default to millis.
|
||||
*/
|
||||
private JsonConfig.DateTime jsonDateTime = JsonConfig.DateTime.MILLIS;
|
||||
private JsonConfig.DateTime jsonDateTime = JsonConfig.DateTime.ISO8601;
|
||||
|
||||
/**
|
||||
* The JSON format used for Date types. Default to millis.
|
||||
*/
|
||||
private JsonConfig.Date jsonDate = JsonConfig.Date.ISO8601;
|
||||
|
||||
/**
|
||||
* For writing JSON specify if null values or empty collections should be exluded.
|
||||
@@ -229,6 +235,10 @@ public class ServerConfig {
|
||||
|
||||
private int persistBatchSize = 20;
|
||||
|
||||
private EnumType defaultEnumType = EnumType.ORDINAL;
|
||||
|
||||
private boolean disableLazyLoading;
|
||||
|
||||
/**
|
||||
* The default batch size for lazy loading
|
||||
*/
|
||||
@@ -250,6 +260,8 @@ public class ServerConfig {
|
||||
|
||||
private boolean ddlRun;
|
||||
|
||||
private boolean ddlExtra = true;
|
||||
|
||||
private boolean ddlCreateOnly;
|
||||
|
||||
private String ddlInitSql;
|
||||
@@ -346,7 +358,7 @@ public class ServerConfig {
|
||||
/**
|
||||
* Behaviour of updates in JDBC batch to by default include all properties.
|
||||
*/
|
||||
private boolean updateAllPropertiesInBatch = true;
|
||||
private boolean updateAllPropertiesInBatch;
|
||||
|
||||
/**
|
||||
* Default behaviour for updates when cascade save on a O2M or M2M to delete any missing children.
|
||||
@@ -364,9 +376,10 @@ public class ServerConfig {
|
||||
private UuidVersion uuidVersion = UuidVersion.VERSION4;
|
||||
|
||||
/**
|
||||
* The UUID state file (for Version 1 UUIDs).
|
||||
* The UUID state file (for Version 1 UUIDs). By default, the file is created in
|
||||
* ${HOME}/.ebean/${servername}-uuid.state
|
||||
*/
|
||||
private String uuidStateFile = "ebean-uuid.state";
|
||||
private String uuidStateFile;
|
||||
|
||||
/**
|
||||
* The clock used for setting the timestamps (e.g. @UpdatedTimestamp) on objects.
|
||||
@@ -471,6 +484,7 @@ public class ServerConfig {
|
||||
*/
|
||||
private boolean disableL2Cache;
|
||||
|
||||
private String enabledL2Regions;
|
||||
|
||||
/**
|
||||
* Should the javax.validation.constraints.NotNull enforce a notNull column in DB.
|
||||
@@ -484,6 +498,11 @@ public class ServerConfig {
|
||||
*/
|
||||
private boolean notifyL2CacheInForeground;
|
||||
|
||||
/**
|
||||
* Set to true to support query plan capture.
|
||||
*/
|
||||
private boolean collectQueryPlans;
|
||||
|
||||
/**
|
||||
* The time in millis used to determine when a query is alerted for being slow.
|
||||
*/
|
||||
@@ -499,7 +518,7 @@ public class ServerConfig {
|
||||
/**
|
||||
* Controls the default order by id setting of queries. See {@link Query#orderById(boolean)}
|
||||
*/
|
||||
private boolean defaultOrderById = false;
|
||||
private boolean defaultOrderById;
|
||||
|
||||
/**
|
||||
* The mappingLocations for searching xml mapping.
|
||||
@@ -511,8 +530,12 @@ public class ServerConfig {
|
||||
*/
|
||||
private boolean idGeneratorAutomatic = true;
|
||||
|
||||
private boolean dumpMetricsOnShutdown;
|
||||
|
||||
private String dumpMetricsOptions;
|
||||
|
||||
/**
|
||||
* Construct a Server Configuration for programmatically creating an EbeanServer.
|
||||
* Construct a Database Configuration for programmatically creating an Database.
|
||||
*/
|
||||
public ServerConfig() {
|
||||
|
||||
@@ -562,8 +585,9 @@ public class ServerConfig {
|
||||
|
||||
|
||||
/**
|
||||
* Sets the default orderById setting for queries.
|
||||
* Deprecated - look to have explicit order by. Sets the default orderById setting for queries.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setDefaultOrderById(boolean defaultOrderById) {
|
||||
this.defaultOrderById = defaultOrderById;
|
||||
}
|
||||
@@ -592,6 +616,48 @@ public class ServerConfig {
|
||||
return serviceObject.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a service object into configuration such that it can be passed to a plugin.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* JedisPool jedisPool = ..
|
||||
*
|
||||
* serverConfig.putServiceObject(jedisPool);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public void putServiceObject(Object configObject) {
|
||||
String key = serviceObjectKey(configObject);
|
||||
serviceObject.put(key, configObject);
|
||||
}
|
||||
|
||||
private String serviceObjectKey(Object configObject) {
|
||||
return serviceObjectKey(configObject.getClass());
|
||||
}
|
||||
|
||||
private String serviceObjectKey(Class<?> cls) {
|
||||
String simpleName = cls.getSimpleName();
|
||||
return Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by plugins to obtain service objects.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* JedisPool jedisPool = serverConfig.getServiceObject(JedisPool.class);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param cls The type of the service object to obtain
|
||||
* @return The service object given the class type
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <P> P getServiceObject(Class<P> cls) {
|
||||
return (P) serviceObject.get(serviceObjectKey(cls));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Jackson JsonFactory to use.
|
||||
* <p>
|
||||
@@ -624,6 +690,20 @@ public class ServerConfig {
|
||||
this.jsonDateTime = jsonDateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSON format used for Date types.
|
||||
*/
|
||||
public JsonConfig.Date getJsonDate() {
|
||||
return jsonDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JSON format to use for Date types.
|
||||
*/
|
||||
public void setJsonDate(JsonConfig.Date jsonDate) {
|
||||
this.jsonDate = jsonDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSON include mode used when writing JSON.
|
||||
*/
|
||||
@@ -642,14 +722,14 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the EbeanServer.
|
||||
* Return the name of the Database.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the EbeanServer.
|
||||
* Set the name of the Database.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
@@ -658,8 +738,8 @@ public class ServerConfig {
|
||||
/**
|
||||
* Return the container / clustering configuration.
|
||||
* <p/>
|
||||
* The container holds all the EbeanServer instances and provides clustering communication
|
||||
* services to all the EbeanServer instances.
|
||||
* The container holds all the Database instances and provides clustering communication
|
||||
* services to all the Database instances.
|
||||
*/
|
||||
public ContainerConfig getContainerConfig() {
|
||||
return containerConfig;
|
||||
@@ -668,8 +748,8 @@ public class ServerConfig {
|
||||
/**
|
||||
* Set the container / clustering configuration.
|
||||
* <p/>
|
||||
* The container holds all the EbeanServer instances and provides clustering communication
|
||||
* services to all the EbeanServer instances.
|
||||
* The container holds all the Database instances and provides clustering communication
|
||||
* services to all the Database instances.
|
||||
*/
|
||||
public void setContainerConfig(ContainerConfig containerConfig) {
|
||||
this.containerConfig = containerConfig;
|
||||
@@ -709,8 +789,8 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set false if you do not want this EbeanServer to be registered as the "default" server
|
||||
* with the Ebean singleton.
|
||||
* Set false if you do not want this Database to be registered as the "default" database
|
||||
* with the DB singleton.
|
||||
* <p>
|
||||
* This is only used when {@link #setRegister(boolean)} is also true.
|
||||
* </p>
|
||||
@@ -927,6 +1007,30 @@ public class ServerConfig {
|
||||
this.queryBatchSize = queryBatchSize;
|
||||
}
|
||||
|
||||
public EnumType getDefaultEnumType() {
|
||||
return defaultEnumType;
|
||||
}
|
||||
|
||||
public void setDefaultEnumType(EnumType defaultEnumType) {
|
||||
this.defaultEnumType = defaultEnumType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if lazy loading is disabled on queries by default.
|
||||
*/
|
||||
public boolean isDisableLazyLoading() {
|
||||
return disableLazyLoading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to disable lazy loading by default.
|
||||
* <p>
|
||||
* It can be turned on per query via {@link Query#setDisableLazyLoading(boolean)}.
|
||||
*/
|
||||
public void setDisableLazyLoading(boolean disableLazyLoading) {
|
||||
this.disableLazyLoading = disableLazyLoading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default batch size for lazy loading of beans and collections.
|
||||
*/
|
||||
@@ -1480,14 +1584,14 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this EbeanServer is a Document store only instance (has no JDBC DB).
|
||||
* Return true if this Database is a Document store only instance (has no JDBC DB).
|
||||
*/
|
||||
public boolean isDocStoreOnly() {
|
||||
return docStoreOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this EbeanServer is Document store only instance (has no JDBC DB).
|
||||
* Set to true if this Database is Document store only instance (has no JDBC DB).
|
||||
*/
|
||||
public void setDocStoreOnly(boolean docStoreOnly) {
|
||||
this.docStoreOnly = docStoreOnly;
|
||||
@@ -1887,16 +1991,16 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the EbeanServer instance should be created in offline mode.
|
||||
* Return true if the Database instance should be created in offline mode.
|
||||
*/
|
||||
public boolean isDbOffline() {
|
||||
return dbOffline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the EbeanServer instance should be created in offline mode.
|
||||
* Set to true if the Database instance should be created in offline mode.
|
||||
* <p>
|
||||
* Typically used to create an EbeanServer instance for DDL Migration generation
|
||||
* Typically used to create an Database instance for DDL Migration generation
|
||||
* without requiring a real DataSource / Database to connect to.
|
||||
* </p>
|
||||
*/
|
||||
@@ -2051,6 +2155,16 @@ public class ServerConfig {
|
||||
this.ddlRun = ddlRun;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to false if you not want to run the extra-ddl.xml scripts. (default = true)
|
||||
* <p>
|
||||
* Typically we want this on when we are running tests.
|
||||
*/
|
||||
public void setDdlExtra(boolean ddlExtra) {
|
||||
this.ddlExtra = ddlExtra;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the "drop all ddl" should be skipped.
|
||||
* <p>
|
||||
@@ -2121,6 +2235,13 @@ public class ServerConfig {
|
||||
return ddlRun;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true, if extra-ddl.xml should be executed.
|
||||
*/
|
||||
public boolean isDdlExtra() {
|
||||
return ddlExtra;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the class path search should be disabled.
|
||||
*/
|
||||
@@ -2130,7 +2251,7 @@ public class ServerConfig {
|
||||
|
||||
/**
|
||||
* Set to true to disable the class path search even for the case where no entity bean classes
|
||||
* have been registered. This can be used to start an EbeanServer instance just to use the
|
||||
* have been registered. This can be used to start an Database instance just to use the
|
||||
* SQL functions such as SqlQuery, SqlUpdate etc.
|
||||
*/
|
||||
public void setDisableClasspathSearch(boolean disableClasspathSearch) {
|
||||
@@ -2244,8 +2365,7 @@ public class ServerConfig {
|
||||
*
|
||||
* // assume Customer has L2 bean caching enabled ...
|
||||
*
|
||||
* Transaction transaction = Ebean.beginTransaction();
|
||||
* try {
|
||||
* try (Transaction transaction = DB.beginTransaction()) {
|
||||
*
|
||||
* // this uses L2 bean cache as the transaction
|
||||
* // ... is considered "query only" at this point
|
||||
@@ -2253,7 +2373,7 @@ public class ServerConfig {
|
||||
*
|
||||
* // transaction no longer "query only" once
|
||||
* // ... a bean has been saved etc
|
||||
* Ebean.save(someBean);
|
||||
* DB.save(someBean);
|
||||
*
|
||||
* // will NOT use L2 bean cache as the transaction
|
||||
* // ... is no longer considered "query only"
|
||||
@@ -2272,9 +2392,6 @@ public class ServerConfig {
|
||||
* transaction.setSkipCache(true);
|
||||
* Customer.find.byId(99); // skips l2 bean cache
|
||||
*
|
||||
*
|
||||
* } finally {
|
||||
* transaction.end();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
@@ -2342,7 +2459,7 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the ebeanServer should collection query statistics by ObjectGraphNode.
|
||||
* Return true if query statistics should be collected by ObjectGraphNode.
|
||||
*/
|
||||
public boolean isCollectQueryStatsByNode() {
|
||||
return collectQueryStatsByNode;
|
||||
@@ -2745,20 +2862,6 @@ public class ServerConfig {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - this does nothing now, we always try to read test configuration.
|
||||
* <p>
|
||||
* Load settings from test-ebean.properties and do nothing if the properties is not found.
|
||||
* <p>
|
||||
* This is typically used when test-ebean.properties is put into the test class path and used
|
||||
* to configure Ebean for running tests.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
public void loadTestProperties() {
|
||||
// do nothing now ... as we always try to read test configuration and that should only
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties that we used for configuration and were set via a call to loadFromProperties().
|
||||
*/
|
||||
@@ -2826,10 +2929,15 @@ public class ServerConfig {
|
||||
}
|
||||
loadDocStoreSettings(p);
|
||||
|
||||
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);
|
||||
docStoreOnly = p.getBoolean("docStoreOnly", docStoreOnly);
|
||||
disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache);
|
||||
enabledL2Regions = p.get("enabledL2Regions", enabledL2Regions);
|
||||
notifyL2CacheInForeground = p.getBoolean("notifyL2CacheInForeground", notifyL2CacheInForeground);
|
||||
explicitTransactionBeginMode = p.getBoolean("explicitTransactionBeginMode", explicitTransactionBeginMode);
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
|
||||
@@ -2896,19 +3004,18 @@ public class ServerConfig {
|
||||
localTimeWithNanos = p.getBoolean("localTimeWithNanos", localTimeWithNanos);
|
||||
jodaLocalTimeMode = p.get("jodaLocalTimeMode", jodaLocalTimeMode);
|
||||
|
||||
defaultEnumType = p.getEnum(EnumType.class, "defaultEnumType", defaultEnumType);
|
||||
disableLazyLoading = p.getBoolean("disableLazyLoading", disableLazyLoading);
|
||||
lazyLoadBatchSize = p.getInt("lazyLoadBatchSize", lazyLoadBatchSize);
|
||||
queryBatchSize = p.getInt("queryBatchSize", queryBatchSize);
|
||||
|
||||
jsonInclude = p.getEnum(JsonConfig.Include.class, "jsonInclude", jsonInclude);
|
||||
String jsonDateTimeFormat = p.get("jsonDateTime", null);
|
||||
if (jsonDateTimeFormat != null) {
|
||||
jsonDateTime = JsonConfig.DateTime.valueOf(jsonDateTimeFormat);
|
||||
} else {
|
||||
jsonDateTime = JsonConfig.DateTime.MILLIS;
|
||||
}
|
||||
jsonDateTime = p.getEnum(JsonConfig.DateTime.class, "jsonDateTime", jsonDateTime);
|
||||
jsonDate = p.getEnum(JsonConfig.Date.class, "jsonDate", jsonDate);
|
||||
|
||||
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);
|
||||
@@ -3049,6 +3156,20 @@ public class ServerConfig {
|
||||
this.expressionNativeIlike = expressionNativeIlike;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the enabled L2 cache regions.
|
||||
*/
|
||||
public String getEnabledL2Regions() {
|
||||
return enabledL2Regions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the enabled L2 cache regions (comma delimited).
|
||||
*/
|
||||
public void setEnabledL2Regions(String enabledL2Regions) {
|
||||
this.enabledL2Regions = enabledL2Regions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if L2 cache is disabled.
|
||||
*/
|
||||
@@ -3192,6 +3313,50 @@ public class ServerConfig {
|
||||
this.idGeneratorAutomatic = idGeneratorAutomatic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if query plan capture is enabled.
|
||||
*/
|
||||
public boolean isCollectQueryPlans() {
|
||||
return collectQueryPlans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to enable query plan capture.
|
||||
*/
|
||||
public void setCollectQueryPlans(boolean collectQueryPlans) {
|
||||
this.collectQueryPlans = collectQueryPlans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if metrics should be dumped when the server is shutdown.
|
||||
*/
|
||||
public boolean isDumpMetricsOnShutdown() {
|
||||
return dumpMetricsOnShutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if metrics should be dumped when the server is shutdown.
|
||||
*/
|
||||
public void setDumpMetricsOnShutdown(boolean dumpMetricsOnShutdown) {
|
||||
this.dumpMetricsOnShutdown = dumpMetricsOnShutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the options for dumping metrics.
|
||||
*/
|
||||
public String getDumpMetricsOptions() {
|
||||
return dumpMetricsOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include 'sql' or 'hash' in options such that they are included in the output.
|
||||
*
|
||||
* @param dumpMetricsOptions Example "sql,hash", "sql"
|
||||
*/
|
||||
public void setDumpMetricsOptions(String dumpMetricsOptions) {
|
||||
this.dumpMetricsOptions = dumpMetricsOptions;
|
||||
}
|
||||
|
||||
public enum UuidVersion {
|
||||
VERSION4,
|
||||
VERSION1,
|
||||
|
||||
@@ -35,9 +35,9 @@ public enum TenantMode {
|
||||
* (that holds configuration e.g.)
|
||||
*/
|
||||
DB_WITH_MASTER(true, true);
|
||||
|
||||
boolean dynamicDataSource;
|
||||
boolean ddlEnabled;
|
||||
|
||||
final boolean dynamicDataSource;
|
||||
final boolean ddlEnabled;
|
||||
|
||||
TenantMode(boolean dynamicDataSource, boolean ddlEnabled) {
|
||||
this.dynamicDataSource = dynamicDataSource;
|
||||
@@ -50,12 +50,12 @@ public enum TenantMode {
|
||||
public boolean isDynamicDataSource() {
|
||||
return dynamicDataSource;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true, if DDL is enabled.
|
||||
*/
|
||||
public boolean isDdlEnabled() {
|
||||
return ddlEnabled;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -49,6 +49,10 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected boolean useExtraTransactionOnIterateSecondaryQueries;
|
||||
|
||||
protected boolean supportsDeleteTableAlias;
|
||||
|
||||
protected boolean supportsSavepointId = true;
|
||||
|
||||
/**
|
||||
* The behaviour used when ending a read only transaction at read committed isolation level.
|
||||
*/
|
||||
@@ -69,6 +73,8 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected boolean allQuotedIdentifiers;
|
||||
|
||||
protected boolean caseSensitiveCollation = true;
|
||||
|
||||
/**
|
||||
* For limit/offset, row_number etc limiting of SQL queries.
|
||||
*/
|
||||
@@ -133,6 +139,8 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected Platform platform = Platform.GENERIC;
|
||||
|
||||
protected String truncateTable = "truncate table %s";
|
||||
|
||||
protected String columnAliasPrefix = "c";
|
||||
|
||||
protected String tableAliasPlaceHolder = "${ta}";
|
||||
@@ -178,7 +186,15 @@ public class DatabasePlatform {
|
||||
protected boolean forwardOnlyHintOnFindIterate;
|
||||
|
||||
/**
|
||||
* By default we use JDBC batch when cascading (except for SQL Server).
|
||||
* If set then use the CONCUR_UPDATABLE hint when creating ResultSets.
|
||||
*
|
||||
* This is {@code false} for HANA
|
||||
*/
|
||||
protected boolean supportsResultSetConcurrencyModeUpdatable = true;
|
||||
|
||||
|
||||
/**
|
||||
* By default we use JDBC batch when cascading (except for SQL Server and HANA).
|
||||
*/
|
||||
protected PersistBatch persistBatchOnCascade = PersistBatch.ALL;
|
||||
|
||||
@@ -216,6 +232,7 @@ public class DatabasePlatform {
|
||||
*/
|
||||
public void configure(PlatformConfig config) {
|
||||
this.sequenceBatchSize = config.getDatabaseSequenceBatchSize();
|
||||
this.caseSensitiveCollation = config.isCaseSensitiveCollation();
|
||||
configureIdType(config.getIdType());
|
||||
configure(config, config.isAllQuotedIdentifiers());
|
||||
}
|
||||
@@ -298,6 +315,30 @@ public class DatabasePlatform {
|
||||
return supportsNativeIlike;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the platform supports delete statements with table alias.
|
||||
*/
|
||||
public boolean isSupportsDeleteTableAlias() {
|
||||
return supportsDeleteTableAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the collation is case sensitive.
|
||||
* <p>
|
||||
* This is expected to be used for testing only.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isCaseSensitiveCollation() {
|
||||
return caseSensitiveCollation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the platform supports SavepointId values.
|
||||
*/
|
||||
public boolean isSupportsSavepointId() {
|
||||
return supportsSavepointId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum table name length.
|
||||
* <p>
|
||||
@@ -517,10 +558,28 @@ public class DatabasePlatform {
|
||||
this.forwardOnlyHintOnFindIterate = forwardOnlyHintOnFindIterate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the ResultSet CONCUR_UPDATABLE Hint should be used on
|
||||
* createNativeSqlTree() PreparedStatements.
|
||||
* <p>
|
||||
* This specifically is required for Hana which doesn't support CONCUR_UPDATABLE
|
||||
* </p>
|
||||
*/
|
||||
public boolean isSupportsResultSetConcurrencyModeUpdatable() {
|
||||
return supportsResultSetConcurrencyModeUpdatable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the ResultSet CONCUR_UPDATABLE Hint should be used by default on createNativeSqlTree() PreparedStatements.
|
||||
*/
|
||||
public void setSupportsResultSetConcurrencyModeUpdatable(boolean supportsResultSetConcurrencyModeUpdatable) {
|
||||
this.supportsResultSetConcurrencyModeUpdatable = supportsResultSetConcurrencyModeUpdatable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normally not needed - overridden in CockroachPlatform.
|
||||
*/
|
||||
public boolean isDdlCommitOnCreateIndex() {
|
||||
public boolean isDdlAutoCommit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -651,6 +710,13 @@ public class DatabasePlatform {
|
||||
return persistBatchOnCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a statement to truncate a table.
|
||||
*/
|
||||
public String truncateStatement(String table) {
|
||||
return String.format(truncateTable, table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the DB schema if it does not exist.
|
||||
*/
|
||||
|
||||
@@ -27,15 +27,13 @@ public class DbDefaultValue {
|
||||
* The key for the NOW / current timestamp.
|
||||
*/
|
||||
public static final String NOW = "now";
|
||||
|
||||
|
||||
/**
|
||||
* The 'null' literal.
|
||||
*/
|
||||
public static final String NULL = "null";
|
||||
|
||||
|
||||
|
||||
protected Map<String, String> map = new LinkedHashMap<>();
|
||||
protected final Map<String, String> map = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* Set the DB now function.
|
||||
@@ -82,10 +80,9 @@ public class DbDefaultValue {
|
||||
return val != null ? val : dbDefaultLiteral;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method checks & convert the {@link DbDefault#value()} to a valid SQL literal.
|
||||
*
|
||||
*
|
||||
* This is mainly to quote string literals and verify integer/dates for correctness.
|
||||
* <p>
|
||||
* Note: There are some special cases:
|
||||
@@ -98,24 +95,24 @@ public class DbDefaultValue {
|
||||
* If you need really the String "null", you have to specify <code>@DbDefault("'null'")</code>
|
||||
* which gives you the <code>default 'null'</code> statement.</li>
|
||||
* <li>Any statement, that begins and ends with single quote will not be checked or get quoted again.</li>
|
||||
* <li>A statement that begins with "$RAW:", e.g <code>@DbDefault("$RAW:N'SANDNES'")</code> will lead to
|
||||
* <li>A statement that begins with "$RAW:", e.g <code>@DbDefault("$RAW:N'SANDNES'")</code> will lead to
|
||||
* a <code>default N'SANDNES'</code> in DDL. Note that this is platform specific!</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static String toSqlLiteral(String defaultValue, Class<?> propertyType, int sqlType) {
|
||||
if (propertyType == null
|
||||
|| defaultValue == null
|
||||
|| defaultValue == null
|
||||
|| NULL.equals(defaultValue)
|
||||
|| (defaultValue.startsWith("'") && defaultValue.endsWith("'"))
|
||||
|| (defaultValue.startsWith("$RAW:"))) {
|
||||
|| (defaultValue.startsWith("$RAW:"))) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (Boolean.class.isAssignableFrom(propertyType) || Boolean.TYPE.isAssignableFrom(propertyType)) {
|
||||
return toBooleanLiteral(defaultValue);
|
||||
}
|
||||
|
||||
if (Number.class.isAssignableFrom(propertyType)
|
||||
|
||||
if (Number.class.isAssignableFrom(propertyType)
|
||||
|| Byte.TYPE.equals(propertyType)
|
||||
|| Short.TYPE.equals(propertyType)
|
||||
|| Integer.TYPE.equals(propertyType)
|
||||
@@ -126,7 +123,7 @@ public class DbDefaultValue {
|
||||
Double.valueOf(defaultValue); // verify if it is a number
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
// check if it is a date/time - in all other cases return quoted defaultValue
|
||||
switch (sqlType) {
|
||||
// date
|
||||
@@ -155,7 +152,7 @@ public class DbDefaultValue {
|
||||
}
|
||||
throw new IllegalArgumentException("'" + value + "' is not a valid value for boolean");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This adds single qoutes around the <code>value</code> and doubles single quotes.
|
||||
* "User's home" will return "'User''s home'"
|
||||
@@ -175,7 +172,7 @@ public class DbDefaultValue {
|
||||
return sb.toString();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static String toDateLiteral(String value) {
|
||||
if (NOW.equals(value)) {
|
||||
return value; // this will get translated later
|
||||
@@ -191,7 +188,7 @@ public class DbDefaultValue {
|
||||
DatatypeConverter.parseTime(value); // verify
|
||||
return toTextLiteral(value);
|
||||
}
|
||||
|
||||
|
||||
private static String toDateTimeLiteral(String value) {
|
||||
if (NOW.equals(value)) {
|
||||
return value; // this will get translated later
|
||||
|
||||
@@ -8,7 +8,9 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public class DbIdentity {
|
||||
|
||||
private static final Pattern TABLE_REPLACE = Pattern.compile("{table}", Pattern.LITERAL);
|
||||
private static final String TABLE_PLACEHOLDER = "{table}";
|
||||
|
||||
private static final Pattern TABLE_REPLACE = Pattern.compile(TABLE_PLACEHOLDER, Pattern.LITERAL);
|
||||
|
||||
/**
|
||||
* Set if this DB supports sequences. Note some DB's support both Sequences
|
||||
@@ -53,7 +55,9 @@ public class DbIdentity {
|
||||
if (selectLastInsertedIdTemplate == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!selectLastInsertedIdTemplate.contains(TABLE_PLACEHOLDER)) {
|
||||
return selectLastInsertedIdTemplate;
|
||||
}
|
||||
return TABLE_REPLACE.matcher(selectLastInsertedIdTemplate).replaceAll(Matcher.quoteReplacement(table));
|
||||
}
|
||||
|
||||
|
||||
@@ -11,12 +11,12 @@ class DbPlatformTypeLookup {
|
||||
/**
|
||||
* A map to lookup the type by name.
|
||||
*/
|
||||
private Map<String, DbType> nameLookup = new HashMap<>();
|
||||
private final Map<String, DbType> nameLookup = new HashMap<>();
|
||||
|
||||
/**
|
||||
* A map to lookup the type by JDBC int value.
|
||||
*/
|
||||
private Map<Integer, DbType> idLookup = new HashMap<>();
|
||||
private final Map<Integer, DbType> idLookup = new HashMap<>();
|
||||
|
||||
DbPlatformTypeLookup() {
|
||||
addAll();
|
||||
|
||||
@@ -23,10 +23,13 @@ public class DbPlatformTypeMapping {
|
||||
}
|
||||
}
|
||||
|
||||
private static DbPlatformTypeLookup lookup = new DbPlatformTypeLookup();
|
||||
private static final DbPlatformTypeLookup lookup = new DbPlatformTypeLookup();
|
||||
|
||||
private static final DbPlatformType BOOLEAN_LOGICAL = new BooleanLogicalType();
|
||||
|
||||
private static final DbPlatformType INET_NATIVE = new DbPlatformType("inet", false);
|
||||
private static final DbPlatformType INET_VARCHAR = new DbPlatformType("varchar", 50);
|
||||
|
||||
private static final DbPlatformType UUID_NATIVE = new DbPlatformType("uuid", false);
|
||||
@SuppressWarnings("unused")
|
||||
private static final DbPlatformType UUID_PLACEHOLDER = new DbPlatformType("uuidPlaceholder");
|
||||
@@ -106,6 +109,7 @@ public class DbPlatformTypeMapping {
|
||||
put(DbType.JSONBLOB, new DbPlatformType("jsonblob"));
|
||||
put(DbType.JSONVARCHAR, new DbPlatformType("jsonvarchar", 1000));
|
||||
put(DbType.UUID, UUID_NATIVE);
|
||||
put(DbType.INET, INET_NATIVE);
|
||||
|
||||
} else {
|
||||
put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
|
||||
@@ -121,6 +125,7 @@ public class DbPlatformTypeMapping {
|
||||
put(DbType.JSONVARCHAR, JSON_VARCHAR_PLACEHOLDER);
|
||||
// default to native UUID and override on platform configure()
|
||||
put(DbType.UUID, UUID_NATIVE);
|
||||
put(DbType.INET, INET_VARCHAR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ public enum DbType {
|
||||
ARRAY(Types.ARRAY),
|
||||
|
||||
UUID(ExtraDbTypes.UUID),
|
||||
INET(ExtraDbTypes.INET),
|
||||
CDIR(ExtraDbTypes.CDIR),
|
||||
|
||||
POINT(ExtraDbTypes.POINT),
|
||||
POLYGON(ExtraDbTypes.POLYGON),
|
||||
|
||||
@@ -40,6 +40,9 @@ public interface ExtraDbTypes {
|
||||
*/
|
||||
int JSONBlob = 5005;
|
||||
|
||||
int INET = 5020;
|
||||
int CDIR = 5021;
|
||||
|
||||
/**
|
||||
* Geo Point
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class SqlErrorCodes {
|
||||
|
||||
private Map<String,DataErrorType> map = new HashMap<>();
|
||||
private final Map<String,DataErrorType> map = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Map the codes to AcquireLockException.
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package io.ebean.config.dbplatform.clickhouse;
|
||||
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
public class ClickHousePlatform extends DatabasePlatform {
|
||||
|
||||
public ClickHousePlatform() {
|
||||
super();
|
||||
this.platform = Platform.CLICKHOUSE;
|
||||
//this.dbEncrypt =
|
||||
//this.historySupport =
|
||||
//this.exceptionTranslator =
|
||||
|
||||
this.nativeUuidType = true;
|
||||
this.dbDefaultValue.setNow("now()");
|
||||
this.columnAliasPrefix = null;
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
this.dbIdentity.setSupportsSequence(false);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
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));
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("UInt32", false));
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("UInt64", false));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("Decimal", 16,4));
|
||||
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.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.CDIR, new DbPlatformType("String", false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNativeArrayType() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,7 +21,7 @@ public class CockroachPlatform extends PostgresPlatform {
|
||||
* Needs a commit after create index such that alter table add foreign key ... succeeds.
|
||||
*/
|
||||
@Override
|
||||
public boolean isDdlCommitOnCreateIndex() {
|
||||
public boolean isDdlAutoCommit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ public class DB2Platform extends DatabasePlatform {
|
||||
this.platform = Platform.DB2;
|
||||
this.maxTableNameLength = 18;
|
||||
this.maxConstraintNameLength = 18;
|
||||
this.truncateTable = "truncate table %s reuse storage ignore delete triggers immediate";
|
||||
this.sqlLimiter = new Db2SqlLimiter();
|
||||
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
|
||||
@@ -23,9 +23,9 @@ public class H2Platform extends DatabasePlatform {
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
this.historySupport = new H2HistorySupport();
|
||||
this.nativeUuidType = true;
|
||||
this.supportsDeleteTableAlias = true;
|
||||
this.dbDefaultValue.setNow("now()");
|
||||
this.columnAliasPrefix = null;
|
||||
|
||||
this.exceptionTranslator =
|
||||
new SqlErrorCodes()
|
||||
.addAcquireLock("50200","HYT00")
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package io.ebean.config.dbplatform.hana;
|
||||
|
||||
import io.ebean.config.dbplatform.BasicSqlLimiter;
|
||||
|
||||
public class HanaBasicSqlLimiter implements BasicSqlLimiter {
|
||||
@Override
|
||||
public String limit(String dbSql, int firstRow, int maxRows) {
|
||||
StringBuilder sb = new StringBuilder(50 + dbSql.length());
|
||||
|
||||
sb.append(dbSql);
|
||||
|
||||
if (maxRows > 0) {
|
||||
sb.append(" ").append("limit");
|
||||
sb.append(" ").append(maxRows);
|
||||
|
||||
if (firstRow > 0) {
|
||||
sb.append(" ").append("offset").append(" ");
|
||||
sb.append(firstRow);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package io.ebean.config.dbplatform.hana;
|
||||
|
||||
import io.ebean.config.dbplatform.DbStandardHistorySupport;
|
||||
|
||||
public class HanaHistorySupport extends DbStandardHistorySupport {
|
||||
|
||||
@Override
|
||||
public String getAsOfViewSuffix(String asOfViewSuffix) {
|
||||
return " for system_time as of ?";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersionsBetweenSuffix(String asOfViewSuffix) {
|
||||
return " for system_time between ? and ?";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSysPeriodLower(String tableAlias, String sysPeriod) {
|
||||
return tableAlias + "." + sysPeriod + "_start";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSysPeriodUpper(String tableAlias, String sysPeriod) {
|
||||
return tableAlias + "." + sysPeriod + "_end";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package io.ebean.config.dbplatform.hana;
|
||||
|
||||
import io.ebean.Query.ForUpdate;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
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;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.dbplatform.SqlErrorCodes;
|
||||
|
||||
public class HanaPlatform extends DatabasePlatform {
|
||||
|
||||
public HanaPlatform() {
|
||||
this.platform = Platform.HANA;
|
||||
this.sqlLimiter = new HanaSqlLimiter();
|
||||
this.persistBatchOnCascade = PersistBatch.NONE;
|
||||
this.supportsResultSetConcurrencyModeUpdatable = false;
|
||||
this.columnAliasPrefix = null;
|
||||
this.historySupport = new HanaHistorySupport();
|
||||
this.basicSqlLimiter = new HanaBasicSqlLimiter();
|
||||
|
||||
this.likeClauseRaw = "like ?";
|
||||
this.maxConstraintNameLength = 127;
|
||||
this.maxTableNameLength = 127;
|
||||
|
||||
this.dbDefaultValue.setNow("current_timestamp");
|
||||
|
||||
this.exceptionTranslator = new SqlErrorCodes().addAcquireLock("131", "133", "146")
|
||||
.addDataIntegrity("130", "429", "461", "462").addDuplicateKey("144", "301", "349").build();
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSelectLastInsertedIdTemplate("select current_identity_value() from sys.dummy");
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
this.dbTypeMap.put(DbType.BIGINT, new DbPlatformType("bigint", false));
|
||||
this.dbTypeMap.put(DbType.BINARY, new DbPlatformType("varbinary", 255));
|
||||
this.dbTypeMap.put(DbType.BIT, new DbPlatformType("smallint", false));
|
||||
this.dbTypeMap.put(DbType.BLOB, new DbPlatformType("blob", false));
|
||||
this.dbTypeMap.put(DbType.CHAR, new DbPlatformType("nvarchar", 255));
|
||||
this.dbTypeMap.put(DbType.CLOB, new DbPlatformType("nclob", false));
|
||||
this.dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
|
||||
this.dbTypeMap.put(DbType.JSONVARCHAR, new DbPlatformType("nvarchar", 255));
|
||||
this.dbTypeMap.put(DbType.LINESTRING, new DbPlatformType("st_geometry"));
|
||||
this.dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("blob", false));
|
||||
this.dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("nclob", false));
|
||||
this.dbTypeMap.put(DbType.MULTILINESTRING, new DbPlatformType("st_geometry"));
|
||||
this.dbTypeMap.put(DbType.MULTIPOINT, new DbPlatformType("st_geometry"));
|
||||
this.dbTypeMap.put(DbType.MULTIPOLYGON, new DbPlatformType("st_geometry"));
|
||||
this.dbTypeMap.put(DbType.POINT, new DbPlatformType("st_point"));
|
||||
this.dbTypeMap.put(DbType.POLYGON, new DbPlatformType("st_geometry"));
|
||||
this.dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("smallint", false));
|
||||
this.dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint", false));
|
||||
this.dbTypeMap.put(DbType.UUID, new DbPlatformType("varchar", 40));
|
||||
this.dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
|
||||
this.dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("nvarchar", 255));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addGeoTypes(int srid) {
|
||||
this.dbTypeMap.put(DbType.LINESTRING, new DbPlatformType("st_geometry(" + srid + ")", false));
|
||||
this.dbTypeMap.put(DbType.MULTILINESTRING, new DbPlatformType("st_geometry(" + srid + ")", false));
|
||||
this.dbTypeMap.put(DbType.MULTIPOINT, new DbPlatformType("st_geometry(" + srid + ")", false));
|
||||
this.dbTypeMap.put(DbType.MULTIPOLYGON, new DbPlatformType("st_geometry(" + srid + ")", false));
|
||||
this.dbTypeMap.put(DbType.POINT, new DbPlatformType("st_point(" + srid + ")", false));
|
||||
this.dbTypeMap.put(DbType.POLYGON, new DbPlatformType("st_geometry(" + srid + ")", false));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
case BASE:
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(PlatformConfig config, boolean allQuotedIdentifiers) {
|
||||
super.configure(config, allQuotedIdentifiers);
|
||||
if (config.getDbUuid().useBinary()) {
|
||||
this.dbTypeMap.put(DbType.UUID, new DbPlatformType("varbinary", 16));
|
||||
} else {
|
||||
this.dbTypeMap.put(DbType.UUID, new DbPlatformType("varchar", 40));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package io.ebean.config.dbplatform.hana;
|
||||
|
||||
import io.ebean.config.dbplatform.SqlLimitRequest;
|
||||
import io.ebean.config.dbplatform.SqlLimitResponse;
|
||||
import io.ebean.config.dbplatform.SqlLimiter;
|
||||
|
||||
public class HanaSqlLimiter implements SqlLimiter {
|
||||
@Override
|
||||
public SqlLimitResponse limit(SqlLimitRequest request) {
|
||||
String dbSql = request.getDbSql();
|
||||
|
||||
StringBuilder sb = new StringBuilder(50 + dbSql.length());
|
||||
sb.append("select ");
|
||||
if (request.isDistinct()) {
|
||||
sb.append("distinct ");
|
||||
}
|
||||
|
||||
sb.append(dbSql);
|
||||
|
||||
int firstRow = request.getFirstRow();
|
||||
int maxRows = request.getMaxRows();
|
||||
|
||||
if (maxRows > 0) {
|
||||
sb.append(" ").append("limit ").append(maxRows);
|
||||
if (firstRow > 0) {
|
||||
sb.append(" ").append("offset ");
|
||||
sb.append(firstRow);
|
||||
}
|
||||
}
|
||||
|
||||
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
|
||||
|
||||
return new SqlLimitResponse(sql, false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* SAP HANA specific support.
|
||||
*/
|
||||
package io.ebean.config.dbplatform.hana;
|
||||
@@ -21,7 +21,7 @@ public class HsqldbPlatform extends DatabasePlatform {
|
||||
super();
|
||||
this.platform = Platform.HSQLDB;
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
|
||||
this.truncateTable = "delete from %s";
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
@@ -27,15 +27,15 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
this.platform = Platform.MYSQL;
|
||||
this.useExtraTransactionOnIterateSecondaryQueries = true;
|
||||
this.selectCountWithAlias = true;
|
||||
this.supportsSavepointId = false;
|
||||
this.dbEncrypt = new MySqlDbEncrypt();
|
||||
this.historySupport = new MySqlHistorySupport();
|
||||
this.columnAliasPrefix = null;
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
this.dbIdentity.setSupportsSequence(false);
|
||||
|
||||
|
||||
this.dbDefaultValue.setNow("now(6)"); // must have same precision as TIMESTAMP
|
||||
this.dbDefaultValue.setFalse("0");
|
||||
this.dbDefaultValue.setTrue("1");
|
||||
@@ -51,8 +51,8 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
this.openQuote = "`";
|
||||
this.closeQuote = "`";
|
||||
// use pipe for escaping as it depends if mysql runs in no_backslash_escapes or not.
|
||||
this.likeClauseRaw = "like binary ? escape ''";
|
||||
this.likeClauseEscaped = "like binary ? escape '|'";
|
||||
this.likeClauseRaw = "like ? escape ''";
|
||||
this.likeClauseEscaped = "like ? escape '|'";
|
||||
|
||||
this.forwardOnlyHintOnFindIterate = true;
|
||||
this.booleanDbType = Types.BIT;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package io.ebean.config.dbplatform.nuodb;
|
||||
|
||||
import io.ebean.config.dbplatform.DbViewHistorySupport;
|
||||
|
||||
/**
|
||||
* Runtime support for @History with NuoDB.
|
||||
*/
|
||||
public class NuoDbHistorySupport extends DbViewHistorySupport {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package io.ebean.config.dbplatform.nuodb;
|
||||
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.dbplatform.PlatformIdGenerator;
|
||||
import io.ebean.config.dbplatform.SqlErrorCodes;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* NuoDb specific platform.
|
||||
*/
|
||||
public class NuoDbPlatform extends DatabasePlatform {
|
||||
|
||||
public NuoDbPlatform() {
|
||||
super();
|
||||
this.platform = Platform.NUODB;
|
||||
this.idInExpandedForm = true;
|
||||
this.supportsResultSetConcurrencyModeUpdatable = false;
|
||||
this.supportsDeleteTableAlias = true;
|
||||
this.columnAliasPrefix = null;
|
||||
this.likeClauseRaw = "like ?";
|
||||
this.historySupport = new NuoDbHistorySupport();
|
||||
//this.dbEncrypt = ...
|
||||
dbIdentity.setIdType(IdType.IDENTITY);
|
||||
dbIdentity.setSupportsIdentity(true);
|
||||
dbIdentity.setSupportsSequence(true);
|
||||
dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
|
||||
// No referential integrity exception to map
|
||||
this.exceptionTranslator =
|
||||
new SqlErrorCodes()
|
||||
//.addAcquireLock("")
|
||||
.addDuplicateKey("23000")
|
||||
.build();
|
||||
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) {
|
||||
return new NuoDbSequence(be, ds, seqName, stepSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
case NOWAIT:
|
||||
return sql + " for update nowait";
|
||||
case SKIPLOCKED:
|
||||
default:
|
||||
return sql + " for update";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user