mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
846
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b594fb533 | ||
|
|
c0efd49c73 | ||
|
|
54ba1480eb | ||
|
|
4d8bc0a2ce | ||
|
|
e182190f96 | ||
|
|
8711ebc6f7 | ||
|
|
baa7242939 | ||
|
|
47e8d27212 | ||
|
|
70aed3906e | ||
|
|
70c3860a65 | ||
|
|
1ba21d5c43 | ||
|
|
2019bc7bf1 | ||
|
|
3cb52917e3 | ||
|
|
55a257a64c | ||
|
|
83ef204f3c | ||
|
|
a18cac035b | ||
|
|
873c14faaf | ||
|
|
e1af7c29eb | ||
|
|
c1c85b67c2 | ||
|
|
05b8adbf6e | ||
|
|
3ca4efc818 | ||
|
|
ec2c3b13d4 | ||
|
|
5a3e386b7c | ||
|
|
7e56a147be | ||
|
|
62cdfb3209 | ||
|
|
740532da4b | ||
|
|
130356cb3b | ||
|
|
ab84cfae52 | ||
|
|
ad21b7a3fd | ||
|
|
31581082d2 | ||
|
|
aa84dfe7d8 | ||
|
|
aad5b33db2 | ||
|
|
5801f7620d | ||
|
|
514416a1e0 | ||
|
|
8faa95adc1 | ||
|
|
ebaeafc11b | ||
|
|
98e014f8c8 | ||
|
|
78912d75e0 | ||
|
|
09786a7062 | ||
|
|
54530248a5 | ||
|
|
fdafa776e1 | ||
|
|
392eb2744d | ||
|
|
b642b3c644 | ||
|
|
0e1c815826 | ||
|
|
83b463040f | ||
|
|
aea7d937eb | ||
|
|
78628ffad0 | ||
|
|
56a742ad70 | ||
|
|
a4415b03ff | ||
|
|
e252f71792 | ||
|
|
18ca3403ac | ||
|
|
94a118d635 | ||
|
|
efe325034b | ||
|
|
0c368ed7b3 | ||
|
|
c1b022c123 | ||
|
|
021d57f4b2 | ||
|
|
11e180aa3f | ||
|
|
9e2ddc9f8c | ||
|
|
d4e72eefa0 | ||
|
|
525afbc00f | ||
|
|
6f2e1c0248 | ||
|
|
0d0a3422fc | ||
|
|
57b0190cd2 | ||
|
|
c8e199177c | ||
|
|
68a470a086 | ||
|
|
45a023f0e4 | ||
|
|
06bce35f5a | ||
|
|
3dfdd0e2e8 | ||
|
|
a569c7fc96 | ||
|
|
e751f991cb | ||
|
|
83cf768369 | ||
|
|
bb418456e3 | ||
|
|
ac9f3408b2 | ||
|
|
78f8d48e2e | ||
|
|
3f8b9529e1 | ||
|
|
10f3d85d9f | ||
|
|
0e3f47ee82 | ||
|
|
cdbbd749a3 | ||
|
|
a712be2917 | ||
|
|
0cba0664f8 | ||
|
|
a3e5c3a786 | ||
|
|
58def02cd1 | ||
|
|
cec65cc888 | ||
|
|
da7bb834e7 | ||
|
|
a64a244745 | ||
|
|
1c19d4cf7e | ||
|
|
347225efb2 | ||
|
|
91cb5a23fd | ||
|
|
0e219a9bc6 | ||
|
|
21182da793 | ||
|
|
0de084caec | ||
|
|
e3425a8850 | ||
|
|
8e9843ab8a | ||
|
|
75462e7410 | ||
|
|
265bda8cf2 | ||
|
|
7d0ed261b5 | ||
|
|
ff111eaf33 | ||
|
|
8b18e907af | ||
|
|
40704e2ef7 | ||
|
|
0e62d0579e | ||
|
|
47d55a2f29 | ||
|
|
b037be5d3e | ||
|
|
60a3c24cba | ||
|
|
4a243a76a7 | ||
|
|
9aee7c892d | ||
|
|
18d944f228 | ||
|
|
29bb9d3b48 | ||
|
|
f8ea5619d0 | ||
|
|
e3fac7c622 | ||
|
|
8ee68ac5e1 | ||
|
|
ec7b376612 | ||
|
|
f2d438f21a | ||
|
|
20bd2241e4 | ||
|
|
dd907cc4bc | ||
|
|
4d122ea05b | ||
|
|
83384c6f0e | ||
|
|
eaa48468cd | ||
|
|
0b1c3a4233 | ||
|
|
3e8b06e38e | ||
|
|
81d48d67a7 | ||
|
|
8d0df6541e | ||
|
|
2be3099d55 | ||
|
|
183d079b58 | ||
|
|
40634412f5 | ||
|
|
b8aa822a30 | ||
|
|
a1d0fbb194 | ||
|
|
70ccc6588d | ||
|
|
3d62e84d59 | ||
|
|
ac36172cc6 | ||
|
|
1829c74694 | ||
|
|
cc7e22014d | ||
|
|
a5c6f483b0 | ||
|
|
5237e8ba66 | ||
|
|
9926cad7f1 | ||
|
|
6c1b295d41 | ||
|
|
49b568e7d4 | ||
|
|
628af31ddd | ||
|
|
31cac60393 | ||
|
|
6a067c0cf7 | ||
|
|
842292ef6b | ||
|
|
6db9a60f4f | ||
|
|
d9125db957 | ||
|
|
4bd9e67703 | ||
|
|
2a986ab590 | ||
|
|
7c477827fe | ||
|
|
b2967dec1e | ||
|
|
a95fd063ae | ||
|
|
17a54e3804 | ||
|
|
f1b2a09b30 | ||
|
|
e4d9e4f2de | ||
|
|
6474f306b5 | ||
|
|
f1c2f134ad | ||
|
|
0f7158ea18 | ||
|
|
3fdb76d18f | ||
|
|
b1027a2f25 | ||
|
|
e5a1f9f7cc | ||
|
|
f78f24136a | ||
|
|
5b2aa0c74d | ||
|
|
175714046a | ||
|
|
73b2cc55f3 | ||
|
|
cebe375856 | ||
|
|
2f47235018 | ||
|
|
17abd6d977 | ||
|
|
cc5f3689f3 | ||
|
|
abcc651e7f | ||
|
|
caa36262c1 | ||
|
|
66b6dba921 | ||
|
|
fc01f230f3 | ||
|
|
7fe3e657d7 | ||
|
|
9bade12c9d | ||
|
|
7a816ae2da | ||
|
|
b83412281e | ||
|
|
478bba292d | ||
|
|
77a4e684bb | ||
|
|
a8254c4295 | ||
|
|
2a5d0084ef | ||
|
|
f9404639d7 | ||
|
|
bbef5a6bbb | ||
|
|
4645fd9725 | ||
|
|
823cb45221 | ||
|
|
b2bbb05b83 | ||
|
|
5ff71324d0 | ||
|
|
851f1c98b0 | ||
|
|
a92e620f7e | ||
|
|
f9cd955f7a | ||
|
|
71f66005e7 | ||
|
|
b682293a32 | ||
|
|
5bd7853ce8 | ||
|
|
276c56161a | ||
|
|
6b01821623 | ||
|
|
8495ccced6 | ||
|
|
2d929837c4 | ||
|
|
6754992b1c | ||
|
|
08b7f4a95f | ||
|
|
07e2605a30 | ||
|
|
9a0b742f14 | ||
|
|
bce745e88d | ||
|
|
51d2e4c600 | ||
|
|
4e33027fdf | ||
|
|
0a809b0fb3 | ||
|
|
13ddb915c8 | ||
|
|
07cdf64ece | ||
|
|
b9ae76d465 | ||
|
|
82f5c21d26 | ||
|
|
14105eb1eb | ||
|
|
bab27f25ca | ||
|
|
eed8d69715 | ||
|
|
7b93df2df7 | ||
|
|
bb205ced54 | ||
|
|
0d4c50e19c | ||
|
|
8cff85fdda | ||
|
|
932986a6b5 | ||
|
|
01539091ef | ||
|
|
7e69f71b51 | ||
|
|
58d6b2c24e | ||
|
|
3c7ef7d46e | ||
|
|
db5db26fca | ||
|
|
7110f4a59b | ||
|
|
9f91d8bcf9 | ||
|
|
ac97444ad1 | ||
|
|
f6e9afcab6 | ||
|
|
a7226079fe | ||
|
|
fc915010d9 | ||
|
|
c1818bc309 | ||
|
|
4a4134ee93 | ||
|
|
e07bd8f736 | ||
|
|
4d0b29624e | ||
|
|
c7f4b56dd1 | ||
|
|
69c045443c | ||
|
|
fd2d083971 | ||
|
|
b9380aa5b8 | ||
|
|
3a1368a342 | ||
|
|
0e9fc31531 | ||
|
|
5132107748 | ||
|
|
7ff3d703f7 | ||
|
|
ef91c643ed | ||
|
|
f0ddf6c7e6 | ||
|
|
fcff571664 | ||
|
|
d5555ed9a9 | ||
|
|
c5a11aa5a8 | ||
|
|
d1099c8309 | ||
|
|
7ff8758797 | ||
|
|
f1ebe7929b | ||
|
|
0056568bc7 | ||
|
|
4b72924529 | ||
|
|
a75ed676f8 | ||
|
|
c3438b888d | ||
|
|
56be274acc | ||
|
|
84bb4ff78c | ||
|
|
4054eda1f6 | ||
|
|
a4b9354e43 | ||
|
|
06e033f23f | ||
|
|
156f505394 | ||
|
|
9b2b2f7787 | ||
|
|
e68dae0baa | ||
|
|
2cf864954f | ||
|
|
2b94487573 | ||
|
|
fcf730ec39 | ||
|
|
7d343455ac | ||
|
|
21e0b748a6 | ||
|
|
2fab733e4e | ||
|
|
7260a1b6eb | ||
|
|
434a005366 | ||
|
|
ff67ef60b0 | ||
|
|
0a1747d8e3 | ||
|
|
f36499f71f | ||
|
|
da818f17c2 | ||
|
|
10eb2bc21f | ||
|
|
66fe278e3f | ||
|
|
10607385e0 | ||
|
|
db6562df76 | ||
|
|
c0ec87d4cd | ||
|
|
0dbba7a211 | ||
|
|
e75670f207 | ||
|
|
fb8db14f3a | ||
|
|
c00b1849ef | ||
|
|
1e1c518641 | ||
|
|
d5b42f9ba1 | ||
|
|
bda564d2c8 | ||
|
|
dce124cabd | ||
|
|
f5cfcbd56e | ||
|
|
5bccdccbd6 | ||
|
|
6e62b72fb9 | ||
|
|
89dac3820b | ||
|
|
ea836a0078 | ||
|
|
1ffd7c7720 | ||
|
|
387582543c | ||
|
|
a215878a7c | ||
|
|
dbedb65922 | ||
|
|
1d52b3a818 | ||
|
|
6ce2b91fff | ||
|
|
55d66ae851 | ||
|
|
37d001f754 | ||
|
|
c121618c0c | ||
|
|
7ebef51859 | ||
|
|
093f82a87f | ||
|
|
b60f1f978f | ||
|
|
6ac146cabe | ||
|
|
2263d31f46 | ||
|
|
4a66d0be6b | ||
|
|
e68e496207 | ||
|
|
088110385f | ||
|
|
a355f66561 | ||
|
|
00fdb632d7 | ||
|
|
a54c4157e6 | ||
|
|
a89a9f0202 | ||
|
|
331f49824f | ||
|
|
94a857d345 | ||
|
|
1005f177fd | ||
|
|
96a4b93c75 | ||
|
|
5869187368 | ||
|
|
eac50b8f5b | ||
|
|
6e2712ea49 | ||
|
|
f6e5446dab | ||
|
|
4879d44da4 | ||
|
|
2c5bf98d0b | ||
|
|
45a571bd97 | ||
|
|
d0ca75c25b | ||
|
|
fb1c7667cc | ||
|
|
1909ba1557 | ||
|
|
e4eca4bbe9 | ||
|
|
b2438ecd71 | ||
|
|
ed08567d06 | ||
|
|
bbe8abcc2e | ||
|
|
1651d5e119 | ||
|
|
64bf6d6a35 | ||
|
|
47b0a917a2 | ||
|
|
2fe1a349c3 | ||
|
|
f168a8fd0d | ||
|
|
dda98c1dda | ||
|
|
88a13c5416 | ||
|
|
16b8f5da35 | ||
|
|
3471f6d206 | ||
|
|
0bf4c84bc8 | ||
|
|
d366336ee5 | ||
|
|
bf3f8ecff5 | ||
|
|
7524903aea | ||
|
|
90cf3fddc9 | ||
|
|
8e0f9f7591 | ||
|
|
24936c0a41 | ||
|
|
f02a552cdf | ||
|
|
5a5cb7ffbd | ||
|
|
f85fa772bf | ||
|
|
9f9ec8ef9f | ||
|
|
62707caf64 | ||
|
|
c6fc7a032d | ||
|
|
10faa1fae6 | ||
|
|
764f5ce4d4 | ||
|
|
65ba231fc0 | ||
|
|
1da2382e45 | ||
|
|
a86af94a8c | ||
|
|
8301cb634e | ||
|
|
721654d033 | ||
|
|
fe1817ef02 | ||
|
|
fc996659f2 | ||
|
|
368d22baa6 | ||
|
|
daf3d97266 | ||
|
|
f2179fca2d | ||
|
|
2c436c3af5 | ||
|
|
8d334ff2e8 | ||
|
|
f3e4696498 | ||
|
|
221260fa44 | ||
|
|
f8e7a79e9a | ||
|
|
b66f18bfd6 | ||
|
|
ac6708e0d0 | ||
|
|
a5f46c095d | ||
|
|
3ac7ea6e60 | ||
|
|
b2e0271ce7 | ||
|
|
c7a7651602 | ||
|
|
1e6678cbb4 | ||
|
|
a6e4e181bf | ||
|
|
b8e1dffca2 | ||
|
|
7e8ed72b7b | ||
|
|
ec8dd30a04 | ||
|
|
f81d5c9f3a | ||
|
|
74b24b1db1 | ||
|
|
179ef8c8a0 | ||
|
|
f77f3c3d6e | ||
|
|
9a7646195c | ||
|
|
84d3578e33 | ||
|
|
ef05b81014 | ||
|
|
726c682984 | ||
|
|
0c22a99fdf | ||
|
|
c062c8e001 | ||
|
|
06f3c000f5 | ||
|
|
8c0232fdb8 | ||
|
|
2470486f20 | ||
|
|
8fbf0374dd | ||
|
|
dd8fff0277 | ||
|
|
73b3d1d977 | ||
|
|
2a76ae2192 | ||
|
|
39931a3a2c | ||
|
|
58eb49617b | ||
|
|
9b621d2ec7 | ||
|
|
f2e8b652fa | ||
|
|
f342d9d561 | ||
|
|
8009bdf099 | ||
|
|
7336ce81bd | ||
|
|
f805bec8f2 | ||
|
|
46cdc84e6b | ||
|
|
e908d16ba8 | ||
|
|
96e3f4138f | ||
|
|
977dd52890 | ||
|
|
a9b7bb2175 | ||
|
|
f83c7fdac8 | ||
|
|
a695fb59b2 | ||
|
|
e197bb2900 | ||
|
|
b54b8815d9 | ||
|
|
1d1fde61be | ||
|
|
683186cbe9 | ||
|
|
5e6be40454 | ||
|
|
c00febd95b | ||
|
|
4c8e1113bf | ||
|
|
6f854da70b | ||
|
|
3f5a162a4e | ||
|
|
d14529b602 | ||
|
|
f471961f06 | ||
|
|
457c1356a4 | ||
|
|
419ac2bf50 | ||
|
|
727d088577 | ||
|
|
972d2dcc6b | ||
|
|
a5bcd49ecb | ||
|
|
ff496ad2d3 | ||
|
|
24d438ba23 | ||
|
|
591067e39e | ||
|
|
38a95dc5c4 | ||
|
|
53426d8493 | ||
|
|
a06238558e | ||
|
|
b3a3b19d5d | ||
|
|
57231c80a8 | ||
|
|
dc96fb9ad5 | ||
|
|
567847b47a | ||
|
|
b74fed7073 | ||
|
|
cdaf8ee6d5 | ||
|
|
c6c5073e47 | ||
|
|
2a58b954e9 | ||
|
|
9772623880 | ||
|
|
27b6183aad | ||
|
|
55e19618f8 | ||
|
|
5c60ba4d7f | ||
|
|
b9cc584086 | ||
|
|
bf5a8c2fad | ||
|
|
66138e5ea2 | ||
|
|
75fb89ef76 | ||
|
|
a2cb468222 | ||
|
|
166bcd7c45 | ||
|
|
95aed6af54 | ||
|
|
7a697c12af | ||
|
|
23278ce30b | ||
|
|
36a5610e25 | ||
|
|
08263c4588 | ||
|
|
1e88a52208 | ||
|
|
e770a42175 | ||
|
|
35b467c04f | ||
|
|
2001539755 | ||
|
|
e49c4bfe5a | ||
|
|
15be31fd5f | ||
|
|
4777ec46be | ||
|
|
80ab731aec | ||
|
|
080bafe18f | ||
|
|
e913f88f52 | ||
|
|
e94c5484a0 | ||
|
|
4af00c51d3 | ||
|
|
23d1256dbf | ||
|
|
ed0ef46d2e | ||
|
|
1860ded735 | ||
|
|
d432854b82 | ||
|
|
93582c8ea3 | ||
|
|
520d35b1d6 | ||
|
|
8ca3599cbf | ||
|
|
283ae74219 | ||
|
|
cebd3f92a4 | ||
|
|
4b2481d3ea | ||
|
|
f1f2a416d3 | ||
|
|
74dd97a55f | ||
|
|
3f04f7f363 | ||
|
|
800f854a12 | ||
|
|
bef9e6d54f | ||
|
|
0e4c0ae6c3 | ||
|
|
a0ea9887df | ||
|
|
0413c22e6e | ||
|
|
989ae44a6d | ||
|
|
100d314e63 | ||
|
|
dbf4e99187 | ||
|
|
7b8a85106c | ||
|
|
58c5f01e2b | ||
|
|
bc74d35651 | ||
|
|
a1f95bf25e | ||
|
|
c454e1f8a7 | ||
|
|
5a3669e1db | ||
|
|
7a2e0b3695 | ||
|
|
ce6d6269cd | ||
|
|
7d800b7080 | ||
|
|
136154e247 | ||
|
|
0a5ce1bee8 | ||
|
|
b4e2c89e2d | ||
|
|
9e2923f571 | ||
|
|
d0c1ae76f4 | ||
|
|
fe9500e6d0 | ||
|
|
79f7c73983 | ||
|
|
d04954e46f | ||
|
|
88c6ec358c | ||
|
|
d3ea01b76e | ||
|
|
0c1a9786a3 | ||
|
|
db298a349e | ||
|
|
c1bed9f578 | ||
|
|
c7cbe4ead8 | ||
|
|
4064aaf714 | ||
|
|
6ad808003a | ||
|
|
70de6101db | ||
|
|
933595ceea | ||
|
|
461c2aef60 | ||
|
|
0c49b6514c | ||
|
|
0ec425928b | ||
|
|
711701932a | ||
|
|
951e517caf | ||
|
|
8cef603d1c | ||
|
|
2a64a02211 | ||
|
|
67ef0cd5d9 | ||
|
|
9f2334362a | ||
|
|
44ff304423 | ||
|
|
f9c70d2a2b | ||
|
|
e51f7f11f1 | ||
|
|
54ef0e7465 | ||
|
|
63def00626 | ||
|
|
335c4de109 | ||
|
|
a120c2aaee | ||
|
|
43408fcb87 | ||
|
|
8432f7b0d5 | ||
|
|
bdd7884f42 | ||
|
|
485e62b5d6 | ||
|
|
0557e6cd08 | ||
|
|
b821702b8d | ||
|
|
c5b23c321e | ||
|
|
964d2d00a2 | ||
|
|
1778afa17d | ||
|
|
0d9f9982b7 | ||
|
|
7178085680 | ||
|
|
4d82b86f81 | ||
|
|
1d99a5c5a4 | ||
|
|
41a7f2c97e | ||
|
|
c8d01828b3 | ||
|
|
a3dbd4538f | ||
|
|
3051412d90 | ||
|
|
a22eb555d0 | ||
|
|
cb89300027 | ||
|
|
27cb0d062d | ||
|
|
140c1dd965 | ||
|
|
75b9e748f4 | ||
|
|
289c0253b1 | ||
|
|
07ce758302 | ||
|
|
d91729f65d | ||
|
|
9e64d09e07 | ||
|
|
5f63d5c35f | ||
|
|
23e1ab4bfd | ||
|
|
0e2900d796 | ||
|
|
a46e086dc4 | ||
|
|
40ca179509 | ||
|
|
7632910027 | ||
|
|
ca777d7967 | ||
|
|
a315c7c11e | ||
|
|
35f3f53443 | ||
|
|
40f5596837 | ||
|
|
43c978e41a | ||
|
|
6120a465e1 | ||
|
|
8bb884374b | ||
|
|
3d8db775f7 | ||
|
|
b3b8f6b154 | ||
|
|
e4c80582a5 | ||
|
|
1846427859 | ||
|
|
82102340b8 | ||
|
|
d9e884b8bd | ||
|
|
6744c7886a | ||
|
|
271b4ee095 | ||
|
|
7cfdd331ca | ||
|
|
7e15faa9a8 | ||
|
|
1292c86b76 | ||
|
|
0260a73cb6 | ||
|
|
085fdaf177 | ||
|
|
a4b49dfa27 | ||
|
|
d056151852 | ||
|
|
f9ba6f9a3a | ||
|
|
2fa4345742 | ||
|
|
d9147327c1 | ||
|
|
5ad9a611f9 | ||
|
|
3fb497b651 | ||
|
|
fbfe5d1ff8 | ||
|
|
b6f21f8649 | ||
|
|
8fd04807c7 | ||
|
|
e49c42302a | ||
|
|
d96abece75 | ||
|
|
c953da637e | ||
|
|
8d39b0a996 | ||
|
|
0efcf1eeb3 | ||
|
|
335cef870f | ||
|
|
4c40962f04 | ||
|
|
9be0d22cfb | ||
|
|
2893d73fad | ||
|
|
33d66ea9d1 | ||
|
|
073ea9c550 | ||
|
|
8467934021 | ||
|
|
96ba63407f | ||
|
|
88df6ffc6e | ||
|
|
3efcfec300 | ||
|
|
e51eb00889 | ||
|
|
9ae27ddcdd | ||
|
|
b9516e64a3 | ||
|
|
f7f5552bf0 | ||
|
|
adec2ab1b8 | ||
|
|
da6d7284f8 | ||
|
|
1c160fea5a | ||
|
|
cc87de76d7 | ||
|
|
70b380e6e7 | ||
|
|
3e419d3e3a | ||
|
|
7e2be20b6e | ||
|
|
ab2d5fb4c8 | ||
|
|
809901ff13 | ||
|
|
fcc58d77e8 | ||
|
|
bc93a82b1a | ||
|
|
84e1e12b66 | ||
|
|
2eb0c12213 | ||
|
|
4941134ce1 | ||
|
|
cf37fda3f4 | ||
|
|
f429811f79 | ||
|
|
70fd988d8c | ||
|
|
fe4167ed60 | ||
|
|
0eef69a277 | ||
|
|
76bfd805c0 | ||
|
|
971e2dc91b | ||
|
|
5821dc96b9 | ||
|
|
e027110006 | ||
|
|
b5e6e9a66c | ||
|
|
514047e680 | ||
|
|
a727a98a21 | ||
|
|
e75b5e8b30 | ||
|
|
ad0e085ff5 | ||
|
|
322a2f500d | ||
|
|
1c7454d249 | ||
|
|
e1efca6736 | ||
|
|
8ae61074ad | ||
|
|
c3bc0c4975 | ||
|
|
611bba272a | ||
|
|
4c9ec38c88 | ||
|
|
e2731a99be | ||
|
|
7d56df3b23 | ||
|
|
bebef48332 | ||
|
|
f66ea12fbf | ||
|
|
b08f1580f9 | ||
|
|
707912f7ad | ||
|
|
5ce31b16d4 | ||
|
|
a5945b1d5d | ||
|
|
b8577ae6d0 | ||
|
|
14dedb7b9a | ||
|
|
2dbd543127 | ||
|
|
cc989af1c6 | ||
|
|
0aad285f35 | ||
|
|
a3754e31f2 | ||
|
|
1dd0f3f609 | ||
|
|
f9b381b10a | ||
|
|
6e2d7a89f8 | ||
|
|
dfa336239f | ||
|
|
3a28dd0d55 | ||
|
|
502e9daaf2 | ||
|
|
b7c92aec3d | ||
|
|
c0341458c3 | ||
|
|
aecac211d9 | ||
|
|
c46b235eff | ||
|
|
a585447dc9 | ||
|
|
85bb05d90e | ||
|
|
027dd1eba9 | ||
|
|
588d5c5cfa | ||
|
|
7ba86f7cf2 | ||
|
|
609dc233a8 | ||
|
|
5d7c287821 | ||
|
|
ff325057c4 | ||
|
|
cc6469851b | ||
|
|
7f31104439 | ||
|
|
2ab98a922d | ||
|
|
063c1825ca | ||
|
|
d0e9c6a218 | ||
|
|
81d829f74e | ||
|
|
b4a0d9f5ea | ||
|
|
f0044aba91 | ||
|
|
6f322dcfb2 | ||
|
|
a391a25b7f | ||
|
|
4af350bd14 | ||
|
|
cdb319f0ef | ||
|
|
60ed64cb37 | ||
|
|
79efe006ec | ||
|
|
70f929949d | ||
|
|
d7916eb3ee | ||
|
|
f724982776 | ||
|
|
182a47697e | ||
|
|
d6b37bdf83 | ||
|
|
0bc2dc7d4c | ||
|
|
1263f0f049 | ||
|
|
f4b32e89f5 | ||
|
|
54711a96d3 | ||
|
|
6ca5ec986c | ||
|
|
40029edca8 | ||
|
|
4159af9002 | ||
|
|
b0dae02c42 | ||
|
|
0322b37ae7 | ||
|
|
58760fe001 | ||
|
|
99f3bc8c54 | ||
|
|
d3bf219129 | ||
|
|
57813179b2 | ||
|
|
c410700433 | ||
|
|
697e4dd0da | ||
|
|
60dfe6308e | ||
|
|
002d7d9f27 | ||
|
|
2dceccfa78 | ||
|
|
5cf9d14237 | ||
|
|
bdd4370fe3 | ||
|
|
63b08af3d2 | ||
|
|
983306ed86 | ||
|
|
15973c8992 | ||
|
|
b49a52057a | ||
|
|
82151872fd | ||
|
|
709d4151f2 | ||
|
|
d8e3f127c0 | ||
|
|
f4e422a239 | ||
|
|
442f24124c | ||
|
|
259814f4d9 | ||
|
|
41a860ebb9 | ||
|
|
2584fe9b7b | ||
|
|
f815415eb0 | ||
|
|
cf81d1699b | ||
|
|
0f3f79ab2c | ||
|
|
de9576835c | ||
|
|
7e7951df09 | ||
|
|
632cf10096 | ||
|
|
d2b6d06da5 | ||
|
|
b41f3e9d1f | ||
|
|
8357d9c7e7 | ||
|
|
97f1834c4d | ||
|
|
01f551a951 | ||
|
|
482d454fc3 | ||
|
|
7341f742de | ||
|
|
ffb2d6a10c | ||
|
|
56c96923c4 | ||
|
|
e4e850717d | ||
|
|
2953418683 | ||
|
|
5c142a61f6 | ||
|
|
74626184b2 | ||
|
|
019fdd3a12 | ||
|
|
119edbdb9d | ||
|
|
e8237cc04f | ||
|
|
95ee163d8b | ||
|
|
9a22f9735a | ||
|
|
29dbd5ac5d | ||
|
|
8661e1fd3f | ||
|
|
9569b1b0d5 | ||
|
|
3eb9bc1d16 | ||
|
|
ec6a8f5ea2 | ||
|
|
d6ba567763 | ||
|
|
6826fe1015 | ||
|
|
e67860cbe3 | ||
|
|
b41238ddbb | ||
|
|
c0b1c3d3ee | ||
|
|
ae69fcb80a | ||
|
|
6c4c33f1f3 | ||
|
|
2986290947 | ||
|
|
376cb9ebcb | ||
|
|
5cf5629232 | ||
|
|
98aa5e9da9 | ||
|
|
ed1df5bcbb | ||
|
|
6704ccc6a7 | ||
|
|
5f35e3c944 | ||
|
|
0893972115 | ||
|
|
7a8d1b85a9 | ||
|
|
686593e9e8 | ||
|
|
d05b593432 | ||
|
|
b581c893ec | ||
|
|
63f852475d | ||
|
|
51364763fb | ||
|
|
ea408fd4c7 | ||
|
|
8dc521ca8b | ||
|
|
6680e2ea75 | ||
|
|
da30df3b2b | ||
|
|
d12ea89388 | ||
|
|
e0931e41e5 | ||
|
|
c98d258127 | ||
|
|
a4922a5b1d | ||
|
|
edb2a69f6e | ||
|
|
b94f852b67 | ||
|
|
a8778ef14c | ||
|
|
cbfce0d14d | ||
|
|
abb25d397a | ||
|
|
969a3c8b8d | ||
|
|
2a6d38eef2 | ||
|
|
d84080fb76 | ||
|
|
54d7a6fb42 | ||
|
|
e5356e7118 | ||
|
|
e83556cada | ||
|
|
201a2826ab | ||
|
|
670bac52f8 | ||
|
|
77e3346d9e | ||
|
|
4663162f95 | ||
|
|
83a3ef43bd | ||
|
|
3701b314a0 | ||
|
|
4fa9f739d4 | ||
|
|
fad8358a9d | ||
|
|
78c4dbb44d | ||
|
|
9c74520a4b | ||
|
|
c911c710d5 | ||
|
|
f08dd01035 | ||
|
|
a1b4af2716 | ||
|
|
8c500c5836 | ||
|
|
c1d6cc7b75 | ||
|
|
d6fe16ffda | ||
|
|
d0230491e5 | ||
|
|
ba0509dadc | ||
|
|
3526f71f0a | ||
|
|
64c67e3755 | ||
|
|
6142dd34f4 | ||
|
|
06e265ec47 | ||
|
|
7b19973836 | ||
|
|
18f943ab2b | ||
|
|
03ff53c7af | ||
|
|
c20d111ea2 | ||
|
|
920fa73d11 | ||
|
|
cd62686337 | ||
|
|
e9ad459fa5 | ||
|
|
ea5e9fa75a | ||
|
|
d44460e180 | ||
|
|
0e5ebf3fea | ||
|
|
42d35f8ec6 | ||
|
|
7f52e466e0 | ||
|
|
861a8a4ee5 | ||
|
|
abe2f76d5c | ||
|
|
d0f75a940c | ||
|
|
44ad78b5e0 | ||
|
|
967b4de784 | ||
|
|
ea45201905 | ||
|
|
938f4ec9c2 | ||
|
|
99bd2972d0 | ||
|
|
deac291951 | ||
|
|
3161e24677 | ||
|
|
37804bd083 | ||
|
|
0a2a987695 | ||
|
|
4a085cb819 | ||
|
|
67469ef4d3 | ||
|
|
c3f43d503f | ||
|
|
9158f46bb3 | ||
|
|
b3bfa88eb5 |
@@ -0,0 +1,13 @@
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
spaces_around_operators = true
|
||||
max_line_length = 130
|
||||
+2
-1
@@ -13,10 +13,11 @@ ebean-profiling*.xml
|
||||
/db
|
||||
/mydb.db
|
||||
!src/test/ddl-review/*.sql
|
||||
|
||||
profiling/
|
||||
|
||||
# Intellij project files
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
*uuid.state
|
||||
+13
-1
@@ -1,3 +1,4 @@
|
||||
dist: trusty
|
||||
sudo: required
|
||||
language: java
|
||||
jdk:
|
||||
@@ -7,17 +8,28 @@ git:
|
||||
depth: 3
|
||||
|
||||
addons:
|
||||
postgresql: "9.4"
|
||||
postgresql: "9.6"
|
||||
# apt:
|
||||
# packages:
|
||||
# - mysql-server-5.7
|
||||
# - mysql-client-core-5.7
|
||||
# - mysql-client-5.7
|
||||
|
||||
services:
|
||||
- docker
|
||||
- postgresql
|
||||
- mysql
|
||||
|
||||
before_script:
|
||||
- ./.travis/setup_database
|
||||
- mysql -u root -e 'CREATE DATABASE test_ebean;'
|
||||
- mysql -u root -e "CREATE USER 'test_ebean'@'localhost' IDENTIFIED BY 'test';"
|
||||
- mysql -u root -e "GRANT ALL ON test_ebean.* TO 'test_ebean'@'localhost';"
|
||||
|
||||
env:
|
||||
- EBEAN_DB=h2
|
||||
- EBEAN_DB=pg
|
||||
# - EBEAN_DB=mysql
|
||||
|
||||
install: true
|
||||
|
||||
|
||||
@@ -0,0 +1,298 @@
|
||||
Overview of ebean.properties file
|
||||
=================================
|
||||
|
||||
|
||||
### DbMigration options
|
||||
|
||||
You can set individual values for different platforms when generating migrations
|
||||
|
||||
`dbmigration.platform.<PLATFORM>.databaseSequenceBatchSize`
|
||||
For DB's using sequences this is the number of sequence values prefetched.
|
||||
|
||||
`dbmigration.platform.<PLATFORM>.dbuuid`
|
||||
Control, how UUID generation should work - it affects DDL which column type is generated. Possible values:
|
||||
- BINARY enforces binary UUID
|
||||
- VARCHAR enforces varchar UUID
|
||||
- BINARY_OPTIMIZED enforces binary-optimized UUID (makes sense only with Type1 ID)
|
||||
- AUTO_BINARY use binary when platform does not support native UUID
|
||||
- AUTO_BINARY_OPTIMIZED use binary-optimized when platform does not support native UUID
|
||||
- AUTO_VARCHAR (default) use varchar when platform does not support UUID
|
||||
|
||||
`dbmigration.platform.<PLATFORM>.uuidStoreAsBinary`
|
||||
Same as setting dbuuid to BINARY
|
||||
|
||||
`dbmigration.platform.<PLATFORM>.geometrySRID`
|
||||
The Geometry SRID value (default 4326).
|
||||
|
||||
`dbmigration.platform.<PLATFORM>.idType`
|
||||
The ID type (IDENTITY, SEQUENCE, GENERATOR, EXTERNAL)
|
||||
|
||||
`dbmigration.platform.<PLATFORM>.mapping`
|
||||
Adjust the mapping. For example `BOOLEAN=integer(32);BIT=tinyint(3)`
|
||||
|
||||
|
||||
`ebean.migration.applyPrefix`
|
||||
Set this to "V" to be compatible with FlywayDB.
|
||||
|
||||
`ebean.migration.applySuffix`
|
||||
Defaults to '.sql'
|
||||
|
||||
`ebean.migration.dbusername`
|
||||
DB user used to run the DB migration.
|
||||
|
||||
`ebean.migration.dbpassword`
|
||||
DB password used to run the DB migration.
|
||||
|
||||
`ebean.migration.generate`
|
||||
Set to true if the DB migration should be generated on server start.
|
||||
|
||||
`ebean.migration.generatePendingDrop`
|
||||
The version of a pending drop that should be generated as the next migration.
|
||||
|
||||
`ebean.migration.includeGeneratedFileComment`
|
||||
TODO
|
||||
|
||||
`ebean.migration.metaTable`
|
||||
For running migration the DB table that holds migration execution status. Default 'db_migration'
|
||||
|
||||
`ebean.migration.migrationPath`
|
||||
Resource path for the migration xml and sql.
|
||||
|
||||
`ebean.migration.modelPath`
|
||||
Subdirectory the model xml files go into. Default 'model'
|
||||
|
||||
`ebean.migration.modelSuffix`
|
||||
Suffix. Default '.model.xml'
|
||||
|
||||
`ebean.migration.name`
|
||||
Description text that can be appended to the version to become the ddl script file name
|
||||
|
||||
`ebean.migration.patchInsertOn`
|
||||
migration versions that should be added to history without running.
|
||||
|
||||
`ebean.migration.patchResetChecksumOn`
|
||||
migration versions that should have their checksum reset and not run.
|
||||
Use this if you get a 'Checksum mismatch' error.
|
||||
|
||||
`ebean.migration.placeholders`
|
||||
A comma and equals delimited placeholders that are substituted in SQL scripts when running migration (used by DB Migration runner only).
|
||||
|
||||
`ebean.migration.platform`
|
||||
The database platform to generate migration DDL for.
|
||||
|
||||
`ebean.migration.run`
|
||||
Flag set to true means to run any outstanding migrations on startup.
|
||||
|
||||
`ebean.migration.version`
|
||||
The migration version name (typically FlywayDb compatible). Example: 1.1.1_2
|
||||
|
||||
|
||||
### Ebean UUID options
|
||||
|
||||
`ebean.uuidVersion`
|
||||
Controls, how the UUIDs are generated. Possible values
|
||||
- VERSION4 (default) generate random V4 UUIDs,
|
||||
- VERSION1 generate rfc4122 compliant Type 1 UUIDs (requires a state file)
|
||||
- VERSION1RND generate fake Type 1 UUIDs
|
||||
|
||||
Note, that V1 UUIDs in conjunction with AUTO_BINARY_OPTIMIZED will give you the best index performance, but you MUST understand how this works to avoid collisions.
|
||||
|
||||
`ebean.uuidStateFile`
|
||||
The state file that is Required to generate V1 UUIDs
|
||||
|
||||
|
||||
### DocStoreConfig
|
||||
|
||||
`ebean.docstore.active`
|
||||
True when the Document store integration is active/on.
|
||||
|
||||
`ebean.docstore.allowAllCertificates`
|
||||
Set to true such that the client allows connections to invalid/self signed SSL certificates.
|
||||
|
||||
`ebean.docstore.bulkBatchSize`
|
||||
The default batch size to use for the Bulk API calls.
|
||||
|
||||
`ebean.docstore.create`
|
||||
When true the Document store should create any document indexes that don't already exist.
|
||||
|
||||
`ebean.docstore.dropCreate`
|
||||
When true the Document store should drop and re-create document indexes.
|
||||
|
||||
`ebean.docstore.generateMapping`
|
||||
Set to true means Ebean will generate mapping files on startup.
|
||||
|
||||
`ebean.docstore.mappingPath`
|
||||
Resource path for the Document store mapping files.
|
||||
|
||||
`ebean.docstore.mappingSuffix`
|
||||
Suffix used for mapping files.
|
||||
|
||||
`ebean.docstore.password`
|
||||
Password credential that be used for authentication to document store.
|
||||
|
||||
`ebean.docstore.pathToResources`
|
||||
Location of resources that mapping files are generated into.
|
||||
|
||||
`ebean.docstore.persist`
|
||||
The default mode used by indexes. `DEFAULT|IGNORE|QUEUE|UPDATE`
|
||||
|
||||
`ebean.docstore.url`
|
||||
The URL of the Document store server. For example: http://localhost:9200.
|
||||
|
||||
`ebean.docstore.username`
|
||||
Credential that be used for authentication to document store.
|
||||
|
||||
### Ebean Autotune
|
||||
|
||||
`ebean.autoTune.mode`
|
||||
The autoTune mode `DEFAULT_OFF|DEFAULT_ON|DEFAULT_ONIFEMPTY`
|
||||
|
||||
`ebean.autoTune.profiling`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.profilingBase`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.profilingFile`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.profilingRate`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.profilingUpdateFrequency`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.queryTuning`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.queryTuningAddVersion`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.queryTuningFile`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.skipGarbageCollectionOnShutdown`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.skipProfileReportingOnShutdown`
|
||||
TODO
|
||||
|
||||
|
||||
### Ebean options
|
||||
`ebean.allQuotedIdentifiers`
|
||||
Quote all identifiers
|
||||
|
||||
`ebean.asOfSysPeriod`
|
||||
Column used to support history and 'As of' queries. This column is a timestamp range or equivalent.
|
||||
|
||||
`ebean.asOfViewSuffix`
|
||||
Suffix appended to the base table to derive the view that contains the union of the base table and the history table in order to support asOf queries.
|
||||
|
||||
`ebean.autoCommitMode`
|
||||
Set to true if the DataSource uses autoCommit. Indicates that Ebean should use autoCommit friendly Transactions and TransactionManager.
|
||||
|
||||
`ebean.autoReadOnlyDataSource`
|
||||
When true create a read only DataSource using readOnlyDataSourceConfig defaulting values from dataSourceConfig
|
||||
|
||||
`ebean.autostart`
|
||||
Should the server start all
|
||||
|
||||
`ebean.backgroundExecutorSchedulePoolSize`
|
||||
TODO
|
||||
|
||||
`ebean.backgroundExecutorShutdownSecs`
|
||||
TODO
|
||||
|
||||
and some more todos:
|
||||
`ebean.batch.mode`
|
||||
`ebean.batch.size`
|
||||
`ebean.changeLogAsync`
|
||||
`ebean.changeLogIncludeInserts`
|
||||
`ebean.classes`
|
||||
`ebean.collectQueryOrigins`
|
||||
`ebean.collectQueryStatsByNode`
|
||||
`ebean.currentUserProvider`
|
||||
`ebean.dataSourceJndiName`
|
||||
`ebean.dataTimeZone`
|
||||
`ebean.databaseBooleanFalse`
|
||||
`ebean.databaseBooleanTrue`
|
||||
`ebean.databasePlatform`
|
||||
`ebean.databasePlatformName`
|
||||
`ebean.databaseSequenceBatchSize`
|
||||
ebean.datasource.h2.adminpassword
|
||||
ebean.datasource.h2.adminusername
|
||||
`ebean.dbEncrypt`
|
||||
`ebean.dbOffline`
|
||||
ebean.ddl.createOnly
|
||||
ebean.ddl.generate
|
||||
ebean.ddl.header
|
||||
ebean.ddl.initSql
|
||||
ebean.ddl.run
|
||||
ebean.ddl.seedSql
|
||||
ebean.defaultDeleteMissingChildren
|
||||
ebean.defaultOrderById
|
||||
ebean.disableClasspathSearch
|
||||
ebean.disableL2Cache
|
||||
ebean.docStoreOnly
|
||||
ebean.docstore.active
|
||||
ebean.docstore.allowAllCertificates
|
||||
ebean.docstore.bulkBatchSize
|
||||
ebean.docstore.create
|
||||
ebean.docstore.dropCreate
|
||||
ebean.docstore.generateMapping
|
||||
ebean.docstore.mappingPath
|
||||
ebean.docstore.mappingSuffix
|
||||
ebean.docstore.password
|
||||
ebean.docstore.pathToResources
|
||||
ebean.docstore.persist
|
||||
ebean.docstore.url
|
||||
ebean.docstore.username
|
||||
ebean.encryptDeployManager
|
||||
ebean.encryptKeyManager
|
||||
ebean.encryptor
|
||||
ebean.explicitTransactionBeginMode
|
||||
ebean.expressionEqualsWithNullAsNoop
|
||||
ebean.expressionNativeIlike
|
||||
ebean.geometrySRID
|
||||
ebean.historyTableSuffix
|
||||
ebean.jdbcFetchSizeFindEach
|
||||
ebean.jdbcFetchSizeFindList
|
||||
ebean.jodaLocalTimeMode
|
||||
ebean.jsonDateTime
|
||||
ebean.jsonInclude
|
||||
ebean.lazyLoadBatchSize
|
||||
ebean.localTimeWithNanos
|
||||
ebean.namingConvention.schema
|
||||
ebean.namingConvention.sequenceFormat
|
||||
ebean.namingConvention.useForeignKeyPrefix
|
||||
ebean.namingconvention
|
||||
ebean.notifyL2CacheInForeground
|
||||
ebean.packages
|
||||
ebean.persistBatch
|
||||
ebean.persistBatchOnCascade
|
||||
ebean.persistBatchSize
|
||||
ebean.persistBatching
|
||||
ebean.persistenceContextScope
|
||||
ebean.profiling
|
||||
ebean.profiling.directory
|
||||
ebean.profiling.includeProfileIds
|
||||
ebean.profiling.minimumMicros
|
||||
ebean.profiling.profilesPerFile
|
||||
ebean.profiling.verbose
|
||||
ebean.queryBatchSize
|
||||
ebean.queryPlanTTLSeconds
|
||||
ebean.search.packages
|
||||
ebean.serverCachePlugin
|
||||
ebean.skipCacheAfterWrite
|
||||
ebean.slowQueryMillis
|
||||
ebean.tenant.catalogProvider
|
||||
ebean.tenant.currentTenantProvider
|
||||
ebean.tenant.mode
|
||||
ebean.tenant.partitionColumn
|
||||
ebean.tenant.schemaProvider
|
||||
ebean.updateAllPropertiesInBatch
|
||||
ebean.updateChangesOnly
|
||||
ebean.updatesDeleteMissingChildren
|
||||
ebean.useJavaxValidationNotNull
|
||||
ebean.useJtaTransactionManager
|
||||
|
||||
@@ -6,12 +6,12 @@ Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Web
|
||||
|
||||
|
||||
## Maven cental links:
|
||||
[Maven central - ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebean%22%20AND%20a%3A%22ebean%22 "maven central ebean")
|
||||
[Maven central - ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.ebean%22%20AND%20a%3A%22ebean%22 "maven central ebean")
|
||||
|
||||
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
|
||||
|
||||
## Current versions
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean) - ebean
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent) - ebean-agent
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin) - ebean-maven-plugin
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean) - ebean
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent) - ebean-agent
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin) - ebean-maven-plugin
|
||||
|
||||
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
This is a short description how to run tests
|
||||
============================================
|
||||
|
||||
Run tests from maven
|
||||
--------------------
|
||||
|
||||
Just type `mvn test` - it will run the whole test suite with the settings
|
||||
from `src/test/resources/ebean.properties`.
|
||||
|
||||
Run tests from eclipse
|
||||
----------------------
|
||||
|
||||
Running tests requires, that the classes are enhanced. By default, the
|
||||
`BaseTestCase` tries to load the enhancer-agent in a very early stage. This
|
||||
also works for most test cases, but it does not work if you try to run a
|
||||
complete test-suite, as classes that are loaded before the enhancer-agent
|
||||
kicks in will not get enhanced. To solve this problem, you need either the
|
||||
[Eclipse-Enhancer-Plugin](https://github.com/ebean-orm-tools/ebean-eclipse-enhancer)
|
||||
or add the agent to your JVM arguments (Preferences->Installed JREs) or to
|
||||
your run configuration:
|
||||
`-javaagent:<USER_HOME>/.m2/repository/io/ebean/ebean-agent/<VERSION>/ebean-agent-<VERSION>.jar=debug=0`
|
||||
|
||||
|
||||
Platform Tests
|
||||
==============
|
||||
|
||||
By default, the `h2` platform is used. To test a different platform, add
|
||||
`-Ddatasource.default=xxx` to your maven command or JVM arguments.
|
||||
|
||||
'h2' platform
|
||||
-------------
|
||||
|
||||
Reqires no setup
|
||||
|
||||
run: `mvn clean test`
|
||||
|
||||
Current status: PASS
|
||||
Tests run: 1986, Failures: 0, Errors: 0, Skipped: 16
|
||||
|
||||
'pg' platform
|
||||
-------------
|
||||
|
||||
Reqirements
|
||||
- a locally installed PostgreSQL server with PostGis.
|
||||
- Create a user "unit" with password "unit" and a database "unit"
|
||||
- Give the user all permissions to that db
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=pg`
|
||||
|
||||
Current status: PASS
|
||||
Tests run: 2166, Failures: 0, Errors: 0, Skipped: 25
|
||||
|
||||
|
||||
|
||||
'mysql' platform
|
||||
-------------
|
||||
|
||||
Reqirements
|
||||
- a locally installed MySQL server.
|
||||
- Create a user "unit" with password "unit" and a database "unit"
|
||||
- Give the user all permissions to that db
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=mysql`
|
||||
|
||||
Current status: PASS
|
||||
Tests run: 2166, Failures: 0, Errors: 0, Skipped: 33
|
||||
|
||||
|
||||
|
||||
'sqlserver' platform
|
||||
--------------------
|
||||
|
||||
Reqires an installed sqlserver - e.g. https://hub.docker.com/r/microsoft/mssql-server-linux/
|
||||
|
||||
- Create a user "ebean" with password "ebean" and a database "ebean_unittest"
|
||||
- Adjust the connection string and/or username in ebean.properties
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=mssql`
|
||||
|
||||
Current status: PASS
|
||||
Tests run: 2166, Failures: 0, Errors: 0, Skipped: 39
|
||||
|
||||
|
||||
|
||||
'oracle' platform
|
||||
-----------------
|
||||
|
||||
Reqires a locally installed Oracle server.
|
||||
- Create a user "unit" with password "unit" with all permissions
|
||||
- The test wirtes directly to the "xe" SID - so do not use a productive server!
|
||||
- As the Oracle JDBC driver is only available on an oracle repository,
|
||||
you need a special maven setup as described [here](http://docs.oracle.com/middleware/1213/core/MAVEN/config_maven_repo.htm#MAVEN9010)
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=ora -Poracle`
|
||||
|
||||
Current status: FAIL
|
||||
Tests run: 1986, Failures: 17, Errors: 34, Skipped: 16
|
||||
|
||||
|
||||
|
||||
'db2' platform
|
||||
--------------
|
||||
|
||||
Reqires a locally installed DB2 Express-C server.
|
||||
- Create a user "unit" with password "unit" with all permissions
|
||||
- Install the db2jcc4 driver (see pom.xml)
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=db2 -Pdb2`
|
||||
|
||||
Current status: FAIL
|
||||
Tests run: 2166, Failures: 29, Errors: 58, Skipped: 30
|
||||
|
||||
|
||||
'sqlite' platform
|
||||
-----------------
|
||||
|
||||
Reqires no setup
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=sqlite`
|
||||
|
||||
Current status: FAIL
|
||||
Tests run: 1986, Failures: 24, Errors: 86, Skipped: 16
|
||||
|
||||
After some time, the db locks up, every test takes 3 seconds and fails with
|
||||
"the database file is locked"
|
||||
|
||||
|
||||
|
||||
'hsqldb' platform
|
||||
-----------------
|
||||
|
||||
Reqires no setup
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=hsqldb`
|
||||
|
||||
Current status: FAIL
|
||||
Tests run: 1980, Failures: 3, Errors: 657, Skipped: 16
|
||||
|
||||
|
||||
@Rob FYI
|
||||
The problem is https://sourceforge.net/p/hsqldb/bugs/1364/
|
||||
In `InsertHandler.getPstmt` the `meta.getIdentityDbColumns()` contains
|
||||
'id' in lowercase. Changing that to uppercase gives me this result:
|
||||
`Tests run: 1986, Failures: 2, Errors: 18, Skipped: 16`
|
||||
(as quick hack I added temporary a toUpperCase to BindableIdScalar.getIdentityColumn)
|
||||
|
||||
|
||||
'sqlanywhere' platform
|
||||
----------------------
|
||||
|
||||
TODO: not yet tested
|
||||
|
||||
|
||||
@@ -3,111 +3,154 @@
|
||||
|
||||
<parent>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>oss-parent</artifactId>
|
||||
<version>1.1</version>
|
||||
<artifactId>java8-parent</artifactId>
|
||||
<version>1.3</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>8.4.2</version>
|
||||
<version>11.14.3</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
<url>http://ebean-orm.github.io/</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>rbygrave</id>
|
||||
<name>Rob Bygrave</name>
|
||||
<email>robin.bygrave@gmail.com</email>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:https://github.com/ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-8.4.2</tag>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-11.14.3</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<!-- Note: to use this profile, you need credentials for the oracle repository in your
|
||||
settings.xml as described here:
|
||||
http://docs.oracle.com/middleware/1213/core/MAVEN/config_maven_repo.htm#MAVEN9010 -->
|
||||
<id>oracle</id>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.oracle.jdbc</groupId>
|
||||
<artifactId>ojdbc8</artifactId>
|
||||
<version>12.2.0.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>maven.oracle.com</id>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<url>https://maven.oracle.com</url>
|
||||
<layout>default</layout>
|
||||
</repository>
|
||||
</repositories>
|
||||
</profile>
|
||||
<profile>
|
||||
<!-- Note: to use this profile, you need to download manually the db2jcc4 driver.
|
||||
After that, install it into your local maven repository:
|
||||
|
||||
mvn install:install-file \
|
||||
-Dfile=db2jcc4.jar \
|
||||
-DgroupId=com.ibm.jdbc \
|
||||
-DartifactId=db2jcc4 \
|
||||
-Dversion=4.23.42 \
|
||||
-Dpackaging=jar
|
||||
-->
|
||||
<id>db2</id>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.ibm.jdbc</groupId>
|
||||
<artifactId>db2jcc4</artifactId>
|
||||
<version>4.23.42</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
<dependencies>
|
||||
|
||||
<!--
|
||||
Projects are expected to explicit depend on version
|
||||
of slf4j that they want to use
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>13.0</version>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.25</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
Exclude snakeyaml if you desire - it is not strictly required.
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>1.0</version>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>1.19</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
Class retention Nonnull and Nullable annotations
|
||||
to assist with IDE auto-completion with Ebean API
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-datasource-api</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-jsr305</artifactId>
|
||||
<version>1.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>2.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>3.8</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-datasource</artifactId>
|
||||
<version>1.1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-classpath-scanner-api</artifactId>
|
||||
<version>2.2</version>
|
||||
<version>3.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-classpath-scanner</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<version>3.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-dbmigration</artifactId>
|
||||
<version>1.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>[1.7.1,1.7.99)</version>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>11.3.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-runtime</artifactId>
|
||||
<version>4.5.3</version>
|
||||
<version>4.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.6.5</version>
|
||||
<version>2.9.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope for JsonNode support -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.6.5</version>
|
||||
<version>2.9.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -122,21 +165,21 @@
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>1.0.0.GA</version>
|
||||
<version>1.1.0.Final</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.4</version>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>1.6</version>
|
||||
<version>2.9.7</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -144,7 +187,7 @@
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>9.4-1202-jdbc41</version>
|
||||
<version>9.4.1212</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -157,24 +200,31 @@
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>microsoft</groupId>-->
|
||||
<!--<artifactId>sqlserver-jdbc</artifactId>-->
|
||||
<!--<version>4.2</version>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-agentloader</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-docker-run</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.3</version>
|
||||
<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>8.1.1</version>
|
||||
<version>11.10.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -183,28 +233,36 @@
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.192</version>
|
||||
<version>1.4.196</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.8.11.2</version>
|
||||
<version>3.15.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>2.3.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
<version>6.1.3.jre8-preview</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.36</version>
|
||||
<!-- Do not upgrade to 6.0.6: https://bugs.mysql.com/bug.php?id=82896 -->
|
||||
<version>5.1.43</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -219,14 +277,14 @@
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
<version>2.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.moduuid</groupId>
|
||||
<artifactId>avaje-moduuid</artifactId>
|
||||
<version>1.2</version>
|
||||
<version>2.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -237,29 +295,18 @@
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.2</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>8.1.1</version>
|
||||
<version>11.10.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
<phase>process-test-classes</phase>
|
||||
<configuration>
|
||||
<classSource>target/test-classes</classSource>
|
||||
<transformArgs>debug=1</transformArgs>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>enhance</goal>
|
||||
<goal>testEnhance</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
@@ -283,6 +330,11 @@
|
||||
<name>datasource.default</name>
|
||||
<value>${datasource.default}</value>
|
||||
</property>
|
||||
<property>
|
||||
<!-- transfer dbClockDelta parameter -->
|
||||
<name>dbClockDelta</name>
|
||||
<value>${dbClockDelta}</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
@@ -303,11 +355,11 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<doctitle>Ebean 8</doctitle>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
<doctitle>Ebean 10</doctitle>
|
||||
<overview>src/main/java/io/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
<excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util:com.avaje.ebean.dbmigration.ddlgeneration:com.avaje.ebean.dbmigration.migration:com.avaje.ebean.dbmigration.migrationreader:com.avaje.ebean.dbmigration.model</excludePackageNames>
|
||||
<excludePackageNames>io.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
|
||||
<docletArtifact>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>pygments-doclet</artifactId>
|
||||
@@ -336,5 +388,5 @@
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* For making calls to stored procedures. Refer to the Ebean execute() method.
|
||||
* <p>
|
||||
* Note that UpdateSql is designed for general DML sql and CallableSql is
|
||||
* designed for use with stored procedures. Also note that when using this in
|
||||
* batch mode the out parameters are not read.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example 1:
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* String sql = "{call sp_order_mod(?,?)}";
|
||||
*
|
||||
* CallableSql cs = Ebean.createCallableSql(sql);
|
||||
* cs.setParameter(1, "turbo");
|
||||
* cs.registerOut(2, Types.INTEGER);
|
||||
*
|
||||
* Ebean.execute(cs);
|
||||
*
|
||||
* // read the out parameter
|
||||
* Integer returnValue = (Integer) cs.getObject(2);
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Example 2:<br>
|
||||
* Includes batch mode, table modification information and label. Note that the
|
||||
* label is really only to help people reading the transaction logs to identify
|
||||
* the procedure called etc.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* String sql = "{call sp_insert_order(?,?)}";
|
||||
*
|
||||
* CallableSql cs = Ebean.createCallableSql(sql);
|
||||
*
|
||||
* // Inform Ebean this stored procedure inserts into the
|
||||
* // oe_order table and inserts + updates the oe_order_detail table.
|
||||
* // this is used to invalidate objects in the cache
|
||||
* 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 {
|
||||
* cs.setParameter(1, "Was");
|
||||
* cs.setParameter(2, "Banana");
|
||||
* Ebean.execute(cs);
|
||||
*
|
||||
* cs.setParameter(1, "Here");
|
||||
* cs.setParameter(2, "Kumera");
|
||||
* Ebean.execute(cs);
|
||||
*
|
||||
* cs.setParameter(1, "More");
|
||||
* cs.setParameter(2, "Apple");
|
||||
* Ebean.execute(cs);
|
||||
*
|
||||
* // Ebean.externalModification("oe_order",true,false,false);
|
||||
* // Ebean.externalModification("oe_order_detail",true,true,false);
|
||||
* Ebean.commitTransaction();
|
||||
*
|
||||
* } finally {
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see com.avaje.ebean.SqlUpdate
|
||||
* @see com.avaje.ebean.Ebean#execute(CallableSql)
|
||||
*/
|
||||
public interface CallableSql {
|
||||
|
||||
/**
|
||||
* Return the label that is put into the transaction log.
|
||||
*/
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* Set the label that is put in the transaction log.
|
||||
*/
|
||||
CallableSql setLabel(String label);
|
||||
|
||||
/**
|
||||
* Return the statement execution timeout.
|
||||
*/
|
||||
int getTimeout();
|
||||
|
||||
/**
|
||||
* Return the callable sql.
|
||||
*/
|
||||
String getSql();
|
||||
|
||||
/**
|
||||
* Set the statement execution timeout. Zero implies unlimited time.
|
||||
* <p>
|
||||
* This is set to the underlying CallableStatement.
|
||||
* </p>
|
||||
*/
|
||||
CallableSql setTimeout(int secs);
|
||||
|
||||
/**
|
||||
* Set the callable sql.
|
||||
*/
|
||||
CallableSql setSql(String sql);
|
||||
|
||||
/**
|
||||
* Bind a parameter that is bound as a IN parameter.
|
||||
* <p>
|
||||
* position starts at value 1 (not 0) to be consistent with CallableStatement.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is designed so that you do not need to set params in index order. You
|
||||
* can set/register param 2 before param 1 etc.
|
||||
* </p>
|
||||
*
|
||||
* @param position
|
||||
* the index position of the parameter.
|
||||
* @param value
|
||||
* the value of the parameter.
|
||||
*/
|
||||
CallableSql bind(int position, Object value);
|
||||
|
||||
/**
|
||||
* Bind a positioned parameter (same as bind method).
|
||||
*
|
||||
* @param position
|
||||
* the index position of the parameter.
|
||||
* @param value
|
||||
* the value of the parameter.
|
||||
*/
|
||||
CallableSql setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Register an OUT parameter.
|
||||
* <p>
|
||||
* Note that position starts at value 1 (not 0) to be consistent with
|
||||
* CallableStatement.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is designed so that you do not need to register params in index order.
|
||||
* You can set/register param 2 before param 1 etc.
|
||||
* </p>
|
||||
*
|
||||
* @param position
|
||||
* the index position of the parameter (starts with 1).
|
||||
* @param type
|
||||
* the jdbc type of the OUT parameter that will be read.
|
||||
*/
|
||||
CallableSql registerOut(int position, int type);
|
||||
|
||||
/**
|
||||
* Return an OUT parameter value.
|
||||
* <p>
|
||||
* position starts at value 1 (not 0) to be consistent with CallableStatement.
|
||||
* </p>
|
||||
* <p>
|
||||
* This can only be called after the CallableSql has been executed. When run
|
||||
* in batch mode you effectively can't use this method.
|
||||
* </p>
|
||||
*/
|
||||
Object getObject(int position);
|
||||
|
||||
/**
|
||||
*
|
||||
* You can extend this object and override this method for more advanced
|
||||
* stored procedure calls. This would be the case when ResultSets are returned
|
||||
* etc.
|
||||
*/
|
||||
boolean executeOverride(CallableStatement cstmt) throws SQLException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* more sense to set it here with the CallableSql.
|
||||
* </p>
|
||||
* <p>
|
||||
* For UpdateSql the table modification information is derived by parsing the
|
||||
* sql to determine the table name and whether it was an insert, update or
|
||||
* delete.
|
||||
* </p>
|
||||
*/
|
||||
CallableSql addModification(String tableName, boolean inserts, boolean updates, boolean deletes);
|
||||
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.RawSql.ColumnMapping;
|
||||
|
||||
/**
|
||||
* Parses columnMapping (select clause) mapping columns to bean properties.
|
||||
*/
|
||||
final class DRawSqlColumnsParser {
|
||||
|
||||
private final int end;
|
||||
|
||||
private final String sqlSelect;
|
||||
|
||||
private int pos;
|
||||
|
||||
private int indexPos;
|
||||
|
||||
public static ColumnMapping parse(String sqlSelect) {
|
||||
return new DRawSqlColumnsParser(sqlSelect).parse();
|
||||
}
|
||||
|
||||
private DRawSqlColumnsParser(String sqlSelect) {
|
||||
this.sqlSelect = sqlSelect;
|
||||
this.end = sqlSelect.length();
|
||||
}
|
||||
|
||||
private ColumnMapping parse() {
|
||||
|
||||
ArrayList<ColumnMapping.Column> columns = new ArrayList<ColumnMapping.Column>();
|
||||
while (pos <= end) {
|
||||
ColumnMapping.Column c = nextColumnInfo();
|
||||
columns.add(c);
|
||||
}
|
||||
|
||||
return new ColumnMapping(columns);
|
||||
}
|
||||
|
||||
private ColumnMapping.Column nextColumnInfo() {
|
||||
int start = pos;
|
||||
nextComma();
|
||||
String colInfo = sqlSelect.substring(start, pos++);
|
||||
colInfo = colInfo.trim();
|
||||
|
||||
String[] split = colInfo.split("\\s(?=[^\\)]*(?:\\(|$))");
|
||||
if (split.length > 1) {
|
||||
ArrayList<String> tmp = new ArrayList<String>(split.length);
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
if (!split[i].trim().isEmpty()) {
|
||||
tmp.add(split[i].trim());
|
||||
}
|
||||
}
|
||||
split = tmp.toArray(new String[tmp.size()]);
|
||||
}
|
||||
|
||||
if (split.length == 0) {
|
||||
throw new PersistenceException("Huh? Not expecting length=0 when parsing column " + colInfo);
|
||||
}
|
||||
if (split.length == 1) {
|
||||
// default to column the same name as the property
|
||||
return new ColumnMapping.Column(indexPos++, split[0], null);
|
||||
}
|
||||
if (split.length == 2) {
|
||||
return new ColumnMapping.Column(indexPos++, split[0], split[1]);
|
||||
}
|
||||
// Ok, we now expect/require the AS keyword and it should be the
|
||||
// second to last word in the colInfo content
|
||||
if (!split[split.length - 2].equalsIgnoreCase("as")) {
|
||||
throw new PersistenceException("Expecting AS keyword as second to last word when parsing column " + colInfo);
|
||||
}
|
||||
// build back the 'column formula' that precedes the AS keyword
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(split[0]);
|
||||
for (int i = 1; i < split.length-2; i++) {
|
||||
sb.append(" ").append(split[i]);
|
||||
}
|
||||
return new ColumnMapping.Column(indexPos++, sb.toString(), split[split.length - 1]);
|
||||
}
|
||||
|
||||
private void nextComma() {
|
||||
boolean inQuote = false;
|
||||
int inbrackets = 0;
|
||||
while (pos < end) {
|
||||
char c = sqlSelect.charAt(pos);
|
||||
if (c == '\'') inQuote = !inQuote;
|
||||
else if (c == '(') inbrackets++;
|
||||
else if (c == ')') inbrackets--;
|
||||
else if (!inQuote && inbrackets == 0 && c == ',') {
|
||||
return;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Intended to be used as a base class for 'Finder' implementations that can then
|
||||
* be injected or used as public static fields on the associated entity bean.
|
||||
* <p>
|
||||
* These 'finders' are a place to organise all the finder methods for that bean type
|
||||
* and specific finder methods are expected to be added (find by unique properties etc).
|
||||
* </p>
|
||||
*
|
||||
* <h3>Testing</h3>
|
||||
* <p>
|
||||
* For testing the mocki-ebean project has the ability to replace the finder implementation
|
||||
*
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* public class CustomerFinder extends Finder<Customer> {
|
||||
*
|
||||
* public CustomerFinder() {
|
||||
* super(Customer.class);
|
||||
* }
|
||||
*
|
||||
* // Add your customer finder methods ...
|
||||
*
|
||||
* public Customer byName(String name) {
|
||||
* return query().eq("name", name).findUnique();
|
||||
* }
|
||||
*
|
||||
* public List<Customer> findNew() {
|
||||
* return query()
|
||||
* .eq("status", Customer.Status.NEW)
|
||||
* .orderBy("name")
|
||||
* .findList()
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final CustomerFinder find = new CustomerFinder();
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public class Finder<I, T> {
|
||||
|
||||
/**
|
||||
* The entity bean type.
|
||||
*/
|
||||
private final Class<T> type;
|
||||
|
||||
/**
|
||||
* The name of the EbeanServer, null for the default server.
|
||||
*/
|
||||
private final String serverName;
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* public class CustomerFinder extends Finder<Customer> {
|
||||
*
|
||||
* public CustomerFinder() {
|
||||
* super(Customer.class);
|
||||
* }
|
||||
*
|
||||
* // ... add extra customer specific finder methods
|
||||
* }
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final CustomerFinder find = new CustomerFinder();
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public Finder(Class<T> type) {
|
||||
this.type = type;
|
||||
this.serverName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean and specific server name.
|
||||
*/
|
||||
public Finder(Class<T> type, String serverName) {
|
||||
this.type = type;
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' EbeanServer.
|
||||
*
|
||||
* <p>
|
||||
* This provides full access to the API such as explicit transaction demarcation etc.
|
||||
*
|
||||
*/
|
||||
public EbeanServer db() {
|
||||
return Ebean.getServer(serverName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return typically a different EbeanServer to the default.
|
||||
* <p>
|
||||
* This is equivalent to {@link Ebean#getServer(String)}
|
||||
*
|
||||
* @param server
|
||||
* The name of the EbeanServer. If this is null then the default EbeanServer is
|
||||
* returned.
|
||||
*/
|
||||
public EbeanServer db(String server) {
|
||||
return Ebean.getServer(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an entity reference for this ID.
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
|
||||
*/
|
||||
public T ref(I id) {
|
||||
return db().getReference(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an entity by ID.
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class, Object)}
|
||||
*/
|
||||
@Nullable
|
||||
public T byId(I id) {
|
||||
return db().find(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bean by Id.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#delete(Class, Object)}
|
||||
*/
|
||||
public void deleteById(I id) {
|
||||
db().delete(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all entities of the given type.
|
||||
*/
|
||||
public List<T> all() {
|
||||
return query().findList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class)}
|
||||
*/
|
||||
public Query<T> query() {
|
||||
return db().find(type);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Used to specify the type of like matching used.
|
||||
*/
|
||||
public enum LikeType {
|
||||
|
||||
/**
|
||||
* You need to put in your own wildcards.
|
||||
*/
|
||||
RAW,
|
||||
|
||||
/**
|
||||
* The % wildcard is added to the end of the search word.
|
||||
*/
|
||||
STARTS_WITH,
|
||||
|
||||
/**
|
||||
* The % wildcard is added to the beginning of the search word.
|
||||
*/
|
||||
ENDS_WITH,
|
||||
|
||||
/**
|
||||
* The % wildcard is added to the beginning and end of the search word.
|
||||
*/
|
||||
CONTAINS,
|
||||
|
||||
/**
|
||||
* Uses equal to rather than a LIKE with wildcards.
|
||||
* <p>
|
||||
* This is mainly here to be available for use with ExampleExpression.
|
||||
* </p>
|
||||
*/
|
||||
EQUAL_TO
|
||||
}
|
||||
@@ -1,898 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.util.ClassUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A MappedSuperclass base class that provides convenience methods for inserting, updating and
|
||||
* deleting beans.
|
||||
*
|
||||
* <p>
|
||||
* By having your entity beans extend this it provides a 'Active Record' style programming model for
|
||||
* Ebean users.
|
||||
*
|
||||
* <p>
|
||||
* Note that there is a avaje-ebeanorm-mocker project that enables you to use Mockito or similar
|
||||
* tools to still mock out the underlying 'default EbeanServer' 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
|
||||
* 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
|
||||
* 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
|
||||
* a {@link Find} as a public static field to complete the active record pattern and provide a
|
||||
* relatively nice clean way to write queries.
|
||||
*
|
||||
* <h3>Typical common @MappedSuperclass</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Typically there is a common base model that has some
|
||||
* // common properties like the ones below
|
||||
*
|
||||
* @MappedSuperclass
|
||||
* public class BaseModel extends Model {
|
||||
*
|
||||
* @Id Long id;
|
||||
*
|
||||
* @Version Long version;
|
||||
*
|
||||
* @CreatedTimestamp Timestamp whenCreated;
|
||||
*
|
||||
* @UpdatedTimestamp Timestamp whenUpdated;
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Extend the Model</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Extend the mappedSuperclass
|
||||
*
|
||||
* @Entity @Table(name="oto_account")
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* // Add a static Find
|
||||
* // ... with Long being the type of our @Id property.
|
||||
* // ... Note the {} at the end as Find is an abstract class.
|
||||
*
|
||||
* public static final Find<Long,Account> find = new Find<Long,Account>(){};
|
||||
*
|
||||
* String name;
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Modal: save()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Active record style ... save(), delete() etc
|
||||
* Customer customer = new Customer();
|
||||
* customer.setName("AC234");
|
||||
*
|
||||
* // save() method inherited from Model
|
||||
* customer.save();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Find byId</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // find byId
|
||||
* Customer customer = Customer.find.byId(42);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Find where</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // find where ...
|
||||
* List<Customer> customers =
|
||||
* Customer.find
|
||||
* .where().gt("startDate", lastMonth)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public abstract class Model {
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' EbeanServer.
|
||||
*
|
||||
* <p>
|
||||
* This provides full access to the API such as explicit transaction demarcation etc.
|
||||
*
|
||||
* <p>
|
||||
* Example:
|
||||
* <pre>{@code
|
||||
*
|
||||
* Transaction transaction = Customer.db().beginTransaction();
|
||||
* try {
|
||||
*
|
||||
* // turn off cascade persist for this transaction
|
||||
* transaction.setPersistCascade(false);
|
||||
*
|
||||
* // extra control over jdbc batching for this transaction
|
||||
* transaction.setBatchGetGeneratedKeys(false);
|
||||
* transaction.setBatchMode(true);
|
||||
* transaction.setBatchSize(20);
|
||||
*
|
||||
* Customer customer = new Customer();
|
||||
* customer.setName("Roberto");
|
||||
* customer.save();
|
||||
*
|
||||
* Customer otherCustomer = new Customer();
|
||||
* otherCustomer.setName("Franko");
|
||||
* otherCustomer.save();
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the entity bean as dirty.
|
||||
* <p>
|
||||
* This is used so that when a bean that is otherwise unmodified is updated the version
|
||||
* property is updated.
|
||||
* <p>
|
||||
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
|
||||
* dirty so that it is not skipped.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer = Customer.find.byId(id);
|
||||
*
|
||||
* // mark the bean as dirty so that a save() or update() will
|
||||
* // increment the version property
|
||||
* customer.markAsDirty();
|
||||
* customer.save();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see EbeanServer#markAsDirty(Object)
|
||||
*/
|
||||
public void markAsDirty() {
|
||||
db().markAsDirty(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the property as unset or 'not loaded'.
|
||||
* <p>
|
||||
* This would be used to specify a property that we did not wish to include in a stateless update.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // populate an entity bean from JSON or whatever
|
||||
* User user = ...;
|
||||
*
|
||||
* // mark the email property as 'unset' so that it is not
|
||||
* // included in a 'stateless update'
|
||||
* user.markPropertyUnset("email");
|
||||
*
|
||||
* user.update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyName the name of the property on the bean to be marked as 'unset'
|
||||
*/
|
||||
public void markPropertyUnset(String propertyName) {
|
||||
((EntityBean)this)._ebean_getIntercept().setPropertyLoaded(propertyName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert or update this entity depending on its state.
|
||||
*
|
||||
* <p>
|
||||
* 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)
|
||||
*/
|
||||
public void save() {
|
||||
db().save(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this entity.
|
||||
*
|
||||
* @see EbeanServer#update(Object)
|
||||
*/
|
||||
public void update() {
|
||||
db().update(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert this entity.
|
||||
*
|
||||
* @see EbeanServer#insert(Object)
|
||||
*/
|
||||
public void insert() {
|
||||
db().insert(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete this bean.
|
||||
* <p>
|
||||
* This will return true if the bean was deleted successfully or JDBC batch is being used.
|
||||
* </p>
|
||||
* <p>
|
||||
* If there is no current transaction one will be created and committed for
|
||||
* you automatically.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the Bean does not have a version property (or loaded version property) and
|
||||
* the bean does not exist then this returns false indicating that nothing was
|
||||
* deleted. Note that, if JDBC batch mode is used then this always returns true.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#delete(Object)
|
||||
*/
|
||||
public boolean delete() {
|
||||
return db().delete(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bean permanently without soft delete.
|
||||
* <p>
|
||||
* This is used when the bean contains a <code>@SoftDelete</code> property and we
|
||||
* want to perform a hard/permanent delete.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#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)
|
||||
*/
|
||||
public void refresh() {
|
||||
db().refresh(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* A concrete implementation of Find.
|
||||
* <p>
|
||||
* It should be preferred to use {@link Find} instead of Finder as that can use reflection to determine the class
|
||||
* literal type of the entity bean.
|
||||
* </p>
|
||||
* @param <I> type of the Id property
|
||||
* @param <T> type of the entity bean
|
||||
*/
|
||||
public static class Finder<I, T> extends Find<I, T> {
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final Finder<Long,Customer> find = new Finder<Long,Customer>(Customer.class);
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p/>
|
||||
* The preferred approach is to instead use <code>Find</code> as below. This approach is more DRY in that it does
|
||||
* not require the class literal Customer.class to be passed into the constructor.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public Finder(Class<T> type) {
|
||||
super(null, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean and specific server name.
|
||||
*/
|
||||
public Finder(String serverName, Class<T> type) {
|
||||
super(serverName, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper object for performing queries.
|
||||
*
|
||||
* <p>
|
||||
* Typically a Find instance is defined as a public static field on an entity bean class to provide a
|
||||
* nice way to write queries.
|
||||
*
|
||||
* <h3>Example use:</h3>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
* <p/>
|
||||
* This enables you to write code like:
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer = Customer.find.byId(42L);
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* Customer.find
|
||||
* .select("name, dateOfBirth")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Kotlin</h3>
|
||||
* In Kotlin you would typically create Find as a companion object.
|
||||
* <pre>{@code
|
||||
*
|
||||
* // kotlin
|
||||
* companion object : Model.Find<Long, Product>() {}
|
||||
*
|
||||
* }</pre>
|
||||
* @param <I>
|
||||
* The Id type. This is most often a {@link Long} but is also often a {@link UUID} or
|
||||
* {@link String}.
|
||||
*
|
||||
* @param <T>
|
||||
* The entity bean type
|
||||
*/
|
||||
public static abstract class Find<I, T> {
|
||||
|
||||
/**
|
||||
* The entity bean type.
|
||||
*/
|
||||
private final Class<T> type;
|
||||
|
||||
/**
|
||||
* The name of the EbeanServer, null for the default server.
|
||||
*/
|
||||
private final String serverName;
|
||||
|
||||
/**
|
||||
* Creates a finder for entity of type <code>T</code> with ID of type <code>I</code>.
|
||||
* <p/>
|
||||
* Typically you create Find as a public static field on each entity bean as the example below.
|
||||
*
|
||||
* <p/>
|
||||
* Note that Find is an abstract class and hence <code>{}</code> is required. This is done so
|
||||
* that the type (class literal) of the entity bean can be derived from the generics parameter.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* // Note the trailing {} as Find is an abstract class.
|
||||
* // We do this so that we can derive the type literal Customer.class
|
||||
* // via reflection
|
||||
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
* <p/>
|
||||
* This enables you to write code like:
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer = Customer.find.byId(42L);
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* Customer.find
|
||||
* .select("name, email, dateOfBirth")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Kotlin</h3>
|
||||
* In Kotlin you would typically create it as a companion object.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // kotlin
|
||||
* companion object : Model.Find<Long, Product>() {}
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Find() {
|
||||
this.serverName = null;
|
||||
this.type = (Class<T>)ClassUtil.getSecondArgumentType(getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct passing the class literal type of the entity type.
|
||||
*/
|
||||
protected Find(String serverName, Class<T> type) {
|
||||
this.serverName = serverName;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' EbeanServer.
|
||||
*
|
||||
* <p>
|
||||
* This provides full access to the API such as explicit transaction demarcation etc.
|
||||
*
|
||||
*/
|
||||
public EbeanServer db() {
|
||||
return Ebean.getServer(serverName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return typically a different EbeanServer to the default.
|
||||
* <p>
|
||||
* This is equivalent to {@link Ebean#getServer(String)}
|
||||
*
|
||||
* @param server
|
||||
* The name of the EbeanServer. If this is null then the default EbeanServer is
|
||||
* returned.
|
||||
*/
|
||||
public EbeanServer db(String server) {
|
||||
return Ebean.getServer(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Finder for the named EbeanServer.
|
||||
*
|
||||
* <p>
|
||||
* Create and return a new Finder for a different server.
|
||||
*/
|
||||
public Finder<I, T> on(String server) {
|
||||
return new Finder<I, T>(server, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bean by Id.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#delete(Class, Object)}
|
||||
*/
|
||||
public void deleteById(I id) {
|
||||
db().delete(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all entities of the given type.
|
||||
*
|
||||
* <p>
|
||||
* This is the same as (synonym for) {@link #findList()}
|
||||
*/
|
||||
public List<T> all() {
|
||||
return findList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an entity by ID.
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class, Object)}
|
||||
*/
|
||||
@Nullable
|
||||
public T byId(I id) {
|
||||
return db().find(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an entity reference for this ID.
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
|
||||
*/
|
||||
public T ref(I id) {
|
||||
return db().getReference(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a filter for sorting and filtering lists of entities locally without going back to
|
||||
* the database.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#filter(Class)}
|
||||
*/
|
||||
public Filter<T> filter() {
|
||||
return db().filter(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class)}
|
||||
*/
|
||||
public Query<T> query() {
|
||||
return db().find(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query applying the path properties to set the select and fetch clauses.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#apply(FetchPath)}
|
||||
*/
|
||||
public Query<T> apply(FetchPath fetchPath) {
|
||||
return db().find(type).apply(fetchPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next identity value.
|
||||
*
|
||||
* @see EbeanServer#nextId(Class)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public I nextId() {
|
||||
return (I) db().nextId(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a query and returns the results as a list of IDs.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findIds()}
|
||||
*/
|
||||
public <A> List<A> findIds() {
|
||||
return query().findIds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query consuming each bean one at a time.
|
||||
* <p>
|
||||
* This is generally used to process large queries where unlike findList
|
||||
* you do not want to hold all the results in memory at once but instead
|
||||
* process them one at a time (requiring far less memory).
|
||||
* </p>
|
||||
* Equivalent to {@link Query#findEach(QueryEachConsumer)}
|
||||
*/
|
||||
public void findEach(QueryEachConsumer<T> consumer) {
|
||||
query().findEach(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query consuming each bean one at a time.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findEachWhile(QueryEachWhileConsumer)}
|
||||
* <p>
|
||||
* This is similar to #findEach except that you return boolean
|
||||
* true to continue processing beans and return false to stop
|
||||
* processing early.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is generally used to process large queries where unlike findList
|
||||
* you do not want to hold all the results in memory at once but instead
|
||||
* process them one at a time (requiring far less memory).
|
||||
* </p>
|
||||
* Equivalent to {@link Query#findEachWhile(QueryEachWhileConsumer)}
|
||||
*/
|
||||
public void findEachWhile(QueryEachWhileConsumer<T> consumer) {
|
||||
query().findEachWhile(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all entities of the given type.
|
||||
* <p>
|
||||
* The same as {@link #all()}
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findList()}
|
||||
*/
|
||||
public List<T> findList() {
|
||||
return query().findList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the entities of the given type as a set.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findSet()}
|
||||
*/
|
||||
public Set<T> findSet() {
|
||||
return query().findSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all entities of the given type as a map of objects.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findMap()}
|
||||
*/
|
||||
public <K> Map<K, T> findMap() {
|
||||
return query().findMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a find row count query in a background thread.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findFutureCount()}
|
||||
*/
|
||||
public FutureRowCount<T> findFutureCount() {
|
||||
return query().findFutureCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated in favor of findFutureCount().
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findFutureCount()}
|
||||
*/
|
||||
public FutureRowCount<T> findFutureRowCount() {
|
||||
return query().findFutureCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of entities for this type. *
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findCount()}
|
||||
*/
|
||||
public int findCount() {
|
||||
return query().findCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated in favor of findCount().
|
||||
* @deprecated
|
||||
*/
|
||||
public int findRowCount() {
|
||||
return query().findCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>ExpressionFactory</code> used by this query.
|
||||
*/
|
||||
public ExpressionFactory getExpressionFactory() {
|
||||
return query().getExpressionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly sets a comma delimited list of the properties to fetch on the 'main' entity bean,
|
||||
* to load a partial object.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#select(String)}
|
||||
*/
|
||||
public Query<T> select(String fetchProperties) {
|
||||
return query().select(fetchProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a path to load including all its properties.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#fetch(String)}
|
||||
*/
|
||||
public Query<T> fetch(String path) {
|
||||
return query().fetch(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Additionally specifies a <code>FetchConfig</code> to specify a 'query join' and/or define the
|
||||
* lazy loading query.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#fetch(String, FetchConfig)}
|
||||
*/
|
||||
public Query<T> fetch(String path, FetchConfig joinConfig) {
|
||||
return query().fetch(path, joinConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a path to fetch with a specific list properties to include, to load a partial
|
||||
* object.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#fetch(String, String)}
|
||||
*/
|
||||
public Query<T> fetch(String path, String fetchProperties) {
|
||||
return query().fetch(path, fetchProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Additionally specifies a <code>FetchConfig</code> to use a separate query or lazy loading to
|
||||
* load this path.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#fetch(String, String, FetchConfig)}
|
||||
*/
|
||||
public Query<T> fetch(String assocProperty, String fetchProperties, FetchConfig fetchConfig) {
|
||||
return query().fetch(assocProperty, fetchProperties, fetchConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds expressions to the <code>where</code> clause with the ability to chain on the
|
||||
* <code>ExpressionList</code>.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#where()}
|
||||
*/
|
||||
public ExpressionList<T> where() {
|
||||
return query().where();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>order by</code> clause so that you can append an ascending or descending
|
||||
* property to the <code>order by</code> clause.
|
||||
* <p>
|
||||
* This is exactly the same as {@link #orderBy}.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#order()}
|
||||
*/
|
||||
public OrderBy<T> order() {
|
||||
return query().order();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the <code>order by</code> clause, replacing the existing <code>order by</code> clause if
|
||||
* there is one.
|
||||
* <p>
|
||||
* This is exactly the same as {@link #orderBy(String)}.
|
||||
*/
|
||||
public Query<T> order(String orderByClause) {
|
||||
return query().order(orderByClause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>order by</code> clause so that you can append an ascending or descending
|
||||
* property to the <code>order by</code> clause.
|
||||
* <p>
|
||||
* This is exactly the same as {@link #order}.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#orderBy()}
|
||||
*/
|
||||
public OrderBy<T> orderBy() {
|
||||
return query().orderBy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>order by</code> clause replacing the existing <code>order by</code> clause if
|
||||
* there is one.
|
||||
* <p>
|
||||
* This is exactly the same as {@link #order(String)}.
|
||||
*/
|
||||
public Query<T> orderBy(String orderByClause) {
|
||||
return query().orderBy(orderByClause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the first row to return for this query.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#setFirstRow(int)}
|
||||
*/
|
||||
public Query<T> setFirstRow(int firstRow) {
|
||||
return query().setFirstRow(firstRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of rows to return in the query.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#setMaxRows(int)}
|
||||
*/
|
||||
public Query<T> setMaxRows(int maxRows) {
|
||||
return query().setMaxRows(maxRows);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ID value to query.
|
||||
*
|
||||
* <p>
|
||||
* Use this to perform a find byId query but with additional control over the query such as
|
||||
* using select and fetch to control what parts of the object graph are returned.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#setId(Object)}
|
||||
*/
|
||||
public Query<T> setId(Object id) {
|
||||
return query().setId(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new query based on the <code>RawSql</code>.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#setRawSql(RawSql)}
|
||||
*/
|
||||
public Query<T> setRawSql(RawSql rawSql) {
|
||||
return query().setRawSql(rawSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query with explicit 'AutoTune' use.
|
||||
*/
|
||||
public Query<T> setAutoTune(boolean autoTune) {
|
||||
return query().setAutoTune(autoTune);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query with the select with "for update" specified.
|
||||
*
|
||||
* <p>
|
||||
* This will typically create row level database locks on the selected rows.
|
||||
*/
|
||||
public Query<T> setForUpdate(boolean forUpdate) {
|
||||
return query().setForUpdate(forUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query specifying whether the returned beans will be read-only.
|
||||
*/
|
||||
public Query<T> setReadOnly(boolean readOnly) {
|
||||
return query().setReadOnly(readOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query specifying if the beans should be loaded into the L2 cache.
|
||||
*/
|
||||
public Query<T> setLoadBeanCache(boolean loadBeanCache) {
|
||||
return query().setLoadBeanCache(loadBeanCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query specifying if the L2 bean cache should be used.
|
||||
*/
|
||||
public Query<T> setUseCache(boolean useBeanCache) {
|
||||
return query().setUseCache(useBeanCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query specifying if the L2 query cache should be used.
|
||||
*/
|
||||
public Query<T> setUseQueryCache(boolean useQueryCache) {
|
||||
return query().setUseQueryCache(useQueryCache);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Used to process a query result one bean at a time via a callback to this
|
||||
* visitor.
|
||||
* <p>
|
||||
* If you wish to stop further processing return false from the accept method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Unlike findList() and findSet() using a QueryResultVisitor does not require
|
||||
* all the beans in the query result to be held in memory at once. This makes
|
||||
* QueryResultVisitor useful for processing large queries.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id");
|
||||
*
|
||||
* query.findEach((Customer customer) -> {
|
||||
*
|
||||
* // do something with customer
|
||||
* System.out.println("-- visit " + customer);
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean being queried.
|
||||
*/
|
||||
public interface QueryEachConsumer<T> {
|
||||
|
||||
/**
|
||||
* Process the bean.
|
||||
*
|
||||
* @param bean
|
||||
* the entity bean to process
|
||||
*/
|
||||
void accept(T bean);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Used to process a query result one bean at a time via a callback to this
|
||||
* visitor.
|
||||
* <p>
|
||||
* If you wish to stop further processing return false from the accept method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Unlike findList() and findSet() using a QueryResultVisitor does not require
|
||||
* all the beans in the query result to be held in memory at once. This makes
|
||||
* QueryResultVisitor useful for processing large queries.
|
||||
* </p>
|
||||
* <p/>
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* query.findEachWhile((Customer customer) -> {
|
||||
*
|
||||
* // do something with customer
|
||||
* System.out.println("-- visit " + customer);
|
||||
*
|
||||
* // return true to continue processing or false to stop
|
||||
* return (customer.getId() < 40);
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> the type of entity bean being queried.
|
||||
*/
|
||||
public interface QueryEachWhileConsumer<T> {
|
||||
|
||||
/**
|
||||
* Process the bean and return true if you want to continue processing more
|
||||
* beans. Return false if you want to stop processing further.
|
||||
*
|
||||
* @param bean the entity bean to process
|
||||
* @return true to continue processing more beans or false to stop.
|
||||
*/
|
||||
boolean accept(T bean);
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Used to provide iteration over query results.
|
||||
* <p>
|
||||
* This can be used when you want to process a very large number of results and
|
||||
* means that you don't have to hold all the results in memory at once (unlike
|
||||
* findList(), findSet() etc where all the beans are held in the List or Set
|
||||
* etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that findIterate (and findEach and findEachWhile) uses a "per graph"
|
||||
* persistence context scope and adjusts jdbc fetch buffer size for large
|
||||
* queries. As such it is better to use findList for small queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
|
||||
* when you have finished iterating the results (typically in a finally block).
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* QueryIterator<Customer> it = query.findIterate();
|
||||
* try {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer ...
|
||||
* }
|
||||
* } finally {
|
||||
* // close the underlying resources
|
||||
* it.close();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean in the iteration
|
||||
*/
|
||||
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if the iteration has more elements.
|
||||
*/
|
||||
boolean hasNext();
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
*/
|
||||
T next();
|
||||
|
||||
/**
|
||||
* Remove is not allowed.
|
||||
*/
|
||||
void remove();
|
||||
|
||||
/**
|
||||
* Close the underlying resources held by this iterator.
|
||||
*/
|
||||
void close();
|
||||
}
|
||||
@@ -1,735 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.ResultSet;
|
||||
import java.util.*;
|
||||
|
||||
import com.avaje.ebean.util.CamelCaseHelper;
|
||||
|
||||
/**
|
||||
* Used to build object graphs based on a raw SQL statement (rather than
|
||||
* generated by Ebean).
|
||||
* <p>
|
||||
* If you don't want to build object graphs you can use {@link SqlQuery} instead
|
||||
* which returns {@link SqlRow} objects rather than entity beans.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Unparsed RawSql:</b>
|
||||
* </p>
|
||||
* <p>
|
||||
* When RawSql is created via {@link RawSqlBuilder#unparsed(String)} then Ebean can not
|
||||
* modify the SQL at all. It can't add any extra expressions into the SQL.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Parsed RawSql:</b>
|
||||
* </p>
|
||||
* <p>
|
||||
* When RawSql is created via {@link RawSqlBuilder#parse(String)} then Ebean will parse the
|
||||
* SQL and find places in the SQL where it can add extra where expressions, add
|
||||
* extra having expressions or replace the order by clause. If you want to
|
||||
* explicitly tell Ebean where these insertion points are you can place special
|
||||
* strings into your SQL ({@code ${where}} or {@code ${andWhere}} and {@code ${having}} or
|
||||
* {@code ${andHaving})}.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the SQL already includes a WHERE clause put in {@code ${andWhere}} in the location
|
||||
* you want Ebean to add any extra where expressions. If the SQL doesn't have a
|
||||
* WHERE clause put {@code ${where}} in instead. Similarly you can put in {@code ${having}} or
|
||||
* {@code ${andHaving}} where you want Ebean put add extra having expressions.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Aggregates:</b>
|
||||
* </p>
|
||||
* <p>
|
||||
* Often RawSql will be used with Aggregate functions (sum, avg, max etc). The
|
||||
* follow example shows an example based on Total Order Amount -
|
||||
* sum(d.order_qty*d.unit_price).
|
||||
* </p>
|
||||
* <p>
|
||||
* We can use a OrderAggregate bean that has a @Sql to indicate it is based
|
||||
* on RawSql and not based on a real DB Table or DB View. It has some properties
|
||||
* to hold the values for the aggregate functions (sum etc) and a @OneToOne
|
||||
* to Order.
|
||||
* </p>
|
||||
*
|
||||
* <h3>Example OrderAggregate</h3>
|
||||
*
|
||||
* <pre>{@code
|
||||
* ...
|
||||
* // @Sql indicates to that this bean
|
||||
* // is based on RawSql rather than a table
|
||||
*
|
||||
* @Entity
|
||||
* @Sql
|
||||
* public class OrderAggregate {
|
||||
*
|
||||
* @OneToOne
|
||||
* Order order;
|
||||
*
|
||||
* Double totalAmount;
|
||||
*
|
||||
* Double totalItems;
|
||||
*
|
||||
* // getters and setters
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Example 1:</h3>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = " select order_id, o.status, c.id, c.name, sum(d.order_qty*d.unit_price) as totalAmount"
|
||||
* + " from o_order o"
|
||||
* + " join o_customer c on c.id = o.kcustomer_id "
|
||||
* + " join o_order_detail d on d.order_id = o.id " + " group by order_id, o.status ";
|
||||
*
|
||||
* RawSql rawSql = RawSqlBuilder.parse(sql)
|
||||
* // map the sql result columns to bean properties
|
||||
* .columnMapping("order_id", "order.id")
|
||||
* .columnMapping("o.status", "order.status")
|
||||
* .columnMapping("c.id", "order.customer.id")
|
||||
* .columnMapping("c.name", "order.customer.name")
|
||||
* // we don't need to map this one due to the sql column alias
|
||||
* // .columnMapping("sum(d.order_qty*d.unit_price)", "totalAmount")
|
||||
* .create();
|
||||
*
|
||||
* List<OrderAggregate> list = Ebean.find(OrderAggregate.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .where().gt("order.id", 0)
|
||||
* .having().gt("totalAmount", 20)
|
||||
* .findList();
|
||||
*
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Example 2:</h3>
|
||||
*
|
||||
* <p>
|
||||
* The following example uses a FetchConfig().query() so that after the initial
|
||||
* RawSql query is executed Ebean executes a secondary query to fetch the
|
||||
* associated order status, orderDate along with the customer name.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = " select order_id, 'ignoreMe', sum(d.order_qty*d.unit_price) as totalAmount "
|
||||
* + " from o_order_detail d"
|
||||
* + " group by order_id ";
|
||||
*
|
||||
* RawSql rawSql = RawSqlBuilder.parse(sql)
|
||||
* .columnMapping("order_id", "order.id")
|
||||
* .columnMappingIgnore("'ignoreMe'")
|
||||
* .create();
|
||||
*
|
||||
* List<OrderAggregate> orders = Ebean.find(OrderAggregate.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .fetch("order", "status,orderDate", new FetchConfig().query())
|
||||
* .fetch("order.customer", "name")
|
||||
* .where().gt("order.id", 0)
|
||||
* .having().gt("totalAmount", 20)
|
||||
* .order().desc("totalAmount")
|
||||
* .setMaxRows(10)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* <h3>Example 3: tableAliasMapping</h3>
|
||||
* <p>
|
||||
* Instead of mapping each column you can map each table alias to a path using tableAliasMapping().
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* String rs = "select o.id, o.status, c.id, c.name, "+
|
||||
* " d.id, d.order_qty, p.id, p.name " +
|
||||
* "from o_order o join o_customer c on c.id = o.kcustomer_id " +
|
||||
* "join o_order_detail d on d.order_id = o.id " +
|
||||
* "join o_product p on p.id = d.product_id " +
|
||||
* "where o.id <= :maxOrderId and p.id = :productId "+
|
||||
* "order by o.id, d.id asc";
|
||||
*
|
||||
* RawSql rawSql = RawSqlBuilder.parse(rs)
|
||||
* .tableAliasMapping("c", "customer")
|
||||
* .tableAliasMapping("d", "details")
|
||||
* .tableAliasMapping("p", "details.product")
|
||||
* .create();
|
||||
*
|
||||
* List<Order> ordersFromRaw = Ebean.find(Order.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .setParameter("maxOrderId", 2)
|
||||
* .setParameter("productId", 1)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Note that lazy loading also works with object graphs built with RawSql.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public final class RawSql implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ResultSet resultSet;
|
||||
|
||||
private final Sql sql;
|
||||
|
||||
private final ColumnMapping columnMapping;
|
||||
|
||||
/**
|
||||
* Construct with a ResultSet and properties that the columns map to.
|
||||
* <p>
|
||||
* The properties listed in the propertyNames must be in the same order as the columns in the
|
||||
* resultSet.
|
||||
* <p>
|
||||
* When a query executes this RawSql object then it will close the resultSet.
|
||||
*/
|
||||
public RawSql(ResultSet resultSet, String... propertyNames) {
|
||||
this.resultSet = resultSet;
|
||||
this.sql = null;
|
||||
this.columnMapping = new ColumnMapping(propertyNames);
|
||||
}
|
||||
|
||||
protected RawSql(ResultSet resultSet, Sql sql, ColumnMapping columnMapping) {
|
||||
this.resultSet = resultSet;
|
||||
this.sql = sql;
|
||||
this.columnMapping = columnMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Sql either unparsed or in parsed (broken up) form.
|
||||
*/
|
||||
public Sql getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the key;
|
||||
*/
|
||||
public Key getKey() {
|
||||
boolean parsed = sql != null && sql.parsed;
|
||||
String unParsedSql = (sql == null) ? "" : sql.unparsedSql;
|
||||
return new Key(parsed, unParsedSql, columnMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resultSet if this is a ResultSet based RawSql.
|
||||
*/
|
||||
public ResultSet getResultSet() {
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column mapping for the SQL columns to bean properties.
|
||||
*/
|
||||
public ColumnMapping getColumnMapping() {
|
||||
return columnMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the sql part of the query. For parsed RawSql the sql is broken
|
||||
* up so that Ebean can insert extra WHERE and HAVING expressions into the
|
||||
* SQL.
|
||||
*/
|
||||
public static final class Sql implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final boolean parsed;
|
||||
|
||||
private final String unparsedSql;
|
||||
|
||||
private final String preFrom;
|
||||
|
||||
private final String preWhere;
|
||||
|
||||
private final boolean andWhereExpr;
|
||||
|
||||
private final String preHaving;
|
||||
|
||||
private final boolean andHavingExpr;
|
||||
|
||||
private final String orderByPrefix;
|
||||
|
||||
private final String orderBy;
|
||||
|
||||
private final boolean distinct;
|
||||
|
||||
/**
|
||||
* Construct for unparsed SQL.
|
||||
*/
|
||||
protected Sql(String unparsedSql) {
|
||||
this.parsed = false;
|
||||
this.unparsedSql = unparsedSql;
|
||||
this.preFrom = null;
|
||||
this.preHaving = null;
|
||||
this.preWhere = null;
|
||||
this.andHavingExpr = false;
|
||||
this.andWhereExpr = false;
|
||||
this.orderByPrefix = null;
|
||||
this.orderBy = null;
|
||||
this.distinct = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for parsed SQL.
|
||||
*/
|
||||
protected Sql(String unparsedSql, String preFrom, String preWhere, boolean andWhereExpr,
|
||||
String preHaving, boolean andHavingExpr, String orderByPrefix, String orderBy, boolean distinct) {
|
||||
|
||||
this.unparsedSql = unparsedSql;
|
||||
this.parsed = true;
|
||||
this.preFrom = preFrom;
|
||||
this.preHaving = preHaving;
|
||||
this.preWhere = preWhere;
|
||||
this.andHavingExpr = andHavingExpr;
|
||||
this.andWhereExpr = andWhereExpr;
|
||||
this.orderByPrefix = orderByPrefix;
|
||||
this.orderBy = orderBy;
|
||||
this.distinct = distinct;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (!parsed) {
|
||||
return "unparsed[" + unparsedSql + "]";
|
||||
}
|
||||
return "select[" + preFrom + "] preWhere[" + preWhere + "] preHaving[" + preHaving
|
||||
+ "] orderBy[" + orderBy + "]";
|
||||
}
|
||||
|
||||
public boolean isDistinct() {
|
||||
return distinct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the SQL is left completely unmodified.
|
||||
* <p>
|
||||
* This means Ebean can't add WHERE or HAVING expressions into the query -
|
||||
* it will be left completely unmodified.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isParsed() {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL when it is unparsed.
|
||||
*/
|
||||
public String getUnparsedSql() {
|
||||
return unparsedSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL prior to FROM clause.
|
||||
*/
|
||||
public String getPreFrom() {
|
||||
return preFrom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL prior to WHERE clause.
|
||||
*/
|
||||
public String getPreWhere() {
|
||||
return preWhere;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is already a WHERE clause and any extra where
|
||||
* expressions start with AND.
|
||||
*/
|
||||
public boolean isAndWhereExpr() {
|
||||
return andWhereExpr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL prior to HAVING clause.
|
||||
*/
|
||||
public String getPreHaving() {
|
||||
return preHaving;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is already a HAVING clause and any extra having
|
||||
* expressions start with AND.
|
||||
*/
|
||||
public boolean isAndHavingExpr() {
|
||||
return andHavingExpr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the 'order by' keywords.
|
||||
* This can contain additional keywords, for example 'order siblings by' as Oracle syntax.
|
||||
*/
|
||||
public String getOrderByPrefix() {
|
||||
return (orderByPrefix == null) ? "order by" : orderByPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL ORDER BY clause.
|
||||
*/
|
||||
public String getOrderBy() {
|
||||
return orderBy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the column mapping for raw sql DB columns to bean properties.
|
||||
*/
|
||||
public static final class ColumnMapping implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final LinkedHashMap<String, Column> dbColumnMap;
|
||||
|
||||
private final Map<String, String> propertyMap;
|
||||
|
||||
private final Map<String, Column> propertyColumnMap;
|
||||
|
||||
private final boolean parsed;
|
||||
|
||||
private final boolean immutable;
|
||||
|
||||
/**
|
||||
* Construct from parsed sql where the columns have been identified.
|
||||
*/
|
||||
protected ColumnMapping(List<Column> columns) {
|
||||
this.immutable = false;
|
||||
this.parsed = true;
|
||||
this.propertyMap = null;
|
||||
this.propertyColumnMap = null;
|
||||
this.dbColumnMap = new LinkedHashMap<String, Column>();
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
Column c = columns.get(i);
|
||||
dbColumnMap.put(c.getDbColumnKey(), c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for unparsed sql.
|
||||
*/
|
||||
protected ColumnMapping() {
|
||||
this.immutable = false;
|
||||
this.parsed = false;
|
||||
this.propertyMap = null;
|
||||
this.propertyColumnMap = null;
|
||||
this.dbColumnMap = new LinkedHashMap<String, Column>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for ResultSet use.
|
||||
*/
|
||||
protected ColumnMapping(String... propertyNames) {
|
||||
this.immutable = false;
|
||||
this.parsed = false;
|
||||
this.propertyMap = null;
|
||||
this.dbColumnMap = new LinkedHashMap<String, Column>();
|
||||
|
||||
int pos = 0;
|
||||
for (String prop : propertyNames) {
|
||||
dbColumnMap.put(prop, new Column(pos++, prop, null, prop));
|
||||
}
|
||||
propertyColumnMap = dbColumnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an immutable ColumnMapping based on collected information.
|
||||
*/
|
||||
protected ColumnMapping(boolean parsed, LinkedHashMap<String, Column> dbColumnMap) {
|
||||
this.immutable = true;
|
||||
this.parsed = parsed;
|
||||
this.dbColumnMap = dbColumnMap;
|
||||
|
||||
HashMap<String, Column> pcMap = new HashMap<String, Column>();
|
||||
HashMap<String, String> pMap = new HashMap<String, String>();
|
||||
|
||||
for (Column c : dbColumnMap.values()) {
|
||||
pMap.put(c.getPropertyName(), c.getDbColumn());
|
||||
pcMap.put(c.getPropertyName(), c);
|
||||
}
|
||||
this.propertyMap = Collections.unmodifiableMap(pMap);
|
||||
this.propertyColumnMap = Collections.unmodifiableMap(pcMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ColumnMapping that = (ColumnMapping) o;
|
||||
return dbColumnMap.equals(that.dbColumnMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return dbColumnMap.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the property is mapped.
|
||||
*/
|
||||
public boolean contains(String property) {
|
||||
return this.propertyColumnMap.containsKey(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an immutable copy of this ColumnMapping.
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* when a propertyName has not been defined for a column.
|
||||
*/
|
||||
protected ColumnMapping createImmutableCopy() {
|
||||
|
||||
for (Column c : dbColumnMap.values()) {
|
||||
c.checkMapping();
|
||||
}
|
||||
|
||||
return new ColumnMapping(parsed, dbColumnMap);
|
||||
}
|
||||
|
||||
protected void columnMapping(String dbColumn, String propertyName) {
|
||||
|
||||
if (immutable) {
|
||||
throw new IllegalStateException("Should never happen");
|
||||
}
|
||||
if (!parsed) {
|
||||
int pos = dbColumnMap.size();
|
||||
dbColumnMap.put(dbColumn, new Column(pos, dbColumn, null, propertyName));
|
||||
} else {
|
||||
Column column = dbColumnMap.get(dbColumn);
|
||||
if (column == null) {
|
||||
String msg = "DB Column [" + dbColumn + "] not found in mapping. Expecting one of [" + dbColumnMap.keySet() + "]";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
column.setPropertyName(propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the Columns where supplied by parsing the sql select
|
||||
* clause.
|
||||
* <p>
|
||||
* In the case where the columns where parsed then we can do extra checks on
|
||||
* the column mapping such as, is the column a valid one in the sql and
|
||||
* whether all the columns in the sql have been mapped.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isParsed() {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of columns in this column mapping.
|
||||
*/
|
||||
public int size() {
|
||||
return dbColumnMap.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column mapping.
|
||||
*/
|
||||
protected Map<String, Column> mapping() {
|
||||
return dbColumnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mapping by DB column.
|
||||
*/
|
||||
public Map<String, String> getMapping() {
|
||||
return propertyMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index position by bean property name.
|
||||
*/
|
||||
public int getIndexPosition(String property) {
|
||||
Column c = propertyColumnMap.get(property);
|
||||
return c == null ? -1 : c.getIndexPos();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an iterator of the Columns.
|
||||
*/
|
||||
public Iterator<Column> getColumns() {
|
||||
return dbColumnMap.values().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify any column mappings with the given table alias to have the path prefix.
|
||||
* <p>
|
||||
* For example modify all mappings with table alias "c" to have the path prefix "customer".
|
||||
* </p>
|
||||
* <p>
|
||||
* For the "Root type" you don't need to specify a tableAliasMapping.
|
||||
* </p>
|
||||
*/
|
||||
public void tableAliasMapping(String tableAlias, String path) {
|
||||
|
||||
String startMatch = tableAlias+".";
|
||||
for (Map.Entry<String, Column> entry : dbColumnMap.entrySet()) {
|
||||
if (entry.getKey().startsWith(startMatch)) {
|
||||
entry.getValue().tableAliasMapping(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Column of the RawSql that is mapped to a bean property (or ignored).
|
||||
*/
|
||||
public static class Column implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final int indexPos;
|
||||
private final String dbColumn;
|
||||
|
||||
private final String dbAlias;
|
||||
|
||||
private String propertyName;
|
||||
|
||||
/**
|
||||
* Construct a Column.
|
||||
*/
|
||||
public Column(int indexPos, String dbColumn, String dbAlias) {
|
||||
this(indexPos, dbColumn, dbAlias, derivePropertyName(dbAlias, dbColumn));
|
||||
}
|
||||
|
||||
private Column(int indexPos, String dbColumn, String dbAlias, String propertyName) {
|
||||
this.indexPos = indexPos;
|
||||
this.dbColumn = dbColumn;
|
||||
this.dbAlias = dbAlias;
|
||||
if (propertyName == null && dbAlias != null) {
|
||||
this.propertyName = dbAlias;
|
||||
} else {
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
}
|
||||
|
||||
protected static String derivePropertyName(String dbAlias, String dbColumn) {
|
||||
if (dbAlias != null) {
|
||||
return CamelCaseHelper.toCamelFromUnderscore(dbAlias);
|
||||
}
|
||||
int dotPos = dbColumn.indexOf('.');
|
||||
if (dotPos > -1) {
|
||||
dbColumn = dbColumn.substring(dotPos + 1);
|
||||
}
|
||||
return CamelCaseHelper.toCamelFromUnderscore(dbColumn);
|
||||
}
|
||||
|
||||
private void checkMapping() {
|
||||
if (propertyName == null) {
|
||||
String msg = "No propertyName defined (Column mapping) for dbColumn [" + dbColumn + "]";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Column that = (Column) o;
|
||||
if (indexPos != that.indexPos) return false;
|
||||
if (!dbColumn.equals(that.dbColumn)) return false;
|
||||
if (dbAlias != null ? !dbAlias.equals(that.dbAlias) : that.dbAlias != null) return false;
|
||||
return propertyName != null ? propertyName.equals(that.propertyName) : that.propertyName == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = indexPos;
|
||||
result = 31 * result + dbColumn.hashCode();
|
||||
result = 31 * result + (dbAlias != null ? dbAlias.hashCode() : 0);
|
||||
result = 31 * result + (propertyName != null ? propertyName.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return dbColumn + "->" + propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index position of this column.
|
||||
*/
|
||||
public int getIndexPos() {
|
||||
return indexPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB column alias if specified otherwise DB column.
|
||||
* This is used as the key for mapping a column to a logical property.
|
||||
*/
|
||||
public String getDbColumnKey() {
|
||||
return (dbAlias != null) ? dbAlias : dbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB column name including table alias (if it has one).
|
||||
*/
|
||||
public String getDbColumn() {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean property this column is mapped to.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the property name mapped to this db column.
|
||||
*/
|
||||
private void setPropertyName(String propertyName) {
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepend the path to the property name.
|
||||
* <p/>
|
||||
* For example if path is "customer" then "name" becomes "customer.name".
|
||||
*/
|
||||
public void tableAliasMapping(String path) {
|
||||
if (path != null) {
|
||||
propertyName = path + "." + propertyName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A key for the RawSql object using for the query plan.
|
||||
*/
|
||||
public static final class Key {
|
||||
|
||||
private final boolean parsed;
|
||||
private final ColumnMapping columnMapping;
|
||||
private final String unParsedSql;
|
||||
|
||||
Key(boolean parsed, String unParsedSql, ColumnMapping columnMapping) {
|
||||
this.parsed = parsed;
|
||||
this.unParsedSql = unParsedSql;
|
||||
this.columnMapping = columnMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Key that = (Key) o;
|
||||
return parsed == that.parsed
|
||||
&& columnMapping.equals(that.columnMapping)
|
||||
&& unParsedSql.equals(that.unParsedSql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (parsed ? 1 : 0);
|
||||
result = 31 * result + columnMapping.hashCode();
|
||||
result = 31 * result + unParsedSql.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import com.avaje.ebean.RawSql.ColumnMapping;
|
||||
import com.avaje.ebean.RawSql.Sql;
|
||||
|
||||
/**
|
||||
* Builds RawSql instances from a SQL string and column mappings.
|
||||
* <p>
|
||||
* Note that RawSql can also be defined in ebean-orm.xml files and be used as a
|
||||
* named query.
|
||||
* </p>
|
||||
*
|
||||
* @see RawSql
|
||||
*/
|
||||
public class RawSqlBuilder {
|
||||
|
||||
/**
|
||||
* Special property name assigned to a DB column that should be ignored.
|
||||
*/
|
||||
public static final String IGNORE_COLUMN = "$$_IGNORE_COLUMN_$$";
|
||||
|
||||
private final ResultSet resultSet;
|
||||
|
||||
private final Sql sql;
|
||||
|
||||
private final ColumnMapping columnMapping;
|
||||
|
||||
/**
|
||||
* Create and return a RawSql object based on the resultSet and list of properties the columns in
|
||||
* the resultSet map to.
|
||||
* <p>
|
||||
* The properties listed in the propertyNames must be in the same order as the columns in the
|
||||
* resultSet.
|
||||
*/
|
||||
public static RawSql resultSet(ResultSet resultSet, String... propertyNames) {
|
||||
return new RawSql(resultSet, propertyNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an unparsed RawSqlBuilder. Unlike a parsed one this query can not be
|
||||
* modified - so no additional WHERE or HAVING expressions can be added to
|
||||
* this query.
|
||||
*/
|
||||
public static RawSqlBuilder unparsed(String sql) {
|
||||
|
||||
Sql s = new Sql(sql);
|
||||
return new RawSqlBuilder(s, new ColumnMapping());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a RawSqlBuilder parsing the sql.
|
||||
* <p>
|
||||
* The sql statement will be parsed so that Ebean can determine where it can
|
||||
* insert additional WHERE or HAVING expressions.
|
||||
* </p>
|
||||
* <p>
|
||||
* Additionally the selected columns are parsed to determine the column
|
||||
* ordering. This also means additional checks can be made with the column
|
||||
* mapping - specifically we can check that all columns are mapped and that
|
||||
* correct column names are entered into the mapping.
|
||||
* </p>
|
||||
*/
|
||||
public static RawSqlBuilder parse(String sql) {
|
||||
|
||||
Sql sql2 = DRawSqlParser.parse(sql);
|
||||
String select = sql2.getPreFrom();
|
||||
|
||||
ColumnMapping mapping = DRawSqlColumnsParser.parse(select);
|
||||
return new RawSqlBuilder(sql2, mapping);
|
||||
}
|
||||
|
||||
private RawSqlBuilder(Sql sql, ColumnMapping columnMapping) {
|
||||
this.sql = sql;
|
||||
this.columnMapping = columnMapping;
|
||||
this.resultSet = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mapping of a DB Column to a bean property.
|
||||
* <p>
|
||||
* For Unparsed SQL the columnMapping MUST be defined in the same order that
|
||||
* the columns appear in the SQL statement.
|
||||
* </p>
|
||||
*
|
||||
* @param dbColumn
|
||||
* the DB column that we are mapping to a bean property
|
||||
* @param propertyName
|
||||
* the bean property that we are mapping the DB column to.
|
||||
*/
|
||||
public RawSqlBuilder columnMapping(String dbColumn, String propertyName) {
|
||||
columnMapping.columnMapping(dbColumn, propertyName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore this DB column. It is not mapped to any bean property.
|
||||
*/
|
||||
public RawSqlBuilder columnMappingIgnore(String dbColumn) {
|
||||
return columnMapping(dbColumn, IGNORE_COLUMN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify any column mappings with the given table alias to have the path prefix.
|
||||
* <p>
|
||||
* For example modify all mappings with table alias "c" to have the path prefix "customer".
|
||||
* </p>
|
||||
* <p>
|
||||
* For the "Root type" you don't need to specify a tableAliasMapping.
|
||||
* </p>
|
||||
*/
|
||||
public RawSqlBuilder tableAliasMapping(String tableAlias, String path) {
|
||||
columnMapping.tableAliasMapping(tableAlias, path);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the immutable RawSql object. Do this after all the column mapping
|
||||
* has been defined.
|
||||
*/
|
||||
public RawSql create() {
|
||||
return new RawSql(resultSet, sql, columnMapping.createImmutableCopy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the internal parsed Sql object (for testing).
|
||||
*/
|
||||
protected Sql getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
class SimpleTextParser {
|
||||
|
||||
private final String oql;
|
||||
private final char[] chars;
|
||||
private final int eof;
|
||||
|
||||
private int pos;
|
||||
private String word;
|
||||
private String lowerWord;
|
||||
|
||||
SimpleTextParser(String oql) {
|
||||
this.oql = oql;
|
||||
this.chars = oql.toCharArray();
|
||||
this.eof = oql.length();
|
||||
}
|
||||
|
||||
public int getPos() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
public String getWord() {
|
||||
return word;
|
||||
}
|
||||
|
||||
public String peekNextWord() {
|
||||
int origPos = pos;
|
||||
String nw = nextWordInternal();
|
||||
pos = origPos;
|
||||
return nw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the current and the next word.
|
||||
*/
|
||||
public boolean isMatch(String lowerMatch, String nextWordMatch) {
|
||||
|
||||
if (isMatch(lowerMatch)) {
|
||||
String nw = peekNextWord();
|
||||
if (nw != null) {
|
||||
nw = nw.toLowerCase();
|
||||
return nw.equals(nextWordMatch);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isFinished() {
|
||||
return word == null;
|
||||
}
|
||||
|
||||
public int findWordLower(String lowerMatch, int afterPos) {
|
||||
this.pos = afterPos;
|
||||
return findWordLower(lowerMatch);
|
||||
}
|
||||
|
||||
public int findWordLower(String lowerMatch) {
|
||||
do {
|
||||
if (nextWord() == null) {
|
||||
return -1;
|
||||
}
|
||||
if (lowerMatch.equals(lowerWord)) {
|
||||
return pos - lowerWord.length();
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the current word.
|
||||
*/
|
||||
public boolean isMatch(String lowerMatch) {
|
||||
return lowerMatch.equals(lowerWord);
|
||||
}
|
||||
|
||||
public String nextWord() {
|
||||
word = nextWordInternal();
|
||||
if (word != null) {
|
||||
lowerWord = word.toLowerCase();
|
||||
}
|
||||
return word;
|
||||
}
|
||||
|
||||
private String nextWordInternal() {
|
||||
trimLeadingWhitespace();
|
||||
if (pos >= eof) {
|
||||
return null;
|
||||
}
|
||||
int start = pos;
|
||||
if (chars[pos] == '(') {
|
||||
moveToClose();
|
||||
} else {
|
||||
moveToEndOfWord();
|
||||
}
|
||||
return oql.substring(start, pos);
|
||||
}
|
||||
|
||||
private void moveToClose() {
|
||||
|
||||
pos++;
|
||||
int openParenthesisCount = 0;
|
||||
|
||||
for (; pos < eof; pos++) {
|
||||
char c = chars[pos];
|
||||
if (c == '(') {
|
||||
// count nested parenthesis
|
||||
openParenthesisCount++;
|
||||
|
||||
} else if (c == ')') {
|
||||
if (openParenthesisCount > 0) {
|
||||
// still in nested parenthesis
|
||||
--openParenthesisCount;
|
||||
} else {
|
||||
// we have found the end
|
||||
pos++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void moveToEndOfWord() {
|
||||
char c = chars[pos];
|
||||
boolean isOperator = isOperator(c);
|
||||
for (; pos < eof; pos++) {
|
||||
c = chars[pos];
|
||||
if (isWordTerminator(c, isOperator)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWordTerminator(char c, boolean isOperator) {
|
||||
if (Character.isWhitespace(c)) {
|
||||
return true;
|
||||
}
|
||||
if (isOperator(c)) {
|
||||
return !isOperator;
|
||||
}
|
||||
return c == '(' || isOperator;
|
||||
}
|
||||
|
||||
private boolean isOperator(char c) {
|
||||
switch (c) {
|
||||
case '<':
|
||||
return true;
|
||||
case '>':
|
||||
return true;
|
||||
case '=':
|
||||
return true;
|
||||
case '!':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void trimLeadingWhitespace() {
|
||||
for (; pos < eof; pos++) {
|
||||
char c = chars[pos];
|
||||
if (!Character.isWhitespace(c)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Execute a TxCallable in a Transaction scope.
|
||||
* <p>
|
||||
* Use this with the {@link Ebean#execute(TxCallable)} method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that this is basically the same as TxRunnable except that it returns an
|
||||
* Object (and you specify the return type via generics).
|
||||
* </p>
|
||||
* <p>
|
||||
* See also {@link TxRunnable}.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Ebean.execute(new TxCallable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* User u2 = Ebean.find(User.class, 2);
|
||||
*
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
*
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
*
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @see TxRunnable
|
||||
*/
|
||||
public interface TxCallable<T> {
|
||||
|
||||
/**
|
||||
* Execute the method within a transaction scope returning the result.
|
||||
* <p>
|
||||
* If you do not want to return a result you should look to use TxRunnable
|
||||
* instead.
|
||||
* </p>
|
||||
*/
|
||||
T call();
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* The Transaction Isolation levels.
|
||||
* <p>
|
||||
* These match those of java.sql.Connection with the addition of DEFAULT which
|
||||
* implies the configured default of the DataSource.
|
||||
* </p>
|
||||
* <p>
|
||||
* This can be used with TxScope to define transactional scopes to execute
|
||||
* method within.
|
||||
* </p>
|
||||
*
|
||||
* @see TxScope
|
||||
*/
|
||||
public enum TxIsolation {
|
||||
|
||||
/**
|
||||
* Read Committed Isolation level. This is typically the default for most
|
||||
* configurations.
|
||||
*/
|
||||
READ_COMMITED(Connection.TRANSACTION_READ_COMMITTED),
|
||||
|
||||
/**
|
||||
* Read uncommitted Isolation level.
|
||||
*/
|
||||
READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
|
||||
|
||||
/**
|
||||
* Repeatable Read Isolation level.
|
||||
*/
|
||||
REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
|
||||
|
||||
/**
|
||||
* Serializable Isolation level.
|
||||
*/
|
||||
SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE),
|
||||
|
||||
/**
|
||||
* No Isolation level.
|
||||
*/
|
||||
NONE(Connection.TRANSACTION_NONE),
|
||||
|
||||
/**
|
||||
* The default isolation level. This typically means the default that the
|
||||
* DataSource is using or configured to use.
|
||||
*/
|
||||
DEFAULT(-1);
|
||||
|
||||
final int level;
|
||||
|
||||
TxIsolation(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the level as per java.sql.Connection.
|
||||
* <p>
|
||||
* Note that -1 denotes the default isolation level.
|
||||
* </p>
|
||||
*/
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TxIsolation given the java.sql.Connection isolation level.
|
||||
* <p>
|
||||
* Note that -1 denotes the default isolation level.
|
||||
* </p>
|
||||
*/
|
||||
public static TxIsolation fromLevel(int connectionIsolationLevel) {
|
||||
|
||||
switch (connectionIsolationLevel) {
|
||||
case Connection.TRANSACTION_READ_UNCOMMITTED:
|
||||
return TxIsolation.READ_UNCOMMITTED;
|
||||
|
||||
case Connection.TRANSACTION_READ_COMMITTED:
|
||||
return TxIsolation.READ_COMMITED;
|
||||
|
||||
case Connection.TRANSACTION_REPEATABLE_READ:
|
||||
return TxIsolation.REPEATABLE_READ;
|
||||
|
||||
case Connection.TRANSACTION_SERIALIZABLE:
|
||||
return TxIsolation.SERIALIZABLE;
|
||||
|
||||
case Connection.TRANSACTION_NONE:
|
||||
return TxIsolation.NONE;
|
||||
|
||||
case -1:
|
||||
return TxIsolation.DEFAULT;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Unknown isolation level " + connectionIsolationLevel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Execute a TxRunnable in a Transaction scope.
|
||||
* <p>
|
||||
* Use this with the {@link Ebean#execute(TxRunnable)} method.
|
||||
* </p>
|
||||
* <p>
|
||||
* See also {@link TxCallable}.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* // this run method runs in a transaction scope
|
||||
* // which by default is TxScope.REQUIRED
|
||||
*
|
||||
* Ebean.execute(new TxRunnable() {
|
||||
* public void run() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* User u2 = Ebean.find(User.class, 2);
|
||||
*
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
*
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @see TxCallable
|
||||
*/
|
||||
public interface TxRunnable {
|
||||
|
||||
/**
|
||||
* Run the method in a transaction sope.
|
||||
*/
|
||||
void run();
|
||||
}
|
||||
@@ -1,339 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Holds the definition of how a transactional method should run.
|
||||
* <p>
|
||||
* This information matches the features of the Transactional annotation. You
|
||||
* can use it directly with TxRunnable or TxCallable via
|
||||
* {@link Ebean#execute(TxScope, TxCallable)} or
|
||||
* {@link Ebean#execute(TxScope, TxRunnable)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This object is used internally with the enhancement of a method with
|
||||
* Transactional annotation.
|
||||
* </p>
|
||||
*
|
||||
* @see TxCallable
|
||||
* @see TxRunnable
|
||||
* @see Ebean#execute(TxScope, TxCallable)
|
||||
* @see Ebean#execute(TxScope, TxRunnable)
|
||||
*/
|
||||
public final class TxScope {
|
||||
|
||||
TxType type;
|
||||
|
||||
String serverName;
|
||||
|
||||
TxIsolation isolation;
|
||||
|
||||
PersistBatch batch;
|
||||
|
||||
PersistBatch batchOnCascade;
|
||||
|
||||
int batchSize;
|
||||
|
||||
boolean skipGeneratedKeys;
|
||||
|
||||
boolean readOnly;
|
||||
|
||||
ArrayList<Class<? extends Throwable>> rollbackFor;
|
||||
|
||||
ArrayList<Class<? extends Throwable>> noRollbackFor;
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with REQUIRES.
|
||||
*/
|
||||
public static TxScope required() {
|
||||
return new TxScope(TxType.REQUIRED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with REQUIRES_NEW.
|
||||
*/
|
||||
public static TxScope requiresNew() {
|
||||
return new TxScope(TxType.REQUIRES_NEW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with MANDATORY.
|
||||
*/
|
||||
public static TxScope mandatory() {
|
||||
return new TxScope(TxType.MANDATORY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with SUPPORTS.
|
||||
*/
|
||||
public static TxScope supports() {
|
||||
return new TxScope(TxType.SUPPORTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with NOT_SUPPORTED.
|
||||
*/
|
||||
public static TxScope notSupported() {
|
||||
return new TxScope(TxType.NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with NEVER.
|
||||
*/
|
||||
public static TxScope never() {
|
||||
return new TxScope(TxType.NEVER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a REQUIRED transaction scope.
|
||||
*/
|
||||
public TxScope() {
|
||||
this.type = TxType.REQUIRED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with a given transaction scope type.
|
||||
*/
|
||||
public TxScope(TxType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes this TxScope instance.
|
||||
*/
|
||||
public String toString() {
|
||||
return "TxScope[" + type + "] readOnly[" + readOnly + "] isolation[" + isolation
|
||||
+ "] serverName[" + serverName
|
||||
+ "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if PersistBatch has been set.
|
||||
*/
|
||||
public boolean isBatchSet() {
|
||||
return batch != null && batch != PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if batch on cascade has been set.
|
||||
*/
|
||||
public boolean isBatchOnCascadeSet() {
|
||||
return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if batch size has been set.
|
||||
*/
|
||||
public boolean isBatchSizeSet() {
|
||||
return batchSize > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for batchSize being set without batch mode and use this to imply PersistBatch.ALL.
|
||||
*/
|
||||
public void checkBatchMode() {
|
||||
if (batchSize > 0 && notSet(batch) && notSet(batchOnCascade)) {
|
||||
// Use setting the batchSize as implying PersistBatch.ALL for @Transactional
|
||||
batch = PersistBatch.ALL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the mode is considered not set.
|
||||
*/
|
||||
private boolean notSet(PersistBatch batchMode) {
|
||||
return batchMode == null || batchMode == PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction type.
|
||||
*/
|
||||
public TxType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transaction type.
|
||||
*/
|
||||
public TxScope setType(TxType type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch mode.
|
||||
*/
|
||||
public PersistBatch getBatch() {
|
||||
return batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the batch mode to use.
|
||||
*/
|
||||
public TxScope setBatch(PersistBatch batch) {
|
||||
this.batch = batch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch on cascade mode.
|
||||
*/
|
||||
public PersistBatch getBatchOnCascade() {
|
||||
return batchOnCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the batch on cascade mode.
|
||||
*/
|
||||
public TxScope setBatchOnCascade(PersistBatch batchOnCascade) {
|
||||
this.batchOnCascade = batchOnCascade;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size. 0 means use the default value.
|
||||
*/
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the batch size to use.
|
||||
*/
|
||||
public TxScope setBatchSize(int batchSize) {
|
||||
this.batchSize = batchSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the transaction should skip reading generated keys for inserts.
|
||||
*/
|
||||
public TxScope setSkipGeneratedKeys() {
|
||||
this.skipGeneratedKeys = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if getGeneratedKeys should be skipped for this transaction.
|
||||
*/
|
||||
public boolean isSkipGeneratedKeys() {
|
||||
return skipGeneratedKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the transaction should be treated as read only.
|
||||
*/
|
||||
public boolean isReadonly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the transaction should be treated as read only.
|
||||
*/
|
||||
public TxScope setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Isolation level this transaction should run with.
|
||||
*/
|
||||
public TxIsolation getIsolation() {
|
||||
return isolation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transaction isolation level this transaction should run with.
|
||||
*/
|
||||
public TxScope setIsolation(TxIsolation isolation) {
|
||||
this.isolation = isolation;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the serverName for this transaction. If this is null then the
|
||||
* default server (default DataSource) will be used.
|
||||
*/
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the serverName (DataSource name) for which this transaction will be. If
|
||||
* the serverName is not specified (left null) then the default server will be
|
||||
* used.
|
||||
*/
|
||||
public TxScope setServerName(String serverName) {
|
||||
this.serverName = serverName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the throwable's that should cause a rollback.
|
||||
*/
|
||||
public ArrayList<Class<? extends Throwable>> getRollbackFor() {
|
||||
return rollbackFor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Throwable that should explicitly cause a rollback.
|
||||
*/
|
||||
public TxScope setRollbackFor(Class<? extends Throwable> rollbackThrowable) {
|
||||
if (rollbackFor == null) {
|
||||
rollbackFor = new ArrayList<Class<? extends Throwable>>(2);
|
||||
}
|
||||
rollbackFor.add(rollbackThrowable);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set multiple throwable's that will cause a rollback.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public TxScope setRollbackFor(Class<?>[] rollbackThrowables) {
|
||||
if (rollbackFor == null) {
|
||||
rollbackFor = new ArrayList<Class<? extends Throwable>>(rollbackThrowables.length);
|
||||
}
|
||||
for (int i = 0; i < rollbackThrowables.length; i++) {
|
||||
rollbackFor.add((Class<? extends Throwable>) rollbackThrowables[i]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the throwable's that should NOT cause a rollback.
|
||||
*/
|
||||
public ArrayList<Class<? extends Throwable>> getNoRollbackFor() {
|
||||
return noRollbackFor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Throwable to a list that will NOT cause a rollback. You are able to
|
||||
* call this method multiple times with different throwable's and they will
|
||||
* added to a list.
|
||||
*/
|
||||
public TxScope setNoRollbackFor(Class<? extends Throwable> noRollback) {
|
||||
if (noRollbackFor == null) {
|
||||
noRollbackFor = new ArrayList<Class<? extends Throwable>>(2);
|
||||
}
|
||||
this.noRollbackFor.add(noRollback);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set multiple throwable's that will NOT cause a rollback.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public TxScope setNoRollbackFor(Class<?>[] noRollbacks) {
|
||||
if (noRollbackFor == null) {
|
||||
noRollbackFor = new ArrayList<Class<? extends Throwable>>(noRollbacks.length);
|
||||
}
|
||||
for (int i = 0; i < noRollbacks.length; i++) {
|
||||
noRollbackFor.add((Class<? extends Throwable>) noRollbacks[i]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Used to define the transactional scope for executing a method. Matches the
|
||||
* types defined in the EJB TransactionAttributeType.
|
||||
* <p>
|
||||
* Used with the Transactional annotation and the {@link TxScope} with
|
||||
* {@link Ebean#execute(TxScope, TxCallable)} and
|
||||
* {@link Ebean#execute(TxScope, TxRunnable)}.
|
||||
* </p>
|
||||
*
|
||||
* @see TxScope
|
||||
*/
|
||||
public enum TxType {
|
||||
|
||||
/**
|
||||
* Uses an existing transaction and if none exists will starts a new
|
||||
* Transaction. This is the default.
|
||||
*/
|
||||
REQUIRED,
|
||||
|
||||
/**
|
||||
* A transaction MUST already have been started. Throws
|
||||
* TransactionRequiredException.
|
||||
*/
|
||||
MANDATORY,
|
||||
|
||||
/**
|
||||
* Uses the existing transaction if one exists, otherwise the method does not
|
||||
* run with a transaction. Used this with caution.
|
||||
*/
|
||||
SUPPORTS,
|
||||
|
||||
/**
|
||||
* Always start a new transaction. Suspend an existing once if required.
|
||||
*/
|
||||
REQUIRES_NEW,
|
||||
|
||||
/**
|
||||
* Suspends an existing transaction if required. Method runs without a
|
||||
* transaction.
|
||||
*/
|
||||
NOT_SUPPORTED,
|
||||
|
||||
/**
|
||||
* If there is an existing transaction throws an Exception. Method runs
|
||||
* without a transaction.
|
||||
*/
|
||||
NEVER
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* An Insert Update or Delete statement.
|
||||
* <p>
|
||||
* Generally a named update will be defined on the entity bean. This will take
|
||||
* the form of either an actual sql insert update delete statement or a similar
|
||||
* statement with bean name and property names in place of database table and
|
||||
* column names. The statement will likely include named parameters.
|
||||
* </p>
|
||||
* <p>
|
||||
* The following is an example of named updates on an entity bean.
|
||||
* </p>
|
||||
*
|
||||
* <pre type="class">
|
||||
* ...
|
||||
* @NamedUpdates(value = {
|
||||
* @NamedUpdate(
|
||||
* name = "setTitle",
|
||||
* notifyCache = false,
|
||||
* update = "update topic set title = :title, postCount = :count where id = :id"),
|
||||
* @NamedUpdate(
|
||||
* name = "setPostCount",
|
||||
* notifyCache = false,
|
||||
* update = "update f_topic set post_count = :postCount where id = :id"),
|
||||
* @NamedUpdate(
|
||||
* name = "incrementPostCount",
|
||||
* notifyCache = false,
|
||||
* update = "update Topic set postCount = postCount + 1 where id = :id")
|
||||
* //update = "update f_topic set post_count = post_count + 1 where id = :id")
|
||||
* })
|
||||
* @Entity
|
||||
* @Table(name = "f_topic")
|
||||
* public class Topic {
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* The following show code that would use a named update on the Topic entity
|
||||
* bean.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Update<Topic> update = Ebean.createUpdate(Topic.class, "incrementPostCount");
|
||||
* update.setParameter("id", 1);
|
||||
* int rows = update.execute();
|
||||
* </pre>
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity beans inserted updated or deleted
|
||||
*/
|
||||
public interface Update<T> {
|
||||
|
||||
/**
|
||||
* Return the name if it is a named update.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Set this to false if you do not want the cache to invalidate related
|
||||
* objects.
|
||||
* <p>
|
||||
* If you don't set this Ebean will automatically invalidate the appropriate
|
||||
* parts of the "L2" server cache.
|
||||
* </p>
|
||||
*/
|
||||
Update<T> setNotifyCache(boolean notifyCache);
|
||||
|
||||
/**
|
||||
* Set a timeout for statement execution.
|
||||
* <p>
|
||||
* This will typically result in a call to setQueryTimeout() on a
|
||||
* preparedStatement. If the timeout occurs an exception will be thrown - this
|
||||
* will be a SQLException wrapped up in a PersistenceException.
|
||||
* </p>
|
||||
*
|
||||
* @param secs
|
||||
* the timeout in seconds. Zero implies unlimited.
|
||||
*/
|
||||
Update<T> setTimeout(int secs);
|
||||
|
||||
/**
|
||||
* Execute the statement returning the number of rows modified.
|
||||
*/
|
||||
int execute();
|
||||
|
||||
/**
|
||||
* Set an ordered bind parameter.
|
||||
* <p>
|
||||
* position starts at value 1 (not 0) to be consistent with PreparedStatement.
|
||||
* </p>
|
||||
* <p>
|
||||
* Set a value for each ? you have in the sql.
|
||||
* </p>
|
||||
*
|
||||
* @param position
|
||||
* the index position of the parameter starting with 1.
|
||||
* @param value
|
||||
* the parameter value to bind.
|
||||
*/
|
||||
Update<T> set(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set and ordered bind parameter (same as bind).
|
||||
*
|
||||
* @param position
|
||||
* the index position of the parameter starting with 1.
|
||||
* @param value
|
||||
* the parameter value to bind.
|
||||
*/
|
||||
Update<T> setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set an ordered parameter that is null. The JDBC type of the null must be
|
||||
* specified.
|
||||
* <p>
|
||||
* position starts at value 1 (not 0) to be consistent with PreparedStatement.
|
||||
* </p>
|
||||
*/
|
||||
Update<T> setNull(int position, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set an ordered parameter that is null (same as bind).
|
||||
*/
|
||||
Update<T> setNullParameter(int position, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set a named parameter. Named parameters have a colon to prefix the name.
|
||||
* <p>
|
||||
* A more succinct version of setParameter() to be consistent with Query.
|
||||
* </p>
|
||||
*
|
||||
* @param name
|
||||
* the parameter name.
|
||||
* @param value
|
||||
* the parameter value.
|
||||
*/
|
||||
Update<T> set(String name, Object value);
|
||||
|
||||
/**
|
||||
* Bind a named parameter (same as bind).
|
||||
*/
|
||||
Update<T> setParameter(String name, Object param);
|
||||
|
||||
/**
|
||||
* Set a named parameter that is null. The JDBC type of the null must be
|
||||
* specified.
|
||||
* <p>
|
||||
* A more succinct version of setNullParameter().
|
||||
* </p>
|
||||
*
|
||||
* @param name
|
||||
* the parameter name.
|
||||
* @param jdbcType
|
||||
* the type of the property being bound.
|
||||
*/
|
||||
Update<T> setNull(String name, int jdbcType);
|
||||
|
||||
/**
|
||||
* Bind a named parameter that is null (same as bind).
|
||||
*/
|
||||
Update<T> setNullParameter(String name, int jdbcType);
|
||||
|
||||
/**
|
||||
* Return the sql that is actually executed.
|
||||
*/
|
||||
String getGeneratedSql();
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the default cache use specific entity type.
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Cache {
|
||||
|
||||
/**
|
||||
* Set this to true to enable the use of query cache.
|
||||
* <p>
|
||||
* By default query caching is disabled as the query cache invalidates
|
||||
* frequently and so it is typically used for specific bean types and cases.
|
||||
* </p>
|
||||
*/
|
||||
boolean enableQueryCache() default false;
|
||||
|
||||
/**
|
||||
* Set this to false to disable the use of bean cache.
|
||||
* <p>
|
||||
* By default bean caching is expected so this defaults to true. We might
|
||||
* set this to false on a bean type that we want to use query caching but no
|
||||
* bean caching (and this is expected to be a rare case).
|
||||
* </p>
|
||||
* <p>
|
||||
* When bean caching is enabled by default "find by id" and "find by unique natural key"
|
||||
* queries will try to use the bean cache. We use {@link com.avaje.ebean.Query#setUseCache(boolean)}
|
||||
* with <code>false</code> for the case when we do NOT want to use the bean cache.
|
||||
* </p>
|
||||
*/
|
||||
boolean enableBeanCache() default true;
|
||||
|
||||
/**
|
||||
* Specify the property that is a natural unique identifier for the bean.
|
||||
* <p>
|
||||
* When a findUnique() query is used with this property as the sole expression
|
||||
* then there will be a lookup into the L2 natural key cache.
|
||||
* </p>
|
||||
*/
|
||||
String naturalKey() default "";
|
||||
|
||||
/**
|
||||
* When set to true the beans returned from a query will default to be
|
||||
* readOnly.
|
||||
* <p>
|
||||
* If the bean is readOnly and has no relationships then it may be sharable.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you try to modify a readOnly bean it will throw an
|
||||
* IllegalStateException.
|
||||
* </p>
|
||||
*/
|
||||
boolean readOnly() default false;
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Cache tuning hints for the L2 bean cache of a specific entity type.
|
||||
* <p>
|
||||
* Note that this is not useful when distributed L2 bean caches are used like
|
||||
* ElasticSearch, Hazelcast, Ignite etc.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CacheBeanTuning {
|
||||
|
||||
/**
|
||||
* The maximum size for the cache.
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxSize() default 0;
|
||||
|
||||
/**
|
||||
* The maximum time (in seconds) that a cache entry is allowed to stay in the
|
||||
* cache when it has not been accessed.
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxIdleSecs() default 0;
|
||||
|
||||
/**
|
||||
* The maximum time (in seconds) a cache entry is allowed to stay in the
|
||||
* cache.
|
||||
* <p>
|
||||
* This is not generally required as the cache entries are automatically
|
||||
* evicted when related data changes are committed.
|
||||
* </p>
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxSecsToLive() default 0;
|
||||
|
||||
/**
|
||||
* The frequency (in seconds) that cache trimming should occur.
|
||||
* <p>
|
||||
* This is a hint for cache implementations that use background cache trimming.
|
||||
* </p>
|
||||
*/
|
||||
int trimFrequency() default 0;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify cache tuning for query caching on a specific entity type.
|
||||
* <p>
|
||||
* If this is not specified then the system default settings are used.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CacheQueryTuning {
|
||||
|
||||
/**
|
||||
* The maximum size for the cache.
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxSize() default 0;
|
||||
|
||||
/**
|
||||
* The maximum time (in seconds) that a cache entry is allowed to stay in the
|
||||
* cache when it has not been accessed.
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxIdleSecs() default 0;
|
||||
|
||||
/**
|
||||
* The maximum time (in seconds) a cache entry is allowed to stay in the
|
||||
* cache.
|
||||
* <p>
|
||||
* This is not generally required as the cache entries are automatically
|
||||
* evicted when related data changes are committed.
|
||||
* </p>
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxSecsToLive() default 0;
|
||||
|
||||
/**
|
||||
* The frequency (in seconds) that cache trimming should occur.
|
||||
* <p>
|
||||
* This is a hint for cache implementations that use background cache trimming.
|
||||
* </p>
|
||||
*/
|
||||
int trimFrequency() default 0;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks an entity bean as being included in the change logging.
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ChangeLog {
|
||||
|
||||
/**
|
||||
* Specify if inserts should be explicitly Included or Excluded.
|
||||
* <p>
|
||||
* If not defined explicitly then the server default behaviour defined
|
||||
* on ServerConfig is used.
|
||||
* </p>
|
||||
*/
|
||||
ChangeLogInsertMode inserts() default ChangeLogInsertMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* When specified only include update requests that have at least one
|
||||
* of the given properties as a dirty property.
|
||||
* <p>
|
||||
* This provides a way to filter requests to include in the change log such that
|
||||
* only updates that include at least one of the given properties is included
|
||||
* in the change log.
|
||||
* </p>
|
||||
*/
|
||||
String[] updatesThatInclude() default {};
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
/**
|
||||
* The mode used to determine if inserts should be included or not for a given bean type.
|
||||
*/
|
||||
public enum ChangeLogInsertMode {
|
||||
|
||||
/**
|
||||
* Use the default behaviour as defined on ServerConfig.
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* Include inserts in the change log.
|
||||
*/
|
||||
INCLUDE,
|
||||
|
||||
/**
|
||||
* Exclude inserts in the change log.
|
||||
*/
|
||||
EXCLUDE
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* For a timestamp property that is set to the datetime when the entity is
|
||||
* created/inserted.
|
||||
* <p>
|
||||
* This is effectively an alias for @WhenCreated which was added as it hints
|
||||
* towards a better naming convention (WhenCreated, WhenModified).
|
||||
* </p>
|
||||
* <p>
|
||||
* An alternative to using this annotation would be to use insertable=false,
|
||||
* updateable=false with @Column and have the DB insert the current time
|
||||
* (default value on the DB column is SYSTIME etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* The downside to this approach is that the inserted entity does not have the
|
||||
* timestamp value after the insert has occurred. You need to fetch the entity
|
||||
* back to get the inserted timestamp if you want to used it.
|
||||
* </p>
|
||||
*
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @CreatedTimestamp
|
||||
* Timestamp whenCreated;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CreatedTimestamp {
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify a collection property that will be stored into a DB ARRAY type.
|
||||
* <p>
|
||||
* If the target database does not support ARRAY type (so not Postgres)
|
||||
* then the collection will be stored in JSON format into a VARCHAR column.
|
||||
* </p>
|
||||
*
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Store as ARRAY of UUID on Postgres
|
||||
* @DbArray
|
||||
* List<UUID> uids = new ArrayList<>();
|
||||
*
|
||||
* // Store as ARRAY on Postgres
|
||||
* @DbArray
|
||||
* List<String> phoneNumbers = new ArrayList<>();
|
||||
*
|
||||
* // Store as ARRAY of INTEGER on Postgres
|
||||
* @DbArray
|
||||
* List<Long> someLongs = new ArrayList<>();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DbArray {
|
||||
|
||||
/**
|
||||
* For VARCHAR storage specify the column length (defaults to 1000).
|
||||
*/
|
||||
int length() default 0;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* A database table or column comment.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
|
||||
public @interface DbComment {
|
||||
|
||||
/**
|
||||
* The database table or column comment.
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
/**
|
||||
* Specify the DB storage type used to with <code>@DbEnumValue</code>.
|
||||
*/
|
||||
public enum DbEnumType {
|
||||
|
||||
/**
|
||||
* Store values as database INTEGER.
|
||||
*/
|
||||
INTEGER,
|
||||
|
||||
/**
|
||||
* Store values as database VARCHAR.
|
||||
*/
|
||||
VARCHAR
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify a method on an Enum that returns the value that should be stored in the DB.
|
||||
* <p>
|
||||
* This is the preferred option for mapping Enum's to DB values (preferred over the JPA
|
||||
* standard @Enumerated and Ebean's @EnumValue annotations).
|
||||
* </p>
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* public enum Status {
|
||||
* NEW("N"),
|
||||
* ACTIVE("A"),
|
||||
* INACTIVE("I");
|
||||
*
|
||||
* String dbValue;
|
||||
* Status(String dbValue) {
|
||||
* this.dbValue = dbValue;
|
||||
* }
|
||||
*
|
||||
* @DbEnumValue
|
||||
* public String getValue() {
|
||||
* return dbValue;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface DbEnumValue {
|
||||
|
||||
/**
|
||||
* Specify the database type used to store the values (VARCHAR or INTEGER).
|
||||
*/
|
||||
DbEnumType storage() default DbEnumType.VARCHAR;
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used for mapping a Map<String,String> type property to Postgres HSTORE data type.
|
||||
* <p>
|
||||
* The Map property should have keys and values of type String.
|
||||
* </p>
|
||||
*
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @DbHstore
|
||||
* Map<String, String> tags;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DbHstore {
|
||||
|
||||
/**
|
||||
* For VARCHAR storage specify the column length (defaults to 1000).
|
||||
*/
|
||||
int length() default 0;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify a property holding JSON content.
|
||||
* <p>
|
||||
* By default the content will be stored in a DB Clob except on Postgres where DB JSON type is used.
|
||||
* </p>
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Store as JSON on Postgres or Clob on other databases
|
||||
* @DbJson
|
||||
* Map<String,Object> content;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Example with JSONB storage</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Store as JSONB on Postgres or Clob on other databases
|
||||
* @DbJson(storage = DbJsonType.JSONB)
|
||||
* Map<String,Object> content;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DbJson {
|
||||
|
||||
/**
|
||||
* Specify the database type used to store the JSON content.
|
||||
*/
|
||||
DbJsonType storage() default DbJsonType.JSON;
|
||||
|
||||
/**
|
||||
* For VARCHAR storage specify the column length (defaults to 3000).
|
||||
*/
|
||||
int length() default 0;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify a property holding JSON content.
|
||||
* <p>
|
||||
* The content will be stored on Postgres using it's JSONB type and as Clob for other databases.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is equivalent to using <code>@DbJson(storage = DbJsonType.JSONB)</code>
|
||||
* </p>
|
||||
*
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Store as JSONB on Postgres or Clob on other databases
|
||||
* @DbJsonB
|
||||
* Map<String,Object> content;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Equivalent to:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Store as JSONB on Postgres or Clob on other databases
|
||||
* @DbJson(storage = DbJsonType.JSONB)
|
||||
* Map<String,Object> content;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DbJsonB {
|
||||
|
||||
/**
|
||||
* For VARCHAR storage specify the column length.
|
||||
*/
|
||||
int length() default 0;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
/**
|
||||
* Specify the DB storage type used to store JSON content.
|
||||
*/
|
||||
public enum DbJsonType {
|
||||
|
||||
/**
|
||||
* Store as JSON on Postgres and for other databases store as CLOB.
|
||||
*/
|
||||
JSON,
|
||||
|
||||
/**
|
||||
* Store as JSONB on Postgres and for other databases store as CLOB.
|
||||
*/
|
||||
JSONB,
|
||||
|
||||
/**
|
||||
* Store as database VARCHAR.
|
||||
*/
|
||||
VARCHAR,
|
||||
|
||||
/**
|
||||
* Store as database CLOB.
|
||||
*/
|
||||
CLOB,
|
||||
|
||||
/**
|
||||
* Store as database BLOB.
|
||||
*/
|
||||
BLOB
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used to indicate that a particular string property should be treated as a 'code' and not analysed for text searching.
|
||||
* <p>
|
||||
* By default all Id properties and all Enum properties are treated as 'code' and not analysed.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocCode {
|
||||
|
||||
/**
|
||||
* Set to true to have the property additionally stored separately from _source.
|
||||
*/
|
||||
boolean store() default false;
|
||||
|
||||
/**
|
||||
* Set a boost value specific to this property.
|
||||
*/
|
||||
float boost() default 1;
|
||||
|
||||
/**
|
||||
* Set a value to use instead of null.
|
||||
*/
|
||||
String nullValue() default "";
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the property is included in the parent document store index.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
*
|
||||
* @DocStore
|
||||
* @Entity @Table(name = "o_order")
|
||||
* public class Order {
|
||||
*
|
||||
* ...
|
||||
* // include some customer details including
|
||||
* // nested billingAddress
|
||||
* @DocEmbedded(doc = "id,status,name,billingAddress(*,country(*)")
|
||||
* @ManyToOne
|
||||
* Customer customer;
|
||||
*
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocEmbedded {
|
||||
|
||||
/**
|
||||
* The properties on the embedded bean to include in the index.
|
||||
*/
|
||||
String doc() default "";
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the entity type maps to a document store (like ElasticSearch).
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocMapping {
|
||||
|
||||
/**
|
||||
* The property name the mapping applies to.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Mapping options.
|
||||
*/
|
||||
DocProperty options();
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the entity type maps to a document store (like ElasticSearch).
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocProperty {
|
||||
|
||||
/**
|
||||
* Set this to true to indicate that this property should be un-analysed.
|
||||
*/
|
||||
boolean code() default false;
|
||||
|
||||
/**
|
||||
* Set this to true to get an additional un-analysed 'raw' field to use for sorting etc.
|
||||
*/
|
||||
boolean sortable() default false;
|
||||
|
||||
/**
|
||||
* Set to true to have the property additionally stored separately from _source.
|
||||
*/
|
||||
boolean store() default false;
|
||||
|
||||
/**
|
||||
* Set a boost value specific to this property.
|
||||
*/
|
||||
float boost() default 1;
|
||||
|
||||
/**
|
||||
* Set a value to use instead of null.
|
||||
*/
|
||||
String nullValue() default "";
|
||||
|
||||
/**
|
||||
* Set this to false to exclude this from the _all property.
|
||||
*/
|
||||
boolean includeInAll() default true;
|
||||
|
||||
/**
|
||||
* The analyzer to use.
|
||||
*/
|
||||
String analyzer() default "";
|
||||
|
||||
/**
|
||||
* The analyzer to use for searches.
|
||||
*/
|
||||
String searchAnalyzer() default "";
|
||||
|
||||
/**
|
||||
* The index options for this property.
|
||||
*/
|
||||
Option options() default Option.DEFAULT;
|
||||
|
||||
/**
|
||||
* Set this to false such that doc values are not stored separately for this property.
|
||||
*/
|
||||
boolean docValues() default true;
|
||||
|
||||
/**
|
||||
* Set a copyTo field.
|
||||
*/
|
||||
String copyTo() default "";
|
||||
|
||||
/**
|
||||
* Set to false to disable the field from indexing, it will only be get/set in _source.
|
||||
*/
|
||||
boolean enabled() default true;
|
||||
|
||||
/**
|
||||
* Set to false such that norms are not stored.
|
||||
*/
|
||||
boolean norms() default true;
|
||||
|
||||
/**
|
||||
* Index options for a property.
|
||||
*/
|
||||
enum Option {
|
||||
|
||||
/**
|
||||
* Only index the doc number.
|
||||
*/
|
||||
DOCS,
|
||||
|
||||
/**
|
||||
* Doc number and term frequencies are indexed.
|
||||
*/
|
||||
FREQS,
|
||||
|
||||
/**
|
||||
* Doc number, term frequencies and term positions are indexed.
|
||||
*/
|
||||
POSITIONS,
|
||||
|
||||
/**
|
||||
* Doc number, term frequencies, term positions and start/end offsets are indexed.
|
||||
*/
|
||||
OFFSETS,
|
||||
|
||||
/**
|
||||
* Use the default which means analysed string properties use POSITIONS as the default and all other types use DOCS.
|
||||
*/
|
||||
DEFAULT
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used to indicate that a particular string property should support sorting. What this typically means is that
|
||||
* for ElasticSearch an additional 'raw' field is added that stores the un-analysed value. This un-analysed value
|
||||
* can be used for sorting etc and the original field used for text searching.
|
||||
* <p>
|
||||
* For example, customer name and product name are good candidates for marking with @DocSortable.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocSortable {
|
||||
|
||||
/**
|
||||
* Set to true to have the property additionally stored separately from _source.
|
||||
*/
|
||||
boolean store() default false;
|
||||
|
||||
/**
|
||||
* Set a boost value specific to this property.
|
||||
*/
|
||||
float boost() default 1;
|
||||
|
||||
/**
|
||||
* Set a value to use instead of null.
|
||||
*/
|
||||
String nullValue() default "";
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the entity type maps to a document store (like ElasticSearch).
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocStore {
|
||||
|
||||
/**
|
||||
* A unique Id used when queuing reindex events.
|
||||
*/
|
||||
String queueId() default "";
|
||||
|
||||
/**
|
||||
* The ElasticSearch index name. If left unspecified the short name of the bean type is used.
|
||||
*/
|
||||
String indexName() default "";
|
||||
|
||||
/**
|
||||
* The ElasticSearch index type. If left unspecified the short name of the bean type is used.
|
||||
*/
|
||||
String indexType() default "";
|
||||
|
||||
/**
|
||||
* The number of shards this index should use.
|
||||
*/
|
||||
int shards() default 0;
|
||||
|
||||
/**
|
||||
* The number of replicas this index should use.
|
||||
*/
|
||||
int replicas() default 0;
|
||||
|
||||
/**
|
||||
* Additional mapping that can be defined on the properties.
|
||||
*/
|
||||
DocMapping[] mapping() default {};
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Insert, Update, Delete events occur.
|
||||
*/
|
||||
DocStoreMode persist() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Insert occurs.
|
||||
*/
|
||||
DocStoreMode insert() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Update occurs.
|
||||
*/
|
||||
DocStoreMode update() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Delete occurs.
|
||||
*/
|
||||
DocStoreMode delete() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify to include only some properties in the doc store document.
|
||||
* <p>
|
||||
* If this is left as default then all scalar properties are included,
|
||||
* all @ManyToOne properties are included with just the nested id property
|
||||
* and no @OneToMany properties are included.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that typically DocStoreEmbedded is used on @ManyToOne and @OneToMany
|
||||
* properties to indicate what part of the nested document should be included.
|
||||
* </p>
|
||||
*
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // only include the customer id and name
|
||||
* @DocStore(doc = "id,name")
|
||||
* @Entity @Table(name = "o_order")
|
||||
* public class Customer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
String doc() default "";
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
/**
|
||||
* Defines the behavior options when a Insert, Update or Delete event occurs
|
||||
* on a bean with an associated ElasticSearch index.
|
||||
* <p>
|
||||
* For some indexes or some transactions it can be beneficial to queue the event
|
||||
* for later processing rather than look to update ElasticSearch at that time.
|
||||
* </p>
|
||||
*/
|
||||
public enum DocStoreMode {
|
||||
|
||||
/**
|
||||
* Add the event to the queue for processing later (delaying the update to the document store).
|
||||
*/
|
||||
QUEUE,
|
||||
|
||||
/**
|
||||
* Update the document store when transaction succeeds.
|
||||
*/
|
||||
UPDATE,
|
||||
|
||||
/**
|
||||
* Ignore the event and not update the document store.
|
||||
* <p>
|
||||
* This can be used on a index or for a transaction where you want to have more
|
||||
* manual programmatic control over the updating of the document store. Say you want to
|
||||
* IGNORE on a particular transaction and instead manually queue a bulk update.
|
||||
* </p>
|
||||
*/
|
||||
IGNORE,
|
||||
|
||||
/**
|
||||
* The actual mode of QUEUE, UPDATE or IGNORE is set from the default configuration.
|
||||
*/
|
||||
DEFAULT
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks a boolean property on a @Draftable bean that indicates if the bean instance is a 'draft' or 'live' bean.
|
||||
* The property is transient and has no underlying DB column.
|
||||
* <p>
|
||||
* For beans returned from an <code>asDraft()</code> query this property will be set to true.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Draft {
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks a boolean property on a @Draftable bean that only exists on the 'draft' table
|
||||
* and is used to detect when a draft has unpublished changes.
|
||||
* <p>
|
||||
* This property will automatically have it's value set to true when a draft is saved and
|
||||
* automatically have it's value set to false when the bean is published.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DraftDirty {
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks a property on a @Draftable bean that only exists on the 'draft' and not the 'live' table.
|
||||
* <p>
|
||||
* Typically this would be used on a property that is used as part of application 'workflow' such as
|
||||
* a publish workflow status or when publish timestamp.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DraftOnly {
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks a property on a @Draftable bean that is set to null on the 'draft bean' on publish.
|
||||
* <p>
|
||||
* This is expected to be put on properties that get 'reset' or 'cleared' after a publish.
|
||||
* These properties might represent a publish comment or publish timestamp.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DraftReset {
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used to indicate an entity bean that has 'draftable' support.
|
||||
* <p>
|
||||
* This means that a second set of tables is created to hold draft versions of
|
||||
* the rows and that these can then be published which effectively copies/transfers
|
||||
* the values from the 'draft' table to the 'live' table.
|
||||
* </p>
|
||||
* <p>
|
||||
* Ebean Query supports 'find as draft' which builds the resulting object graph using
|
||||
* the draft tables. This object graph is typically edited, approved in some application
|
||||
* specific manor and then published.
|
||||
* </p>
|
||||
* <p>
|
||||
* EbeanServer has a publish method which transfers/copies the draft object graph to
|
||||
* the 'live' tables.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface Draftable {
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used to indicate an entity bean that has 'draftable' support but it not a 'top level'
|
||||
* (or root level) bean but instead child related to another @Draftable entity bean.
|
||||
* <p>
|
||||
* Relationships to @DraftableElements (@OneToMany, @ManyToMany etc) are automatically
|
||||
* deemed to have Cascade.ALL for save and delete (as well as orphan removal mode).
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface DraftableElement {
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify property name to db column mapping for Embedded beans.
|
||||
* <p>
|
||||
* This is designed to be easier to use than the AttributeOverride annotation in
|
||||
* standard JPA.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EmbeddedColumns {
|
||||
|
||||
/**
|
||||
* A list of property names mapped to DB columns.
|
||||
* <p>
|
||||
* For example <code>currency=IN_CURR, amount=IN_AMOUNT</code>
|
||||
* </p>
|
||||
* <p>
|
||||
* Where currency and amount are properties and IN_CURR and IN_AMOUNT are the
|
||||
* respective DB columns these properties will be mapped to.
|
||||
* </p>
|
||||
*/
|
||||
String columns() default "";
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify that the property is stored in encrypted form.
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Encrypted {
|
||||
|
||||
/**
|
||||
* When true try to use DB encryption rather than local java encryption.
|
||||
*/
|
||||
boolean dbEncryption() default true;
|
||||
|
||||
/**
|
||||
* Used to specify the DB column length.
|
||||
*/
|
||||
int dbLength() default 0;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Enables you to specify a value to use to persist for an enum value.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* public enum Status {
|
||||
*
|
||||
* @EnumValue("N")
|
||||
* NEW,
|
||||
*
|
||||
* @EnumValue("A")
|
||||
* ACTIVE,
|
||||
*
|
||||
* @EnumValue("I")
|
||||
* INACTIVE,
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* This is an alternative to using the JPA standard approach or Ebean's
|
||||
* {@link DbEnumValue} annotation.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that if all the EnumValue values are parsable as Integers then Ebean
|
||||
* will persist and fetch them as integers - otherwise they will be persisted
|
||||
* and fetched as strings.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EnumValue {
|
||||
|
||||
/**
|
||||
* Specify the value to persist for a specific enum value.
|
||||
* <p>
|
||||
* If all the values are parsable as Integers then Ebean will persist and
|
||||
* fetch them as integers rather than strings.
|
||||
* </p>
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/*
|
||||
Copied from gson!!!
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Expose {
|
||||
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is written out in the JSON while
|
||||
* serializing. If {@code false}, the field marked with this annotation is skipped from the
|
||||
* serialized output. Defaults to {@code true}.
|
||||
*/
|
||||
boolean serialize() default true;
|
||||
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
|
||||
* If {@code false}, the field marked with this annotation is skipped during deserialization.
|
||||
* Defaults to {@code true}.
|
||||
*/
|
||||
boolean deserialize() default true;
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
/**
|
||||
* Assign to a property to be based on a SQL formula.
|
||||
* <p>
|
||||
* This is typically a SQL Literal value, SQL case statement, SQL function or
|
||||
* similar.
|
||||
* </p>
|
||||
* <p>
|
||||
* Any property based on a formula becomes a read only property.
|
||||
* </p>
|
||||
* <p>
|
||||
* You may also put use the Transient annotation with the Formula annotation.
|
||||
* The effect of the Transient annotation in this case is that the formula will
|
||||
* <b>NOT</b> be included in queries by default - you have to explicitly include
|
||||
* it via {@link Query#select(String)} or {@link Query#fetch(String, String, com.avaje.ebean.FetchConfig)}.
|
||||
* You may want to do this if the Formula is relatively expensive and only want
|
||||
* it included in the query when you explicitly state it.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // On the Order "master" bean
|
||||
* // ... a formula using the Order details
|
||||
* // ... sum(order_qty*unit_price)
|
||||
* @Transient
|
||||
* @Formula(select = "_b${ta}.total_amount", join = "join (select order_id, sum(order_qty*unit_price) as total_amount from o_order_detail group by order_id) as _b${ta} on _b${ta}.order_id = ${ta}.id")
|
||||
* Double totalAmount;
|
||||
*
|
||||
* </pre>
|
||||
* <p>
|
||||
* As the totalAmount formula is also Transient it is not included by default in
|
||||
* queries - it needs to be explicitly included.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // find by Id
|
||||
* Order o1 = Ebean.find(Order.class)
|
||||
* .select("id, totalAmount")
|
||||
* .setId(1).findUnique();
|
||||
*
|
||||
* // find list ... using totalAmount in the where clause
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .select("id, totalAmount")
|
||||
* .where()
|
||||
* .eq("status", Order.Status.NEW)
|
||||
* .gt("totalAmount", 10)
|
||||
* .findList();
|
||||
*
|
||||
* // as a join from customer
|
||||
* List<Customer> l0 = Ebean.find(Customer.class)
|
||||
* .select("id, name")
|
||||
* .fetch("orders", "status, totalAmount")
|
||||
* .where()
|
||||
* .gt("id", 0)
|
||||
* .gt("orders.totalAmount", 10)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Formula {
|
||||
|
||||
/**
|
||||
* The SQL to be used in the SELECT part of the SQL to populate a property.
|
||||
*/
|
||||
String select();
|
||||
|
||||
/**
|
||||
* OPTIONAL - the SQL to be used in the JOIN part of the SQL to support the
|
||||
* formula.
|
||||
* <p>
|
||||
* This is commonly used to join a 'dynamic view' to support aggregation such
|
||||
* as count, sum etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* The join string should start with either "left outer join" or "join".
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* You will almost certainly use the "${ta}" as a place holder for the table
|
||||
* alias of the table you are joining back to (the "base table" of the entity
|
||||
* bean).
|
||||
* </p>
|
||||
* <p>
|
||||
* The example below is used to support a total count of topics created by a
|
||||
* user.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* join (select user_id, count(*) as topic_count from f_topic group by user_id) as _tc on _tc.user_id = ${ta}.id
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
String join() default "";
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks an entity bean as having history support.
|
||||
* <p>
|
||||
* In Postgres for example this means there is an associated history table which is
|
||||
* typically automatically populated via database triggers.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface History {
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks a property as being excluded from history.
|
||||
* <p>
|
||||
* This means the property values are not maintained in the history table. Typically this
|
||||
* would be placed on relatively large properties (Clobs, Blobs, large varchar columns etc)
|
||||
* that are considered not interesting enough to maintain history on excluding them reduces
|
||||
* underlying database costs.
|
||||
* </p>
|
||||
* <p>
|
||||
* When placed on a ManyToMany this means that the intersection table does not have history
|
||||
* support.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface HistoryExclude {
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation for declaring an index.
|
||||
*
|
||||
* @author rvbiljouw
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(Indices.class)
|
||||
public @interface Index {
|
||||
|
||||
/**
|
||||
* Name of the index. If left blank a name is derived using the built in naming convention.
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* If set true indicates this is a unique index.
|
||||
*/
|
||||
boolean unique() default false;
|
||||
|
||||
/**
|
||||
* When placed on the class (rather than field) you can specify the columns
|
||||
* to include in the index in order.
|
||||
*
|
||||
* Wnen placed on a field, and columnNames are specified, the field-column has to be included.
|
||||
* You can use "${fa}" for alias
|
||||
*/
|
||||
String[] columnNames() default {};
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
/**
|
||||
* An annotation for declaring multiple indices at class or field level.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Indices {
|
||||
|
||||
/**
|
||||
* Array with {@link Index} definitions.
|
||||
*/
|
||||
Index[] value() default {};
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Similar to Jackson JsonIgnore but provides the option to just ignore serialize or deserialize.
|
||||
* <p>
|
||||
* This provides the same features as Expose but from the opposite perspective which is probably
|
||||
* more common and more familiar to Jackson users.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface JsonIgnore {
|
||||
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is written out in the JSON while
|
||||
* serializing. If {@code false}, the field marked with this annotation is skipped from the
|
||||
* serialized output. Defaults to {@code false}.
|
||||
*/
|
||||
boolean serialize() default false;
|
||||
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
|
||||
* If {@code false}, the field marked with this annotation is skipped during deserialization.
|
||||
* Defaults to {@code false}.
|
||||
*/
|
||||
boolean deserialize() default false;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify that the elements of a OneToMany are private owned.
|
||||
* <p>
|
||||
* This means that if they are removed from the List/Set/Map they will be
|
||||
* deleted when their parent object is saved.
|
||||
* </p>
|
||||
* <p>
|
||||
* This could also be described as deleting orphans - in that beans removed from
|
||||
* the List/Set/Map will be deleted automatically when the parent bean is saved.
|
||||
* They are considered 'orphans' when they have been removed from the collection
|
||||
* in that they are no longer associated/linked to their parent bean.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface PrivateOwned {
|
||||
|
||||
/**
|
||||
* Set this to false if you don't want cascade REMOVE on this relationship.
|
||||
* <p>
|
||||
* That is, by default PrivateOwned implicitly adds a cascade REMOVE to the
|
||||
* relationship and if you don't want that you need to set this to false.
|
||||
* </p>
|
||||
*/
|
||||
boolean cascadeRemove() default true;
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks an entity bean as being included in read auditing.
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ReadAudit {
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used to indicate a property on an entity bean used to control 'soft delete'
|
||||
* (also known as 'logical delete').
|
||||
* <p>
|
||||
* The property should be of type boolean.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @SoftDelete
|
||||
* boolean deleted;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface SoftDelete {
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Mark and entity bean that is used solely via RawSql.
|
||||
* <p>
|
||||
* This means the entity bean has no base table specified (via @Table).
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Sql {
|
||||
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.avaje.ebean.TxIsolation;
|
||||
import com.avaje.ebean.TxType;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
/**
|
||||
* Specify transaction scoping for a method.
|
||||
* <p>
|
||||
* <b><i> This is only supported if "Enhancement" is used via javaagent, ANT
|
||||
* task or IDE enhancement plugin etc. </i></b>
|
||||
* </p>
|
||||
* <p>
|
||||
* Note: Currently there are 3 known annotations that perform this role.
|
||||
* <ul>
|
||||
* <li>EJB's javax.ejb.TransactionAttribute</li>
|
||||
* <li>Spring's org.springframework.transaction.annotation.Transactional</li>
|
||||
* <li>and this one, Ebean's own com.avaje.ebean.annotation.Transactional</li>
|
||||
* </ul>
|
||||
* Spring created their one because the EJB annotation does not support features
|
||||
* such as isolation level and specifying rollbackOn, noRollbackOn exceptions.
|
||||
* This one exists for Ebean because I agree that the standard one is
|
||||
* insufficient and don't want to include a dependency on Spring.
|
||||
* </p>
|
||||
* <p>
|
||||
* The default behaviour of EJB (and hence Spring) is to NOT ROLLBACK on checked
|
||||
* exceptions. I find this very counter-intuitive. Ebean will provide a property
|
||||
* to set the default behaviour to rollback on any exception and optionally
|
||||
* change the setting to be consistent with EJB/Spring if people wish to do so.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // a normal class
|
||||
* public class MySimpleUserService {
|
||||
*
|
||||
* // this method is transactional automatically handling
|
||||
* // transaction begin, commit and rollback etc
|
||||
* @Transactional
|
||||
* public void runInTrans() throws IOException {
|
||||
*
|
||||
* // tasks performed within the transaction
|
||||
* ...
|
||||
* // find some objects
|
||||
* Customer cust = ebeanServer.find(Customer.class, 42);
|
||||
*
|
||||
* Order order = ...;
|
||||
* ...
|
||||
* // save some objects
|
||||
* ebeanServer.save(customer);
|
||||
* ebeanServer.save(order);
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Transactional {
|
||||
|
||||
/**
|
||||
* The type of transaction scoping. Defaults to REQUIRED.
|
||||
*/
|
||||
TxType type() default TxType.REQUIRED;
|
||||
|
||||
/**
|
||||
* Persist batch mode for the transaction.
|
||||
*/
|
||||
PersistBatch batch() default PersistBatch.INHERIT;
|
||||
|
||||
/**
|
||||
* Persist batch mode for the request if not set on the transaction.
|
||||
* <p>
|
||||
* If batch is set to NONE then batchOnCascade can be set to INSERT or ALL
|
||||
* and then each save(), delete(), insert(), update() request that cascades
|
||||
* to child beans can use JDBC batch.
|
||||
* </p>
|
||||
*/
|
||||
PersistBatch batchOnCascade() default PersistBatch.INHERIT;
|
||||
|
||||
/**
|
||||
* The batch size to use when using JDBC batch mode.
|
||||
* <p>
|
||||
* If unset this defaults to the value set in ServerConfig.
|
||||
* </p>
|
||||
*/
|
||||
int batchSize() default 0;
|
||||
|
||||
/**
|
||||
* Set to false when we want to skip getting generatedKeys.
|
||||
* <p>
|
||||
* This is typically used in the case of large batch inserts where we get a
|
||||
* performance benefit from not calling getGeneratedKeys (as we are going to
|
||||
* insert a lot of rows and have no need for the Id values after the insert).
|
||||
* </p>
|
||||
*/
|
||||
boolean getGeneratedKeys() default true;
|
||||
|
||||
/**
|
||||
* The transaction isolation level this transaction should have.
|
||||
* <p>
|
||||
* This will only be used if this scope creates the transaction. If the
|
||||
* transaction has already started then this will currently be ignored (you
|
||||
* could argue that it should throw an exception).
|
||||
* </p>
|
||||
*/
|
||||
TxIsolation isolation() default TxIsolation.DEFAULT;
|
||||
|
||||
/**
|
||||
* Set this to true if the transaction should be only contain queries.
|
||||
*/
|
||||
boolean readOnly() default false;
|
||||
|
||||
/**
|
||||
* The name of the server that you want the transaction to be created from.
|
||||
* <p>
|
||||
* If left blank the 'default' server is used.
|
||||
* </p>
|
||||
*/
|
||||
String serverName() default "";
|
||||
|
||||
// int timeout() default 0;
|
||||
|
||||
/**
|
||||
* The Throwable's that will explicitly cause a rollback to occur.
|
||||
*/
|
||||
Class<? extends Throwable>[] rollbackFor() default {};
|
||||
|
||||
/**
|
||||
* The Throwable's that will explicitly NOT cause a rollback to occur.
|
||||
*/
|
||||
Class<? extends Throwable>[] noRollbackFor() default {};
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the update mode for the specific entity type.
|
||||
* <p>
|
||||
* Control whether all 'loaded' properties are included in an Update or whether
|
||||
* just properties that have changed will be included in the update.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that the default can be set via ebean.properties.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* ## Set to update all loaded properties
|
||||
* ebean.updateChangesOnly=false
|
||||
* </pre>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface UpdateMode {
|
||||
|
||||
/**
|
||||
* Set to false if you want to include all the 'loaded' properties in the
|
||||
* update. Otherwise, just the properties that have changed will be included
|
||||
* in the update.
|
||||
*/
|
||||
boolean updateChangesOnly() default true;
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* For a timestamp property that is set to the datetime when the entity was last
|
||||
* updated.
|
||||
* <p>
|
||||
* This is effectively an alias for @WhenModified which was added as it hints
|
||||
* towards a better naming convention (WhenCreated, WhenModified).
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface UpdatedTimestamp {
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotate an entity bean with @View to indicates the bean is based on a view.
|
||||
* <p>
|
||||
* As such typically the view is defined in <code>extra-ddl.xml</code> using
|
||||
* <code>create or replace view ...</code>.
|
||||
* </p>
|
||||
* <p>
|
||||
* When using extra-ddl.xml Ebean will run the resulting DDL script after the
|
||||
* <code>create-all</code> DDL (which is typically used during development) and for
|
||||
* DB Migration will copy the scripts as <code>repeatable migration scripts</code> that
|
||||
* will be run by FlywayDb (or Ebean's own migration runner) when their MD5 hash changes.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface View {
|
||||
|
||||
/**
|
||||
* The name of the view this entity bean is based on.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Tables this view is dependent on.
|
||||
* <p>
|
||||
* This is used with l2 caching to invalidate the query cache. Changes to these
|
||||
* tables invalidate the query cache for the entity based on this view.
|
||||
* </p>
|
||||
*/
|
||||
String[] dependentTables() default {};
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* For a timestamp property that is set to the datetime when the entity is
|
||||
* created/inserted.
|
||||
* <p>
|
||||
* This is effectively an alias for @CreatedTimestamp and added to hint
|
||||
* towards a better naming convention (WhenCreated, WhenModified).
|
||||
* </p>
|
||||
* <p>
|
||||
* An alternative to using this annotation would be to use insertable=false,
|
||||
* updateable=false with @Column and have the DB insert the current time
|
||||
* (default value on the DB column is SYSTIME etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* The downside to this approach is that the inserted entity does not have the
|
||||
* timestamp value after the insert has occurred. You need to fetch the entity
|
||||
* back to get the inserted timestamp if you want to used it.
|
||||
* </p>
|
||||
*
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @WhenCreated
|
||||
* Timestamp whenCreated;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WhenCreated {
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* For a timestamp property that is set to the datetime when the entity was last modified.
|
||||
* <p>
|
||||
* This is effectively an alias for @UpdatedTimestamp and added to hint
|
||||
* towards a better naming convention (WhenCreated, WhenModified).
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WhenModified {
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Add an Literal to add to the where clause when a many property (List, Set or
|
||||
* Map) is loaded or refreshed.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // on a OneToMany property...
|
||||
*
|
||||
* @OneToMany
|
||||
* @Where(clause = "deleted='y'")
|
||||
* List<Topic> topics;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Note that you can include "${ta}" as a place holder for the table alias if
|
||||
* you need to include the table alias in the clause.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* // ... including the ${ta} table alias placeholder...
|
||||
*
|
||||
* @OneToMany
|
||||
* @Where(clause = "${ta}.deleted='y'")
|
||||
* List<Topic> topics;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* This will be added to the where clause when lazy loading the OneToMany
|
||||
* property or when there is a join to that OneToMany property.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Where {
|
||||
|
||||
/**
|
||||
* The clause added to the lazy load query.
|
||||
* <p>
|
||||
* Note that you can include "${ta}" as a place holder for the table alias if
|
||||
* you need to include the table alias in the clause.
|
||||
* </p>
|
||||
*/
|
||||
String clause();
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Mapped onto a entity bean property that represents the user id of
|
||||
* who created the entity>
|
||||
* <p>
|
||||
* To use this annotation you need to implement CurrentUserProvider.
|
||||
* The type of the bean property should match the type returned by
|
||||
* CurrentUserProvider.
|
||||
*</p>
|
||||
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @WhoCreated
|
||||
* String whoCreated;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WhoCreated {
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Mapped onto a entity bean property that represents the user id of
|
||||
* who last modified the entity>
|
||||
* <p>
|
||||
* To use this annotation you need to implement CurrentUserProvider.
|
||||
* The type of the bean property should match the type returned by
|
||||
* CurrentUserProvider.
|
||||
* </p>
|
||||
*
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @WhoModified
|
||||
* String whoModified;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WhoModified {
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
|
||||
<TITLE>Extra deployment annotations</TITLE>
|
||||
</HEAD>
|
||||
<Body BGCOLOR="#ffffff">
|
||||
Extra deployment annotations
|
||||
|
||||
<p>
|
||||
Extra deployment annotations for entity beans.
|
||||
</p>
|
||||
|
||||
</Body>
|
||||
</HTML>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +0,0 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* A callback that can be registered to fire on getter method calls.
|
||||
* It's primary purpose is to automatically flush JDBC batch buffer.
|
||||
*/
|
||||
public interface PreGetterCallback {
|
||||
|
||||
/**
|
||||
* Trigger the callback.
|
||||
*/
|
||||
void preGetterTrigger();
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
|
||||
<TITLE>Enhanced beans API and Support objects</TITLE>
|
||||
</HEAD>
|
||||
<Body BGCOLOR="#ffffff">
|
||||
Enhanced beans API and Support objects
|
||||
|
||||
|
||||
|
||||
</Body>
|
||||
</HTML>
|
||||
@@ -1,60 +0,0 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
/**
|
||||
* Represents part of the "L2" server side cache.
|
||||
* <p>
|
||||
* This is used to cache beans or query results (bean collections).
|
||||
* </p>
|
||||
* <p>
|
||||
* There are 2 ServerCache's for each bean type. One is used as the 'bean cache'
|
||||
* which holds beans of a given type. The other is the 'query cache' holding
|
||||
* query results for a given type.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface ServerCache {
|
||||
|
||||
/**
|
||||
* Return the value given the key.
|
||||
*/
|
||||
Object get(Object id);
|
||||
|
||||
/**
|
||||
* Put the value in the cache with a given id.
|
||||
*/
|
||||
Object put(Object id, Object value);
|
||||
|
||||
/**
|
||||
* Remove a entry from the cache given its id.
|
||||
*/
|
||||
Object remove(Object id);
|
||||
|
||||
/**
|
||||
* Clear all entries from the cache.
|
||||
* <p>
|
||||
* NOTE: Be careful using this method in that most of the time application
|
||||
* code should clear BOTH the bean and query caches at the same time. This can
|
||||
* be done via {@link ServerCacheManager#clear(Class)}.
|
||||
* </p>
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Return the number of entries in the cache.
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Return the hit ratio the cache is currently getting.
|
||||
*/
|
||||
int getHitRatio();
|
||||
|
||||
/**
|
||||
* Return statistics for the cache.
|
||||
*
|
||||
* @param reset
|
||||
* if true the statistics are reset.
|
||||
*/
|
||||
ServerCacheStatistics getStatistics(boolean reset);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
/**
|
||||
* Defines method for constructing caches for beans and queries.
|
||||
*/
|
||||
public interface ServerCacheFactory {
|
||||
|
||||
/**
|
||||
* Create the cache for the given type with options.
|
||||
*/
|
||||
ServerCache createCache(ServerCacheType type, String cacheKey, ServerCacheOptions cacheOptions);
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
/**
|
||||
* The cache service for server side caching of beans and query results.
|
||||
*/
|
||||
public interface ServerCacheManager {
|
||||
|
||||
/**
|
||||
* Return true if the L2 caching is local.
|
||||
* <p>
|
||||
* Local L2 caching means that the cache updates should occur in foreground
|
||||
* rather than background processing.
|
||||
* </p>
|
||||
*/
|
||||
boolean isLocalL2Caching();
|
||||
|
||||
/**
|
||||
* Return true if there is an active bean cache for this type of bean.
|
||||
*/
|
||||
boolean isBeanCaching(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the cache for mapping natural keys to id values.
|
||||
*/
|
||||
ServerCache getNaturalKeyCache(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the cache for beans of a particular type.
|
||||
*/
|
||||
ServerCache getBeanCache(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the cache for associated many properties of a bean type.
|
||||
*/
|
||||
ServerCache getCollectionIdsCache(Class<?> beanType, String propertyName);
|
||||
|
||||
/**
|
||||
* Return the cache for query results of a particular type of bean.
|
||||
*/
|
||||
ServerCache getQueryCache(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* This clears both the bean and query cache for a given type.
|
||||
*/
|
||||
void clear(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Clear all the caches.
|
||||
*/
|
||||
void clearAll();
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
/**
|
||||
* The plugin interface that creates a ServerCacheFactory.
|
||||
*/
|
||||
public interface ServerCachePlugin {
|
||||
|
||||
/**
|
||||
* Create the ServerCacheFactory given the server config and background executor service.
|
||||
*/
|
||||
ServerCacheFactory create(ServerConfig config, BackgroundExecutor executor);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
/**
|
||||
* The type of L2 caches.
|
||||
*/
|
||||
public enum ServerCacheType {
|
||||
|
||||
/**
|
||||
* Bean cache.
|
||||
*/
|
||||
BEAN,
|
||||
|
||||
/**
|
||||
* Natural key cache.
|
||||
*/
|
||||
NATURAL_KEY,
|
||||
|
||||
/**
|
||||
* Collection Ids for Many properties.
|
||||
*/
|
||||
COLLECTION_IDS,
|
||||
|
||||
/**
|
||||
* Query cache.
|
||||
*/
|
||||
QUERY
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
|
||||
<TITLE>Server Cache Service</TITLE>
|
||||
</HEAD>
|
||||
<Body BGCOLOR="#ffffff">
|
||||
Server Cache Service
|
||||
|
||||
</Body>
|
||||
</HTML>
|
||||
@@ -1,207 +0,0 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.ExpressionList;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Base class for List Set and Map implementations of BeanCollection.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
private static final long serialVersionUID = 3365725236140187588L;
|
||||
|
||||
protected boolean readOnly;
|
||||
|
||||
protected boolean disableLazyLoad;
|
||||
|
||||
/**
|
||||
* The EbeanServer this is associated with. (used for lazy fetch).
|
||||
*/
|
||||
protected transient BeanCollectionLoader loader;
|
||||
|
||||
protected transient ExpressionList<?> filterMany;
|
||||
|
||||
/**
|
||||
* Flag set when registered with the batch loading context.
|
||||
*/
|
||||
protected boolean registeredWithLoadContext;
|
||||
|
||||
protected String ebeanServerName;
|
||||
|
||||
/**
|
||||
* The owning bean (used for lazy fetch).
|
||||
*/
|
||||
protected EntityBean ownerBean;
|
||||
|
||||
/**
|
||||
* The name of this property in the owning bean (used for lazy fetch).
|
||||
*/
|
||||
protected String propertyName;
|
||||
|
||||
protected ModifyHolder<E> modifyHolder;
|
||||
|
||||
protected ModifyListenMode modifyListenMode;
|
||||
protected boolean modifyAddListening;
|
||||
protected boolean modifyRemoveListening;
|
||||
protected boolean modifyListening;
|
||||
|
||||
/**
|
||||
* Constructor not non-lazy loading collection.
|
||||
*/
|
||||
public AbstractBeanCollection() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create deferred fetch proxy.
|
||||
*/
|
||||
public AbstractBeanCollection(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
|
||||
this.loader = loader;
|
||||
this.ebeanServerName = loader.getName();
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.readOnly = ownerBean._ebean_getIntercept().isReadOnly();
|
||||
}
|
||||
|
||||
public EntityBean getOwnerBean() {
|
||||
return ownerBean;
|
||||
}
|
||||
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public ExpressionList<?> getFilterMany() {
|
||||
return filterMany;
|
||||
}
|
||||
|
||||
public void setFilterMany(ExpressionList<?> filterMany) {
|
||||
this.filterMany = filterMany;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisableLazyLoad(boolean disableLazyLoad) {
|
||||
this.disableLazyLoad = disableLazyLoad;
|
||||
}
|
||||
|
||||
protected void lazyLoadCollection(boolean onlyIds) {
|
||||
if (loader == null) {
|
||||
loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
|
||||
}
|
||||
if (loader == null) {
|
||||
String msg = "Lazy loading but LazyLoadEbeanServer is null?"
|
||||
+ " The LazyLoadEbeanServer needs to be set after deserialization"
|
||||
+ " to support lazy loading.";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
|
||||
loader.loadMany(this, onlyIds);
|
||||
checkEmptyLazyLoad();
|
||||
}
|
||||
|
||||
public boolean isRegisteredWithLoadContext() {
|
||||
return registeredWithLoadContext;
|
||||
}
|
||||
|
||||
public void setLoader(BeanCollectionLoader loader) {
|
||||
this.registeredWithLoadContext = true;
|
||||
this.loader = loader;
|
||||
this.ebeanServerName = loader.getName();
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
protected void checkReadOnly() {
|
||||
if (readOnly) {
|
||||
String msg = "This collection is in ReadOnly mode";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Support for modify additions deletions etc - ManyToMany
|
||||
// ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* set modifyListening to be on or off.
|
||||
*/
|
||||
public void setModifyListening(ModifyListenMode mode) {
|
||||
|
||||
this.modifyListenMode = mode;
|
||||
this.modifyAddListening = ModifyListenMode.ALL.equals(mode);
|
||||
this.modifyRemoveListening = modifyAddListening || ModifyListenMode.REMOVALS.equals(mode);
|
||||
this.modifyListening = modifyRemoveListening || modifyAddListening;
|
||||
if (modifyListening) {
|
||||
// lose any existing modifications
|
||||
modifyHolder = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the modify listening mode this collection is using.
|
||||
*/
|
||||
public ModifyListenMode getModifyListenMode() {
|
||||
return modifyListenMode;
|
||||
}
|
||||
|
||||
protected ModifyHolder<E> getModifyHolder() {
|
||||
if (modifyHolder == null) {
|
||||
modifyHolder = new ModifyHolder<E>();
|
||||
}
|
||||
return modifyHolder;
|
||||
}
|
||||
|
||||
public void modifyAddition(E bean) {
|
||||
if (modifyAddListening) {
|
||||
getModifyHolder().modifyAddition(bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void modifyRemoval(Object bean) {
|
||||
if (modifyRemoveListening) {
|
||||
getModifyHolder().modifyRemoval(bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void modifyReset() {
|
||||
if (modifyHolder != null) {
|
||||
modifyHolder.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public Set<E> getModifyAdditions() {
|
||||
if (modifyHolder == null) {
|
||||
return null;
|
||||
} else {
|
||||
return modifyHolder.getModifyAdditions();
|
||||
}
|
||||
}
|
||||
|
||||
public Set<E> getModifyRemovals() {
|
||||
if (modifyHolder == null) {
|
||||
return null;
|
||||
} else {
|
||||
return modifyHolder.getModifyRemovals();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are underlying additions or removals.
|
||||
*/
|
||||
public boolean holdsModifications() {
|
||||
return modifyHolder != null && modifyHolder.hasModifications();
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Holds sets of additions and deletions from a 'owner' List Set or Map.
|
||||
* <p>
|
||||
* These sets of additions and deletions are used to support persisting
|
||||
* ManyToMany relationships. The additions becoming inserts into the
|
||||
* intersection table and the removals becoming deletes from the intersection
|
||||
* table.
|
||||
* </p>
|
||||
*/
|
||||
class ModifyHolder<E> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2572572897923801083L;
|
||||
|
||||
/**
|
||||
* Deletions list for manyToMany persistence.
|
||||
*/
|
||||
private Set<E> modifyDeletions = new LinkedHashSet<E>();
|
||||
|
||||
/**
|
||||
* Additions list for manyToMany persistence.
|
||||
*/
|
||||
private Set<E> modifyAdditions = new LinkedHashSet<E>();
|
||||
|
||||
void reset() {
|
||||
modifyDeletions = new LinkedHashSet<E>();
|
||||
modifyAdditions = new LinkedHashSet<E>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by BeanList.addAll() methods.
|
||||
*/
|
||||
void modifyAdditionAll(Collection<? extends E> c) {
|
||||
if (c != null) {
|
||||
for (E e : c) {
|
||||
modifyAddition(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void modifyAddition(E bean) {
|
||||
if (bean != null) {
|
||||
// If it is to delete then just remove the deletion
|
||||
if (!modifyDeletions.remove(bean)) {
|
||||
// Insert
|
||||
modifyAdditions.add(bean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void modifyRemoval(Object bean) {
|
||||
if (bean != null) {
|
||||
// If it is to be added then just remove the addition
|
||||
if (!modifyAdditions.remove(bean)) {
|
||||
modifyDeletions.add((E) bean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<E> getModifyAdditions() {
|
||||
return modifyAdditions;
|
||||
}
|
||||
|
||||
Set<E> getModifyRemovals() {
|
||||
return modifyDeletions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there additions or removals.
|
||||
*/
|
||||
boolean hasModifications() {
|
||||
return !modifyDeletions.isEmpty() || !modifyAdditions.isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
|
||||
<TITLE>Common non-public interfaces and implementation</TITLE>
|
||||
</HEAD>
|
||||
<Body BGCOLOR="#ffffff">
|
||||
Common non-public interfaces and implementation.
|
||||
|
||||
|
||||
</Body>
|
||||
</HTML>
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* API from creating and getting property values from an Immutable Compound
|
||||
* Value Object.
|
||||
*
|
||||
* <p>
|
||||
* A Compound Value object should contain multiple properties that are stored
|
||||
* separately. If you only have a single scalar value you should instead look to
|
||||
* use {@link ScalarTypeConverter}.
|
||||
* </p>
|
||||
* <p>
|
||||
* For each property in the compound type you need to implement the
|
||||
* {@link CompoundTypeProperty} interface. These must be returned from
|
||||
* {@link #getProperties()} in the same order that the properties appear in the
|
||||
* constructor.
|
||||
* </p>
|
||||
* <p>
|
||||
* If your compound type is mutable then you should look to use the JPA Embedded
|
||||
* annotation instead of implementing this interface.
|
||||
* </p>
|
||||
* <p>
|
||||
* When using classpath search Ebean will detect and automatically register any
|
||||
* implementations of this interface (along with detecting the entity classes
|
||||
* etc).
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <V>
|
||||
* The type of the Value Object
|
||||
*
|
||||
* @see ScalarTypeConverter
|
||||
*/
|
||||
public interface CompoundType<V> {
|
||||
|
||||
/**
|
||||
* Create an instance of the compound type given its property values.
|
||||
*/
|
||||
V create(Object[] propertyValues);
|
||||
|
||||
/**
|
||||
* Return the properties in the order they appear in the constructor.
|
||||
*/
|
||||
CompoundTypeProperty<V, ?>[] getProperties();
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Represents a Property of a Compound Value Object.
|
||||
* <p>
|
||||
* For each property in a {@link CompoundType} you need an implementation of
|
||||
* this CompoundTypeProperty interface.
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <V>
|
||||
* The type of the Compound value object
|
||||
* @param <P>
|
||||
* The type of the property
|
||||
*
|
||||
* @see CompoundType
|
||||
* @see ScalarTypeConverter
|
||||
*/
|
||||
public interface CompoundTypeProperty<V, P> {
|
||||
|
||||
/**
|
||||
* The name of this property.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the property value from the containing compound value object.
|
||||
*
|
||||
* @param valueObject
|
||||
* the compound value object
|
||||
* @return the property value.
|
||||
*/
|
||||
P getValue(V valueObject);
|
||||
|
||||
/**
|
||||
* This should <b>ONLY</b> be used when the persistence type is different from
|
||||
* the logical type returned. It most cases just return 0 and Ebean will
|
||||
* persist the logical type.
|
||||
* <p>
|
||||
* Typically this should be used when the logical type is long but the
|
||||
* persistence type is java.sql.Timestamp. In this case return
|
||||
* java.sql.Types.TIMESTAMP (rather than 0).
|
||||
* </p>
|
||||
*
|
||||
* @return Return the java.sql.Type that you want to use to persist this
|
||||
* property or 0 and Ebean will use the logical type.
|
||||
*/
|
||||
int getDbType();
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Configuration for the container that holds the EbeanServer 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.
|
||||
*/
|
||||
public class ContainerConfig {
|
||||
|
||||
protected boolean clusterActive;
|
||||
|
||||
protected Properties properties;
|
||||
|
||||
/**
|
||||
* Return true if clustering is active.
|
||||
*/
|
||||
public boolean isClusterActive() {
|
||||
return clusterActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true for clustering to be active.
|
||||
*/
|
||||
public void setClusterActive(boolean clusterActive) {
|
||||
this.clusterActive = clusterActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the deployment properties.
|
||||
*/
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the deployment properties.
|
||||
*/
|
||||
public void setProperties(Properties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from properties.
|
||||
*/
|
||||
public void loadFromProperties(Properties properties) {
|
||||
this.properties = properties;
|
||||
this.clusterActive = getProperty(properties, "ebean.cluster.active", clusterActive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the boolean property setting.
|
||||
*/
|
||||
protected boolean getProperty(Properties properties, String key, boolean defaultValue) {
|
||||
return "true".equalsIgnoreCase(properties.getProperty(key, Boolean.toString(defaultValue)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Provides the current user in order to support 'Who created', 'Who modified' and other audit features.
|
||||
*/
|
||||
public interface CurrentUserProvider {
|
||||
|
||||
/**
|
||||
* Return the current user id.
|
||||
* <p>
|
||||
* The type returned should match the type of the properties annotated
|
||||
* with @WhoCreated and @WhoModified. These are typically String, Long or UUID.
|
||||
* </p>
|
||||
*/
|
||||
Object currentUser();
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* The JPA naming convention where column names match property names and table
|
||||
* names match entity names.
|
||||
*
|
||||
* <p>
|
||||
* The JPA specification states that the in the case of no annotations the name
|
||||
* of the class will be take as the table name and the name of a property will
|
||||
* be taken as the name of the column.
|
||||
* </p>
|
||||
*
|
||||
* @author emcgreal
|
||||
*/
|
||||
public class MatchingNamingConvention extends AbstractNamingConvention {
|
||||
|
||||
/**
|
||||
* Create with a sequence format of "{table}_seq".
|
||||
*/
|
||||
public MatchingNamingConvention() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates with a specific format for DB sequences.
|
||||
*
|
||||
* @param sequenceFormat
|
||||
* the sequence format
|
||||
*/
|
||||
public MatchingNamingConvention(String sequenceFormat) {
|
||||
super(sequenceFormat);
|
||||
}
|
||||
|
||||
public String getColumnFromProperty(Class<?> beanClass, String propertyName) {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public TableName getTableNameByConvention(Class<?> beanClass) {
|
||||
|
||||
return new TableName(getCatalog(), getSchema(), beanClass.getSimpleName());
|
||||
}
|
||||
|
||||
public String getPropertyFromColumn(Class<?> beanClass, String dbColumnName) {
|
||||
return dbColumnName;
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Defines the mode for JDBC batch processing.
|
||||
* <p>
|
||||
* Used both at a per transaction basis and per request basis.
|
||||
* </p>
|
||||
*
|
||||
* @see com.avaje.ebean.config.ServerConfig#setPersistBatch(PersistBatch)
|
||||
* @see com.avaje.ebean.config.ServerConfig#setPersistBatchOnCascade(PersistBatch)
|
||||
*
|
||||
* @see com.avaje.ebean.Transaction#setBatch(PersistBatch)
|
||||
* @see com.avaje.ebean.Transaction#setBatchOnCascade(PersistBatch)
|
||||
*/
|
||||
public enum PersistBatch {
|
||||
|
||||
/**
|
||||
* Do not use JDBC Batch mode.
|
||||
*/
|
||||
NONE(false),
|
||||
|
||||
/**
|
||||
* Use JDBC Batch mode on Inserts.
|
||||
*/
|
||||
INSERT(true),
|
||||
|
||||
/**
|
||||
* Use JDBC Batch mode on Inserts, Updates and Deletes.
|
||||
*/
|
||||
ALL(true),
|
||||
|
||||
/**
|
||||
* You should not use this value explicitly. It should only used on the Transactional annotation
|
||||
* to indicate that the value should inherit from the ServerConfig setting.
|
||||
*/
|
||||
INHERIT(false);
|
||||
|
||||
|
||||
final boolean forInsert;
|
||||
|
||||
PersistBatch(boolean forInsert) {
|
||||
this.forInsert = forInsert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if persist cascade should use JDBC batch for inserts.
|
||||
*/
|
||||
public boolean forInsert() {
|
||||
return forInsert;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Built in supported platforms.
|
||||
*/
|
||||
public enum Platform {
|
||||
|
||||
/**
|
||||
* Generic base platform configured via properties or code.
|
||||
*/
|
||||
GENERIC,
|
||||
|
||||
/**
|
||||
* H2.
|
||||
*/
|
||||
H2,
|
||||
|
||||
/**
|
||||
* Postgres.
|
||||
*/
|
||||
POSTGRES,
|
||||
|
||||
/**
|
||||
* MySql.
|
||||
*/
|
||||
MYSQL,
|
||||
|
||||
/**
|
||||
* Oracle.
|
||||
*/
|
||||
ORACLE,
|
||||
|
||||
/**
|
||||
* Microsoft SQL Server.
|
||||
*/
|
||||
SQLSERVER,
|
||||
|
||||
/**
|
||||
* DB2.
|
||||
*/
|
||||
DB2,
|
||||
|
||||
/**
|
||||
* SQLite.
|
||||
*/
|
||||
SQLITE
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class PropertiesWrapper {
|
||||
|
||||
protected final Properties properties;
|
||||
|
||||
protected final String prefix;
|
||||
|
||||
protected final String serverName;
|
||||
|
||||
protected final PropertyMap propertyMap;
|
||||
|
||||
/**
|
||||
* Construct with a prefix, serverName and properties.
|
||||
*/
|
||||
public PropertiesWrapper(String prefix, String serverName, Properties properties) {
|
||||
this.serverName = serverName;
|
||||
this.prefix = prefix;
|
||||
this.propertyMap = PropertyMapLoader.load(null, properties);
|
||||
this.properties = propertyMap.asProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct without prefix of serverName.
|
||||
*/
|
||||
public PropertiesWrapper(Properties properties) {
|
||||
this(null, null, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal copy constructor when changing prefix.
|
||||
*/
|
||||
protected PropertiesWrapper(String prefix, String serverName, PropertyMap propertyMap, Properties properties) {
|
||||
this.serverName = serverName;
|
||||
this.prefix = prefix;
|
||||
this.propertyMap = propertyMap;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a PropertiesWrapper instance with a different prefix but same underlying properties.
|
||||
* <p/>
|
||||
* Used when wanting to use "datasource" as the prefix rather than "ebean".
|
||||
* <p/>
|
||||
* The returning instance should only be used in a read only fashion.
|
||||
*/
|
||||
public PropertiesWrapper withPrefix(String prefix) {
|
||||
return new PropertiesWrapper(prefix, serverName, propertyMap, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the serverName (optional).
|
||||
*/
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return as Properties with lower case keys and after evaluation and additional properties loading has occurred.
|
||||
* <p>
|
||||
* Ebean has historically ignored the case of keys hence returning the Properties with all the keys lower cased.
|
||||
* </p>
|
||||
*/
|
||||
public Properties asPropertiesLowerCase() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a property with no default value.
|
||||
*/
|
||||
public String get(String key) {
|
||||
return get(key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a property with a default value.
|
||||
* <p>
|
||||
* This performs a search using the prefix and server name (if supplied) to search for the property
|
||||
* value in order based on:
|
||||
* <pre>{@code
|
||||
* prefix.serverName.key
|
||||
* prefix.key
|
||||
* key
|
||||
* }</pre>
|
||||
* </p>
|
||||
*/
|
||||
public String get(String key, String defaultValue) {
|
||||
|
||||
String value = null;
|
||||
if (serverName != null && prefix != null) {
|
||||
value = propertyMap.get(prefix + "." + serverName + "." + key, null);
|
||||
}
|
||||
if (value == null && prefix != null) {
|
||||
value = propertyMap.get(prefix + "." + key, null);
|
||||
}
|
||||
if (value == null) {
|
||||
value = propertyMap.get(key, null);
|
||||
}
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a double property value.
|
||||
*/
|
||||
public double getDouble(String key, double defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Double.parseDouble(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an int property value.
|
||||
*/
|
||||
public int getInt(String key, int defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a long property value.
|
||||
*/
|
||||
public long getLong(String key, long defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Long.parseLong(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean property value.
|
||||
*/
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Enum property value.
|
||||
*/
|
||||
public <T extends Enum<T>> T getEnum(Class<T> enumType, String key, T defaultValue) {
|
||||
String level = get(key, null);
|
||||
return (level == null) ? defaultValue : Enum.valueOf(enumType, level.toUpperCase());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
/**
|
||||
* Helper used to evaluate expressions such as ${CATALINA_HOME}.
|
||||
* <p>
|
||||
* The expressions can contain environment variables, system properties or JNDI
|
||||
* properties. JNDI expressions take the form ${jndi:propertyName} where you
|
||||
* substitute propertyName with the name of the jndi property you wish to
|
||||
* evaluate.
|
||||
* </p>
|
||||
*/
|
||||
final class PropertyExpression {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PropertyExpression.class);
|
||||
|
||||
/**
|
||||
* Prefix for looking up JNDI Environment variable.
|
||||
*/
|
||||
private static final String JAVA_COMP_ENV = "java:comp/env/";
|
||||
|
||||
/**
|
||||
* Used to detect the start of an expression.
|
||||
*/
|
||||
private static final String START = "${";
|
||||
|
||||
/**
|
||||
* Used to detect the end of an expression.
|
||||
*/
|
||||
private static final String END = "}";
|
||||
|
||||
/**
|
||||
* Specify the PropertyHolder.
|
||||
*/
|
||||
private PropertyExpression() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property value evaluating and replacing any expressions such as
|
||||
* ${CATALINA_HOME}.
|
||||
*/
|
||||
static String eval(String val, PropertyMap map) {
|
||||
if (val == null) {
|
||||
return null;
|
||||
}
|
||||
int sp = val.indexOf(START);
|
||||
if (sp > -1) {
|
||||
int ep = val.indexOf(END, sp + 1);
|
||||
if (ep > -1) {
|
||||
return eval(val, sp, ep, map);
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the expression using JNDI, Environment variables, System Properties
|
||||
* or existing an property in SystemProperties itself.
|
||||
*/
|
||||
private static String evaluateExpression(String exp, PropertyMap map) {
|
||||
|
||||
if (isJndiExpression(exp)) {
|
||||
// JNDI property lookup...
|
||||
String val = getJndiProperty(exp);
|
||||
if (val != null) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
// check Environment Variables first
|
||||
String val = System.getenv(exp);
|
||||
if (val == null) {
|
||||
// then check system properties
|
||||
val = System.getProperty(exp);
|
||||
}
|
||||
if (val == null && map != null) {
|
||||
// then check PropertyMap
|
||||
val = map.get(exp);
|
||||
}
|
||||
|
||||
if (val != null) {
|
||||
return val;
|
||||
|
||||
} else {
|
||||
// unable to evaluate yet... but maybe later based on the order
|
||||
// in which properties are being set/loaded. You can use
|
||||
// GlobalProperties.evaluateExpressions() to get any unresolved
|
||||
// expressions to be evaluated
|
||||
logger.debug("Unable to evaluate expression [" + exp + "]");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String eval(String val, int sp, int ep, PropertyMap map) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(val.substring(0, sp));
|
||||
|
||||
String cal = evalExpression(val, sp, ep, map);
|
||||
sb.append(cal);
|
||||
|
||||
eval(val, ep + 1, sb, map);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static void eval(String val, int startPos, StringBuilder sb, PropertyMap map) {
|
||||
if (startPos < val.length()) {
|
||||
int sp = val.indexOf(START, startPos);
|
||||
if (sp > -1) {
|
||||
// append what is between the last token and the new one (if startPos ==
|
||||
// sp nothing gets added)
|
||||
sb.append(val.substring(startPos, sp));
|
||||
int ep = val.indexOf(END, sp + 1);
|
||||
if (ep > -1) {
|
||||
String cal = evalExpression(val, sp, ep, map);
|
||||
sb.append(cal);
|
||||
eval(val, ep + 1, sb, map);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// append what is left...
|
||||
sb.append(val.substring(startPos));
|
||||
}
|
||||
|
||||
private static String evalExpression(String val, int sp, int ep, PropertyMap map) {
|
||||
// trim off start and end ${ and }
|
||||
String exp = val.substring(sp + START.length(), ep);
|
||||
|
||||
// evaluate the variable
|
||||
String evaled = evaluateExpression(exp, map);
|
||||
if (evaled != null) {
|
||||
return evaled;
|
||||
} else {
|
||||
// unable to evaluate at this stage (maybe later)
|
||||
return START + exp + END;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isJndiExpression(String exp) {
|
||||
return exp.startsWith("JNDI:") || exp.startsWith("jndi:");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null if JNDI is not setup or if the property is not found.
|
||||
*
|
||||
* @param key
|
||||
* the key of the JNDI Environment property including a JNDI: prefix.
|
||||
*/
|
||||
private static String getJndiProperty(String key) {
|
||||
|
||||
try {
|
||||
// remove the JNDI: prefix
|
||||
key = key.substring(5);
|
||||
|
||||
return (String) getJndiObject(key);
|
||||
|
||||
} catch (NamingException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to getProperty but throws NamingException if JNDI is not setup or
|
||||
* if the property is not found.
|
||||
*/
|
||||
private static Object getJndiObject(String key) throws NamingException {
|
||||
|
||||
InitialContext ctx = new InitialContext();
|
||||
return ctx.lookup(JAVA_COMP_ENV + key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A map like structure of properties.
|
||||
* <p/>
|
||||
* Handles evaluation of expressions like ${home} and provides convenience methods for int, long and boolean.
|
||||
*/
|
||||
public final class PropertyMap implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Return properties loaded from test-ebean.properties.
|
||||
*/
|
||||
public static Properties testProperties() {
|
||||
PropertyMap propertyMap = PropertyMapLoader.loadTestProperties();
|
||||
return (propertyMap == null) ? new Properties() : propertyMap.asProperties();
|
||||
}
|
||||
|
||||
public static Properties defaultProperties() {
|
||||
PropertyMap propertyMap = PropertyMapLoader.loadGlobalProperties();
|
||||
return (propertyMap == null) ? new Properties() : propertyMap.asProperties();
|
||||
}
|
||||
|
||||
public static boolean loadTestProperties() {
|
||||
String disable = System.getProperty("disableTestProperties");
|
||||
return (disable == null || !disable.equalsIgnoreCase("true"));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return map.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return as standard Properties.
|
||||
*/
|
||||
public Properties asProperties() {
|
||||
Properties properties = new Properties();
|
||||
for (Entry<String, String> e : entrySet()) {
|
||||
properties.put(e.getKey(), e.getValue());
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through all the properties and evaluate any expressions that have not
|
||||
* been resolved.
|
||||
*/
|
||||
public void evaluateProperties() {
|
||||
|
||||
for (Entry<String, String> e : entrySet()) {
|
||||
String key = e.getKey();
|
||||
String val = e.getValue();
|
||||
String eval = eval(val);
|
||||
if (eval != null && !eval.equals(val)) {
|
||||
put(key, eval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value with expressions like ${home} evaluated using system properties and environment variables.
|
||||
*/
|
||||
public synchronized String eval(String val) {
|
||||
return PropertyExpression.eval(val, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the boolean property value with a given default.
|
||||
*/
|
||||
public synchronized boolean getBoolean(String key, boolean defaultValue) {
|
||||
String value = get(key);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the int property value with a given default.
|
||||
*/
|
||||
public synchronized int getInt(String key, int defaultValue) {
|
||||
String value = get(key);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the long property value with a given default.
|
||||
*/
|
||||
public synchronized long getLong(String key, long defaultValue) {
|
||||
String value = get(key);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return Long.parseLong(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string property value with a given default.
|
||||
*/
|
||||
public synchronized String get(String key, String defaultValue) {
|
||||
String value = map.get(key.toLowerCase());
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property value returning null if there is no value defined.
|
||||
*/
|
||||
public synchronized String get(String key) {
|
||||
return map.get(key.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Put all evaluating any expressions in the values.
|
||||
*/
|
||||
public synchronized void putEvalAll(Map<String, String> keyValueMap) {
|
||||
|
||||
for (Map.Entry<String, String> entry : keyValueMap.entrySet()) {
|
||||
putEval(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a single key value evaluating any expressions in the value.
|
||||
*/
|
||||
public synchronized String putEval(String key, String value) {
|
||||
value = PropertyExpression.eval(value, this);
|
||||
return map.put(key.toLowerCase(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a single key value with no expression evaluation.
|
||||
*/
|
||||
public synchronized String put(String key, String value) {
|
||||
return map.put(key.toLowerCase(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an entry.
|
||||
*/
|
||||
public synchronized String remove(String key) {
|
||||
return map.remove(key.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the entries.
|
||||
*/
|
||||
public synchronized Set<Entry<String, String>> entrySet() {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Helper used to load the ebean.properties into a PropertyMap.
|
||||
*/
|
||||
final class PropertyMapLoader {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PropertyMapLoader.class);
|
||||
|
||||
/**
|
||||
* Load the <code>test-ebean.properties</code>.
|
||||
*/
|
||||
public static PropertyMap loadTestProperties() {
|
||||
if (!PropertyMap.loadTestProperties()) {
|
||||
return new PropertyMap();
|
||||
}
|
||||
return load(null, "test-ebean.properties");
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the ebean.properties (and test-ebean.properties if present).
|
||||
*/
|
||||
public static PropertyMap loadGlobalProperties() {
|
||||
|
||||
boolean loadTestProperties = false;
|
||||
String fileName = System.getenv("EBEAN_PROPS_FILE");
|
||||
if (fileName == null) {
|
||||
fileName = System.getProperty("ebean.props.file");
|
||||
if (fileName == null) {
|
||||
loadTestProperties = PropertyMap.loadTestProperties();
|
||||
fileName = "ebean.properties";
|
||||
}
|
||||
}
|
||||
|
||||
PropertyMap map = load(null, fileName);
|
||||
if (loadTestProperties) {
|
||||
// load test properties if present in classpath
|
||||
map = load(map, "test-ebean.properties");
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the file returning the property map.
|
||||
*
|
||||
* @param p
|
||||
* an existing property map to load into.
|
||||
* @param fileName
|
||||
* the name of the properties file to load.
|
||||
*/
|
||||
public static PropertyMap load(PropertyMap p, String fileName) {
|
||||
|
||||
InputStream is = findInputStream(fileName);
|
||||
if (is == null) {
|
||||
return p;
|
||||
} else {
|
||||
return load(p, is);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the InputStream returning the property map.
|
||||
*
|
||||
* @param p
|
||||
* an existing property map to load into.
|
||||
* @param in
|
||||
* the InputStream of the properties file to load.
|
||||
*/
|
||||
public static PropertyMap load(PropertyMap p, InputStream in) {
|
||||
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
props.load(in);
|
||||
in.close();
|
||||
return load(p, props);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static PropertyMap load(PropertyMap p, Properties props) {
|
||||
|
||||
if (p == null) {
|
||||
p = new PropertyMap();
|
||||
}
|
||||
|
||||
// put values in initially without any evaluation
|
||||
for (Map.Entry<Object, Object> entry : props.entrySet()) {
|
||||
String key = ((String) entry.getKey()).toLowerCase();
|
||||
String val = ((String) entry.getValue());
|
||||
if (val != null) {
|
||||
val = val.trim();
|
||||
}
|
||||
p.put(key, val);
|
||||
}
|
||||
|
||||
p.evaluateProperties();
|
||||
|
||||
String otherProps = p.remove("load.properties");
|
||||
if (otherProps == null) {
|
||||
otherProps = p.remove("load.properties.override");
|
||||
}
|
||||
if (otherProps != null) {
|
||||
otherProps = otherProps.replace("\\", "/");
|
||||
InputStream is = findInputStream(otherProps);
|
||||
if (is != null) {
|
||||
logger.debug("loading properties from " + otherProps);
|
||||
load(p, is);
|
||||
} else {
|
||||
logger.error("load.properties " + otherProps + " not found.");
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the input stream given the file name.
|
||||
*/
|
||||
private static InputStream findInputStream(String fileName) {
|
||||
|
||||
if (fileName == null) {
|
||||
throw new NullPointerException("fileName is null?");
|
||||
}
|
||||
|
||||
try {
|
||||
File f = new File(fileName);
|
||||
|
||||
if (f.exists()) {
|
||||
logger.debug(fileName + " found in file system");
|
||||
return new FileInputStream(f);
|
||||
} else {
|
||||
InputStream in = findInClassPath(fileName);
|
||||
if (in != null) {
|
||||
logger.debug(fileName + " found in classpath");
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
} catch (FileNotFoundException ex) {
|
||||
// already made the check so this
|
||||
// should never be thrown
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static InputStream findInClassPath(String fileName) {
|
||||
return Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Used to convert between a value object and a known scalar type. The value
|
||||
* object is the logical type used in your application and the scalar type is
|
||||
* the value used to persist than to the DB.
|
||||
* <p>
|
||||
* The Value object should be immutable and scalar (aka not compound) and
|
||||
* converts to and from a known scalar type which Ebean will use to persist the
|
||||
* value.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is an easier alternative to implementing the
|
||||
* com.avaje.ebean.server.type.ScalarType interface.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that Ebean will automatically try to detect Immutable Scalar Value
|
||||
* Objects and automatically support them via reflection. This however would not
|
||||
* be appropriate when the logical type is different from the type you wish to
|
||||
* use for persistence - for example, if the logical type was long and you
|
||||
* wanted to use java.sql.Timestamp for persistence. In this case you would want
|
||||
* to implement this interface rather than let Ebean automatically support that
|
||||
* type via reflection.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you want to support a Compound Type rather than a Scalar Type refer to
|
||||
* {@link CompoundType}.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <B>
|
||||
* The value object type.
|
||||
* @param <S>
|
||||
* The scalar object type that is used to persist the value object.
|
||||
*
|
||||
* @see CompoundType
|
||||
* @see CompoundTypeProperty
|
||||
*/
|
||||
public interface ScalarTypeConverter<B, S> {
|
||||
|
||||
/**
|
||||
* Return the value to represent null. Typically this is actually null but for
|
||||
* scala.Option and similar type converters this actually returns an instance
|
||||
* representing "None".
|
||||
*/
|
||||
B getNullValue();
|
||||
|
||||
/**
|
||||
* Convert the scalar type value into the value object.
|
||||
* <p>
|
||||
* This typically occurs when Ebean reads the value from a resultSet or other
|
||||
* data source.
|
||||
* </p>
|
||||
*
|
||||
* @param scalarType
|
||||
* the value from the data source
|
||||
*/
|
||||
B wrapValue(S scalarType);
|
||||
|
||||
/**
|
||||
* Convert the value object into a scalar value that Ebean knows how to
|
||||
* persist.
|
||||
* <p>
|
||||
* This typically occurs when Ebean is persisting the value object to the data
|
||||
* store.
|
||||
* </p>
|
||||
*
|
||||
* @param beanType
|
||||
* the value object
|
||||
*/
|
||||
S unwrapValue(B beanType);
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.DB2Ddl;
|
||||
|
||||
/**
|
||||
* DB2 specific platform.
|
||||
*/
|
||||
public class DB2Platform extends DatabasePlatform {
|
||||
|
||||
public DB2Platform() {
|
||||
super();
|
||||
this.name = "db2";
|
||||
this.maxTableNameLength = 18;
|
||||
this.maxConstraintNameLength = 18;
|
||||
this.sqlLimiter = new Db2SqlLimiter();
|
||||
this.platformDdl = new DB2Ddl(this);
|
||||
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
booleanDbType = Types.BOOLEAN;
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("real"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 15));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a DB2 specific sequence IdGenerator that supports batch fetching
|
||||
* sequence values.
|
||||
*/
|
||||
@Override
|
||||
public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be,
|
||||
DataSource ds, String seqName, int batchSize) {
|
||||
|
||||
return new DB2SequenceIdGenerator(be, ds, seqName, batchSize);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user