mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
569
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f815415eb0 | ||
|
|
cf81d1699b | ||
|
|
de9576835c | ||
|
|
632cf10096 | ||
|
|
d2b6d06da5 | ||
|
|
b41f3e9d1f | ||
|
|
8357d9c7e7 | ||
|
|
97f1834c4d | ||
|
|
01f551a951 | ||
|
|
482d454fc3 | ||
|
|
2953418683 | ||
|
|
5c142a61f6 | ||
|
|
74626184b2 | ||
|
|
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 | ||
|
|
fad8358a9d | ||
|
|
78c4dbb44d | ||
|
|
9c74520a4b | ||
|
|
c911c710d5 | ||
|
|
f08dd01035 | ||
|
|
a1b4af2716 | ||
|
|
8c500c5836 | ||
|
|
c1d6cc7b75 | ||
|
|
d6fe16ffda | ||
|
|
d0230491e5 | ||
|
|
3526f71f0a | ||
|
|
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 | ||
|
|
185dec9c02 | ||
|
|
20634233ca | ||
|
|
7c9dda586e | ||
|
|
3ca0f7b776 | ||
|
|
85caca48de | ||
|
|
ff85a51994 | ||
|
|
6dc3038d0d | ||
|
|
c0fcb77f3d | ||
|
|
da5d5296b6 | ||
|
|
f04ab28c3f | ||
|
|
d6cd41f8d2 | ||
|
|
504a209a78 | ||
|
|
9f98b5333d | ||
|
|
2a600adbcf | ||
|
|
9ce6007330 | ||
|
|
7780dd6272 | ||
|
|
b01ddea781 | ||
|
|
b848587cd3 | ||
|
|
fe7e929a99 | ||
|
|
3ee0b0224e | ||
|
|
169eba4296 | ||
|
|
91d3279061 | ||
|
|
b4b7c631da | ||
|
|
4f98ca5d91 | ||
|
|
014a9aef6f | ||
|
|
f21c33df7b | ||
|
|
f1eb494e0d | ||
|
|
d26203db1f | ||
|
|
abfe58fb06 | ||
|
|
d0ad5f6c48 | ||
|
|
bc4a246f33 | ||
|
|
61f590944b | ||
|
|
223e53416d | ||
|
|
a3143b1cf6 | ||
|
|
bd3e7c8035 | ||
|
|
b753ce3a73 | ||
|
|
a0f2ebe448 | ||
|
|
7e7810602e | ||
|
|
d218fff374 | ||
|
|
a0e927d353 | ||
|
|
51a58d4993 | ||
|
|
b9f0ee7ac0 | ||
|
|
4f3b461f8e | ||
|
|
adfe5f0305 | ||
|
|
1796c8b9bc | ||
|
|
4bad4358f0 | ||
|
|
92665ebc3b | ||
|
|
59670d0303 | ||
|
|
244275fd72 | ||
|
|
d1e2176a5a | ||
|
|
43968e70b8 | ||
|
|
0aa3bd3c97 | ||
|
|
2d85a9a20c | ||
|
|
157dfcfeb6 | ||
|
|
2b7c204072 | ||
|
|
be731feb6b | ||
|
|
da15d0b2c6 | ||
|
|
9c5fd496c1 | ||
|
|
5075ea32b4 | ||
|
|
f5c8d8896f | ||
|
|
32fdff9f11 | ||
|
|
87f6964995 | ||
|
|
b45226dd41 | ||
|
|
992c40d362 | ||
|
|
9144d60948 | ||
|
|
6396143d49 | ||
|
|
ce045ca0fe | ||
|
|
d722d34072 | ||
|
|
2cc4c2c265 | ||
|
|
0a830841c4 | ||
|
|
c427009b93 | ||
|
|
7f42d045ac | ||
|
|
43afaf1344 | ||
|
|
6c182ecaa5 | ||
|
|
fdb839f90e | ||
|
|
16be213faf | ||
|
|
3344f0ddb0 | ||
|
|
479ac38537 | ||
|
|
e30ad80f5f | ||
|
|
08e46d6bf3 | ||
|
|
876476fdc1 | ||
|
|
81de83a6e7 | ||
|
|
b5b221ffb1 | ||
|
|
3c6eab6c85 | ||
|
|
1be30f1671 | ||
|
|
9a5cb242ce | ||
|
|
ea69cae4a3 | ||
|
|
629fb7a433 | ||
|
|
4ff10da739 | ||
|
|
9472592a50 | ||
|
|
f42682ca90 | ||
|
|
5dc296e644 | ||
|
|
380660913f | ||
|
|
d08ac6973e | ||
|
|
9d23c1d56e | ||
|
|
b5d6c5f70b | ||
|
|
3657d05774 | ||
|
|
2de8ae777d | ||
|
|
16950a5641 | ||
|
|
ad992d07ce | ||
|
|
cbcec8f5ea | ||
|
|
6e2148d20b | ||
|
|
ca1c0a08f3 | ||
|
|
baa6fc355e | ||
|
|
dacdc26902 | ||
|
|
48edf64013 | ||
|
|
e2ee6e8e98 | ||
|
|
e6e6a28245 | ||
|
|
82a695a98a | ||
|
|
cdad31bd8a | ||
|
|
4d16cf9caa | ||
|
|
84a86cad0e | ||
|
|
dfdf87fa2d | ||
|
|
ee0615caec | ||
|
|
79b8395f8f | ||
|
|
87c479cd95 | ||
|
|
abbdda810a | ||
|
|
e621900de9 | ||
|
|
76b33511e1 | ||
|
|
77deab5cf0 | ||
|
|
4a9f8cef0e | ||
|
|
4d1340c16c | ||
|
|
74c6c71301 | ||
|
|
0f0028eb1f | ||
|
|
b4a1d52067 | ||
|
|
d82148248c | ||
|
|
dc7c854432 | ||
|
|
7c83010df1 | ||
|
|
ed41e58073 | ||
|
|
5bab9eb648 | ||
|
|
5ce8eb6046 | ||
|
|
56fee2ea9b | ||
|
|
84f32c2ace | ||
|
|
85288a0652 | ||
|
|
3183287833 | ||
|
|
780ee7c7c0 | ||
|
|
2bac7bf84d | ||
|
|
499862438d | ||
|
|
4ad0b7cf66 | ||
|
|
6108ef484b | ||
|
|
b763f4c875 | ||
|
|
ca7285b2ad | ||
|
|
75b639bc15 | ||
|
|
1a7c4dac3f | ||
|
|
6828fa1786 | ||
|
|
ba7e729ae1 | ||
|
|
c3fba72a24 | ||
|
|
ff401cfc72 | ||
|
|
7902276296 | ||
|
|
95f7a85aa1 | ||
|
|
cf9eb4ed97 | ||
|
|
b5cb04a6ed | ||
|
|
5a9193f732 | ||
|
|
55584f09d5 | ||
|
|
05eb0bfc55 | ||
|
|
cf13119b49 | ||
|
|
e0eff149b5 | ||
|
|
474c2d5595 | ||
|
|
e58cec8bdd | ||
|
|
9dd82c0dd7 | ||
|
|
49d3cc91e4 | ||
|
|
a8c2fc2ed5 | ||
|
|
45d7e3cafd | ||
|
|
be6754bd06 | ||
|
|
83c16ad1c6 | ||
|
|
3f8b389999 | ||
|
|
b4b6a13e75 | ||
|
|
3fad4aae2f | ||
|
|
ceab95e6c2 | ||
|
|
84b37fb014 | ||
|
|
1a1c432c2a | ||
|
|
86faa947af | ||
|
|
6b54b6ef46 | ||
|
|
d8dfd66af3 | ||
|
|
675c51b8c1 | ||
|
|
3cd7ecaa4a | ||
|
|
1b322955ee | ||
|
|
8115c5e230 | ||
|
|
ad180c5531 | ||
|
|
b454f46dd4 | ||
|
|
8a853b28f3 | ||
|
|
a1be7ba5dd | ||
|
|
3914516793 | ||
|
|
8c5854f77c | ||
|
|
0bc5b94eae | ||
|
|
12fa287f35 | ||
|
|
2991cb9ad1 | ||
|
|
3b7f5496a8 | ||
|
|
4be703ff6e | ||
|
|
d2c5765ac1 | ||
|
|
aaf256b9be | ||
|
|
c7c6410cd9 | ||
|
|
2c3c23725a | ||
|
|
92069c0319 | ||
|
|
630ad66ff1 | ||
|
|
b732b390c7 | ||
|
|
8c62fcdcb2 | ||
|
|
e458f577fe | ||
|
|
23434bab8c | ||
|
|
c47b5a1595 | ||
|
|
411846347b | ||
|
|
3722d19424 | ||
|
|
04a7310e5d | ||
|
|
3490e90f03 | ||
|
|
d89817a5c5 | ||
|
|
db1ba5f20e | ||
|
|
4f9a9a5094 | ||
|
|
1c6ac1289d | ||
|
|
b96be84106 | ||
|
|
3c40293183 | ||
|
|
a9a6031986 | ||
|
|
b82085da42 | ||
|
|
9a17a7752c | ||
|
|
92474c2b24 | ||
|
|
9a00b9df0e | ||
|
|
697f67c14a | ||
|
|
2c34bc1636 | ||
|
|
1f9ccf1c8b | ||
|
|
a1f10b8704 | ||
|
|
3c21950b91 | ||
|
|
3b45308ac7 | ||
|
|
00e69e1b5d | ||
|
|
11b3f7a813 | ||
|
|
2185c8a886 | ||
|
|
f8bda05b37 | ||
|
|
0a3b819991 | ||
|
|
5c8b1eb3bb | ||
|
|
824f6dcc7e | ||
|
|
06e23b85ad | ||
|
|
09219c759b | ||
|
|
b861038568 | ||
|
|
bfd8445bcd | ||
|
|
c30e3bf78c | ||
|
|
c793d6652f | ||
|
|
d12e55c20b | ||
|
|
3477f590dd | ||
|
|
6bbf93aba8 | ||
|
|
42d02cc521 | ||
|
|
9ea58572de | ||
|
|
35d82c9104 | ||
|
|
31aae38616 | ||
|
|
f144b53651 | ||
|
|
f47cd7e7c2 | ||
|
|
8765cb8356 | ||
|
|
30abe75a96 | ||
|
|
164e6c71c1 | ||
|
|
dfa6353850 | ||
|
|
d88ff2a3b2 | ||
|
|
713ae75464 | ||
|
|
710fb0e947 | ||
|
|
cb0cf97f3f | ||
|
|
07edb2c81f | ||
|
|
066effa5bf | ||
|
|
bb5ca6c56e | ||
|
|
a64a020e36 | ||
|
|
c24ee53462 | ||
|
|
06e4bdca0e | ||
|
|
3dbf35aca4 | ||
|
|
cd56b3ca3c | ||
|
|
353175626d | ||
|
|
1a3acb86df | ||
|
|
1304646cce | ||
|
|
b3828572fd | ||
|
|
eddd48f8ad | ||
|
|
9797502ef2 | ||
|
|
daba7a11b4 | ||
|
|
92caf69cb3 | ||
|
|
a954f8e9e1 | ||
|
|
71f70c01ae | ||
|
|
74d7652044 | ||
|
|
d7ee748f31 | ||
|
|
2442eb017a | ||
|
|
37ea56ad11 | ||
|
|
067a8b784c | ||
|
|
b18922df79 | ||
|
|
70cce1094e | ||
|
|
44c69dec72 | ||
|
|
6c7074e288 | ||
|
|
1c162b9b18 | ||
|
|
676f0d7a24 | ||
|
|
46e674db57 | ||
|
|
0e1aacdeee | ||
|
|
7268890332 | ||
|
|
b2a3f0c99b | ||
|
|
662be92a16 | ||
|
|
11d623cb69 | ||
|
|
a20822a9e1 | ||
|
|
0510304c0f | ||
|
|
fb2488e3b8 | ||
|
|
5959dcc7db | ||
|
|
3656091d1f | ||
|
|
5122ea4b4d | ||
|
|
db8dd48e53 | ||
|
|
4606c7c99f | ||
|
|
e3a7c3040b | ||
|
|
cb51ea4238 | ||
|
|
a1a48dac2c | ||
|
|
b8d9273152 | ||
|
|
026f0e161f | ||
|
|
75a2633590 | ||
|
|
362ceea79b | ||
|
|
1c9b974427 | ||
|
|
f181e3946f | ||
|
|
6df145b4fa | ||
|
|
a4cb116d4f | ||
|
|
3161664d58 | ||
|
|
4b3f63f6e0 | ||
|
|
d89b1b0367 | ||
|
|
17433bb70b | ||
|
|
fb6ea92ae9 | ||
|
|
08b0a6350d | ||
|
|
bd330b4c0e | ||
|
|
ec234f1f39 | ||
|
|
dd28b28095 | ||
|
|
2a5be6db3d | ||
|
|
545f40703e | ||
|
|
35d0481644 | ||
|
|
2282ff3c6e | ||
|
|
d1d4bf1da8 | ||
|
|
8c6653605d | ||
|
|
e344b5c0a1 | ||
|
|
0e5859716b | ||
|
|
90a794fca5 | ||
|
|
1d6e480402 | ||
|
|
54706302df | ||
|
|
4a59cf4c3d | ||
|
|
8cb8f9eabf | ||
|
|
58a36e6b67 | ||
|
|
064d282f7b | ||
|
|
e83ec42bbc | ||
|
|
409720d854 | ||
|
|
1d8bb8c800 | ||
|
|
ad3b9b2f84 | ||
|
|
b8ecbd507e | ||
|
|
45453bbcd8 | ||
|
|
44dfab2ace | ||
|
|
4ab5cdf841 | ||
|
|
b384cb4043 | ||
|
|
2a323f2256 | ||
|
|
8cfba1015f | ||
|
|
bd6ff5d855 | ||
|
|
7256c3ef90 | ||
|
|
17042a9faf | ||
|
|
b197d8a637 | ||
|
|
2bb39b02d0 | ||
|
|
654e12422d | ||
|
|
82d24b300a | ||
|
|
f69a22736d | ||
|
|
6b19b6410c | ||
|
|
7f546afdca | ||
|
|
4e9e11ac34 | ||
|
|
036092d470 | ||
|
|
2b602f6e51 | ||
|
|
2797f6bbcc | ||
|
|
e9e1a975f9 | ||
|
|
13f7d37e76 | ||
|
|
deb6ce23d7 | ||
|
|
2c95d9dc9a | ||
|
|
8c86976e68 | ||
|
|
c1ca02d871 | ||
|
|
0508b0254f | ||
|
|
45e488cadb | ||
|
|
23731072b7 | ||
|
|
dc230af60b | ||
|
|
622258c82c | ||
|
|
dbed34cc51 | ||
|
|
b4d49161af | ||
|
|
8a68e72305 | ||
|
|
07fe1cde6b | ||
|
|
9da5ce01a7 | ||
|
|
5bcfce9cd4 | ||
|
|
a6d276d4d3 | ||
|
|
5b100e6d37 | ||
|
|
bf75af85c1 | ||
|
|
5cf2d3c39a | ||
|
|
840c5f8992 | ||
|
|
f867cd4c01 | ||
|
|
ad17da5b36 | ||
|
|
9350155c00 | ||
|
|
8a84eaf7a7 | ||
|
|
f0fab77ff7 | ||
|
|
41aace9dc4 | ||
|
|
7c9d752c3d | ||
|
|
81531b6cda | ||
|
|
b70f3574d9 | ||
|
|
be214273cc | ||
|
|
69c2810fbe | ||
|
|
82da81116e | ||
|
|
7d5e135f56 | ||
|
|
6b05d2343b | ||
|
|
fc748ea9c1 | ||
|
|
7b8d2a2f9d | ||
|
|
f8b5a7f312 | ||
|
|
ae261d3782 | ||
|
|
d2ae044d1f | ||
|
|
03189ac92a | ||
|
|
2067568a5e | ||
|
|
57417610a6 | ||
|
|
4cec878242 | ||
|
|
2e7aec3b3d | ||
|
|
104dc599e8 | ||
|
|
e769abf737 | ||
|
|
b79bb892f7 | ||
|
|
8f93f780fd | ||
|
|
158a23a34d | ||
|
|
523ddbab63 | ||
|
|
00d4298065 | ||
|
|
4eb1aded2d | ||
|
|
221f5ad879 | ||
|
|
75e3b9276e | ||
|
|
29c51ecb95 | ||
|
|
8c535ba837 | ||
|
|
11e02710d9 | ||
|
|
658ce3c5d3 | ||
|
|
2de78cd20f | ||
|
|
1b8b05790e | ||
|
|
444b848c22 | ||
|
|
707dda636d | ||
|
|
e8a979bc9d | ||
|
|
3fb9a7414c | ||
|
|
061652a48e | ||
|
|
57b03cf86d | ||
|
|
45dbe3bb9a | ||
|
|
24037eeb73 | ||
|
|
2c6f637dab | ||
|
|
a85f9c4be8 | ||
|
|
5d9f11a362 | ||
|
|
3d484c79a2 | ||
|
|
5881047606 | ||
|
|
333eaf08c2 | ||
|
|
a1ff83e9e4 | ||
|
|
640db2267f | ||
|
|
4059034891 | ||
|
|
c58db0033d | ||
|
|
da90eccc12 | ||
|
|
524be4ce55 | ||
|
|
649c14644e | ||
|
|
c504256579 | ||
|
|
97d803e3e0 | ||
|
|
46bc09a09b | ||
|
|
fe387cf456 | ||
|
|
b4cd66e28c | ||
|
|
7c11acaf89 | ||
|
|
7b4d6f2d17 | ||
|
|
8f100f2786 | ||
|
|
6233392548 | ||
|
|
abaa1ff934 | ||
|
|
a7b239a1b7 | ||
|
|
e8c0756ee9 | ||
|
|
e5179432a0 | ||
|
|
d25123eb23 | ||
|
|
27602c15b9 | ||
|
|
bdc81bf6f4 | ||
|
|
b9237cb8a8 | ||
|
|
99e548db03 | ||
|
|
71499d15e1 | ||
|
|
c9b0fd708a | ||
|
|
8e43ece490 | ||
|
|
fb2b8b4cf6 | ||
|
|
33f3920a60 | ||
|
|
9a912390d4 | ||
|
|
30a5769973 | ||
|
|
084c9ad433 | ||
|
|
84fa373728 | ||
|
|
12e6c0b139 | ||
|
|
6f702098bc | ||
|
|
ad3292b92d |
@@ -0,0 +1,12 @@
|
||||
# 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
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
GITHUB ISSUES ARE STRICTLY CONTROLLED FOR THIS PROJECT.
|
||||
|
||||
Refer to http://ebean-orm.github.io/support for the policies controlling the use of github issues.
|
||||
Please post issues to the Ebean group https://groups.google.com/forum/#!forum/ebean first.
|
||||
|
||||
## Expected behavior
|
||||
|
||||
## Actual behavior
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
```java
|
||||
// some java code
|
||||
```
|
||||
|
||||
```console
|
||||
// some logging output
|
||||
```
|
||||
@@ -1,14 +1,17 @@
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm) - avaje-ebeanorm
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent) - avaje-ebeanorm-agent
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer) - avaje-ebeanorm-mavenenhancer
|
||||
# Need help?
|
||||
Post questions or issues to the Ebean google group - https://groups.google.com/forum/#!forum/ebean
|
||||
|
||||
# Documentation
|
||||
Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
|
||||
|
||||
|
||||
Ebean ORM
|
||||
==============
|
||||
[https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
|
||||
## 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 - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
|
||||
|
||||
[Maven central - avaje-ebeanorm](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebeanorm%22%20AND%20a%3A%22avaje-ebeanorm%22 "maven central ebeanorm")
|
||||
|
||||
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cavaje-ebeanorm "maven central ebeanorm")
|
||||
## 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
|
||||
|
||||
|
||||
@@ -3,42 +3,25 @@
|
||||
|
||||
<parent>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-javaparent</artifactId>
|
||||
<version>1.2</version>
|
||||
<artifactId>java8-parent</artifactId>
|
||||
<version>1.1</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>7.4.1</version>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>9.1.2</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
<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>
|
||||
<connection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git</developerConnection>
|
||||
<url>https://github.com/ebean-orm/avaje-ebeanorm.git</url>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-9.1.2</tag>
|
||||
</scm>
|
||||
|
||||
<dependencies>
|
||||
@@ -64,27 +47,44 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-datasource</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<version>1.1.3</version>
|
||||
</dependency>
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>org.avaje</groupId>-->
|
||||
<!--<artifactId>avaje-datasource-alert</artifactId>-->
|
||||
<!--<version>1.1.1</version>-->
|
||||
<!--</dependency>-->
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-classpath-scanner-api</artifactId>
|
||||
<version>2.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-classpath-scanner</artifactId>
|
||||
<version>2.2.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.7</version>
|
||||
<version>[1.7.1,1.7.99)</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope for Spring boot loader classpath scanning support -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-loader</artifactId>
|
||||
<version>1.2.7.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-runtime</artifactId>
|
||||
<version>4.5.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope for JsonNode support -->
|
||||
@@ -95,13 +95,6 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.transaction</groupId>
|
||||
<artifactId>jta</artifactId>
|
||||
@@ -139,6 +132,8 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Test scope -->
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>oracle</groupId>-->
|
||||
<!--<artifactId>oracle-jdbc</artifactId>-->
|
||||
@@ -153,13 +148,6 @@
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>2.4.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-agentloader</artifactId>
|
||||
@@ -168,9 +156,9 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-agent</artifactId>
|
||||
<version>4.9.2</version>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<artifactId>ebean-agent</artifactId>
|
||||
<version>8.1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -179,7 +167,7 @@
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.189</version>
|
||||
<version>1.4.192</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -219,33 +207,29 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.moduuid</groupId>
|
||||
<artifactId>avaje-moduuid</artifactId>
|
||||
<version>1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
<!-- Enhance the meta beans -->
|
||||
<build>
|
||||
<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.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
|
||||
<version>4.9.2</version>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>8.1.1</version>
|
||||
<executions>
|
||||
<!-- Not going to enhance Model bean -->
|
||||
<execution>
|
||||
<id>test</id>
|
||||
<phase>process-test-classes</phase>
|
||||
<configuration>
|
||||
<classSource>target/test-classes</classSource>
|
||||
<packages>com.avaje.tests.**</packages>
|
||||
<transformArgs>debug=1</transformArgs>
|
||||
</configuration>
|
||||
<goals>
|
||||
@@ -276,7 +260,8 @@
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
@@ -286,12 +271,13 @@
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<doctitle>Ebean 7</doctitle>
|
||||
<doctitle>Ebean 9</doctitle>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
@@ -311,7 +297,6 @@
|
||||
<linksource>true</linksource>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
</configuration>
|
||||
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
@@ -321,6 +306,7 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
|
||||
@@ -38,6 +38,11 @@ public interface BeanState {
|
||||
*/
|
||||
void setDisableLazyLoad(boolean disableLazyLoading);
|
||||
|
||||
/**
|
||||
* Return true if the bean has lazy loading disabled.
|
||||
*/
|
||||
boolean isDisableLazyLoad();
|
||||
|
||||
/**
|
||||
* Set the loaded state of the property given it's name.
|
||||
*
|
||||
@@ -115,4 +120,9 @@ public interface BeanState {
|
||||
* for a fully loaded entity bean.
|
||||
*/
|
||||
void setLoaded();
|
||||
|
||||
/**
|
||||
* Reset the bean putting it into NEW state such that a save() results in an insert.
|
||||
*/
|
||||
void resetForInsert();
|
||||
}
|
||||
@@ -30,7 +30,7 @@ final class DRawSqlColumnsParser {
|
||||
|
||||
private ColumnMapping parse() {
|
||||
|
||||
ArrayList<ColumnMapping.Column> columns = new ArrayList<ColumnMapping.Column>();
|
||||
ArrayList<ColumnMapping.Column> columns = new ArrayList<>();
|
||||
while (pos <= end) {
|
||||
ColumnMapping.Column c = nextColumnInfo();
|
||||
columns.add(c);
|
||||
@@ -47,10 +47,10 @@ final class DRawSqlColumnsParser {
|
||||
|
||||
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().length() > 0) {
|
||||
tmp.add(split[i].trim());
|
||||
ArrayList<String> tmp = new ArrayList<>(split.length);
|
||||
for (String aSplit : split) {
|
||||
if (!aSplit.trim().isEmpty()) {
|
||||
tmp.add(aSplit.trim());
|
||||
}
|
||||
}
|
||||
split = tmp.toArray(new String[tmp.size()]);
|
||||
@@ -66,8 +66,8 @@ final class DRawSqlColumnsParser {
|
||||
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
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.RawSql.Sql;
|
||||
import com.avaje.ebeaninternal.server.querydefn.SimpleTextParser;
|
||||
|
||||
/**
|
||||
* Parses sql-select queries to try and determine the location where WHERE and
|
||||
@@ -8,13 +9,13 @@ import com.avaje.ebean.RawSql.Sql;
|
||||
*/
|
||||
class DRawSqlParser {
|
||||
|
||||
public static final String $_AND_HAVING = "${andHaving}";
|
||||
private static final String $_AND_HAVING = "${andHaving}";
|
||||
|
||||
public static final String $_HAVING = "${having}";
|
||||
private static final String $_HAVING = "${having}";
|
||||
|
||||
public static final String $_AND_WHERE = "${andWhere}";
|
||||
private static final String $_AND_WHERE = "${andWhere}";
|
||||
|
||||
public static final String $_WHERE = "${where}";
|
||||
private static final String $_WHERE = "${where}";
|
||||
|
||||
private final SimpleTextParser textParser;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Document storage operations.
|
||||
@@ -205,6 +206,39 @@ public interface DocumentStore {
|
||||
*/
|
||||
void createIndex(String indexName, String alias);
|
||||
|
||||
/**
|
||||
* Modify the settings on an index.
|
||||
* <p>
|
||||
* For example, this can be used be used to set elasticSearch refresh_interval
|
||||
* on an index before a bulk update.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // refresh_interval -1 ... disable refresh while bulk loading
|
||||
*
|
||||
* Map<String,Object> settings = new LinkedHashMap<>();
|
||||
* settings.put("refresh_interval", "-1");
|
||||
*
|
||||
* documentStore.indexSettings("product", settings);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // refresh_interval 1s ... restore after bulk loading
|
||||
*
|
||||
* Map<String,Object> settings = new LinkedHashMap<>();
|
||||
* settings.put("refresh_interval", "1s");
|
||||
*
|
||||
* documentStore.indexSettings("product", settings);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param indexName the name of the index to update settings on
|
||||
* @param settings the settings to set on the index
|
||||
*/
|
||||
void indexSettings(String indexName, Map<String, Object> settings);
|
||||
|
||||
/**
|
||||
* Copy the index to a new index.
|
||||
* <p>
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.text.csv.CsvReader;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheStrategy;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.text.csv.CsvReader;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
|
||||
/**
|
||||
* This Ebean object is effectively a singleton that holds a map of registered
|
||||
* {@link EbeanServer}s. It additionally provides a convenient way to use the
|
||||
@@ -135,13 +132,13 @@ public final class Ebean {
|
||||
/**
|
||||
* Cache for fast concurrent read access.
|
||||
*/
|
||||
private final ConcurrentHashMap<String, EbeanServer> concMap = new ConcurrentHashMap<String, EbeanServer>();
|
||||
private final ConcurrentHashMap<String, EbeanServer> concMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Cache for synchronized read, creation and put. Protected by the monitor
|
||||
* object.
|
||||
*/
|
||||
private final HashMap<String, EbeanServer> syncMap = new HashMap<String, EbeanServer>();
|
||||
private final HashMap<String, EbeanServer> syncMap = new HashMap<>();
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
@@ -164,7 +161,7 @@ public final class Ebean {
|
||||
// look to see if there is a default server defined
|
||||
String defaultName = PrimaryServer.getDefaultServerName();
|
||||
logger.debug("defaultName:" + defaultName);
|
||||
if (defaultName != null && defaultName.trim().length() > 0) {
|
||||
if (defaultName != null && !defaultName.trim().isEmpty()) {
|
||||
defaultServer = getWithCreate(defaultName.trim());
|
||||
}
|
||||
}
|
||||
@@ -185,7 +182,7 @@ public final class Ebean {
|
||||
}
|
||||
|
||||
private EbeanServer get(String name) {
|
||||
if (name == null || name.length() == 0) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
return defaultServer;
|
||||
}
|
||||
// non-synchronized read
|
||||
@@ -502,6 +499,13 @@ public final class Ebean {
|
||||
serverMgr.getDefaultServer().endTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the current transaction as rollback only.
|
||||
*/
|
||||
public static void setRollbackOnly() {
|
||||
serverMgr.getDefaultServer().currentTransaction().setRollbackOnly();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of the differences between two objects of the same type.
|
||||
* <p>
|
||||
@@ -642,58 +646,6 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().saveAll(beans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the associations (from the intersection table) of a ManyToMany given
|
||||
* the owner bean and the propertyName of the ManyToMany collection.
|
||||
* <p>
|
||||
* Typically these deletions occur automatically when persisting a ManyToMany
|
||||
* collection and this provides a way to invoke those deletions directly.
|
||||
* </p>
|
||||
*
|
||||
* @return the number of associations deleted (from the intersection table).
|
||||
*/
|
||||
public static int deleteManyToManyAssociations(Object ownerBean, String propertyName) {
|
||||
return serverMgr.getDefaultServer().deleteManyToManyAssociations(ownerBean, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the associations of a ManyToMany given the owner bean and the
|
||||
* propertyName of the ManyToMany collection.
|
||||
* <p>
|
||||
* Typically the saving of these associations (inserting into the intersection
|
||||
* table) occurs automatically when persisting a ManyToMany. This provides a
|
||||
* way to invoke those insertions directly.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can use this when the collection is new and in this case all the
|
||||
* entries in the collection are treated as additions are result in inserts
|
||||
* into the intersection table.
|
||||
* </p>
|
||||
*/
|
||||
public static void saveManyToManyAssociations(Object ownerBean, String propertyName) {
|
||||
serverMgr.getDefaultServer().saveManyToManyAssociations(ownerBean, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the associated collection or bean given the property name.
|
||||
* <p>
|
||||
* This is similar to performing a save cascade on a specific property
|
||||
* manually/programmatically.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that you can turn on/off cascading for a transaction via
|
||||
* {@link Transaction#setPersistCascade(boolean)}
|
||||
* </p>
|
||||
*
|
||||
* @param ownerBean
|
||||
* the bean instance holding the property we want to save
|
||||
* @param propertyName
|
||||
* the property we want to save
|
||||
*/
|
||||
public static void saveAssociation(Object ownerBean, String propertyName) {
|
||||
serverMgr.getDefaultServer().saveAssociation(ownerBean, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the bean.
|
||||
* <p>
|
||||
@@ -731,11 +683,25 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().delete(beanType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete permanent the bean given its type and id.
|
||||
*/
|
||||
public static int deletePermanent(Class<?> beanType, Object id) {
|
||||
return serverMgr.getDefaultServer().deletePermanent(beanType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete several beans given their type and id values.
|
||||
*/
|
||||
public static void deleteAll(Class<?> beanType, Collection<?> ids) {
|
||||
serverMgr.getDefaultServer().deleteAll(beanType, ids);
|
||||
public static int deleteAll(Class<?> beanType, Collection<?> ids) {
|
||||
return serverMgr.getDefaultServer().deleteAll(beanType, ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete permanent several beans given their type and id values.
|
||||
*/
|
||||
public static int deleteAllPermanent(Class<?> beanType, Collection<?> ids) {
|
||||
return serverMgr.getDefaultServer().deleteAllPermanent(beanType, ids);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -921,19 +887,6 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().createSqlQuery(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a named sql query.
|
||||
* <p>
|
||||
* The query statement will be defined in a deployment orm xml file.
|
||||
* </p>
|
||||
*
|
||||
* @param namedQuery
|
||||
* the name of the query
|
||||
*/
|
||||
public static SqlQuery createNamedSqlQuery(String namedQuery) {
|
||||
return serverMgr.getDefaultServer().createNamedSqlQuery(namedQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sql update for executing native dml statements.
|
||||
* <p>
|
||||
@@ -943,10 +896,6 @@ public final class Ebean {
|
||||
* <p>
|
||||
* See {@link SqlUpdate} for example usage.
|
||||
* </p>
|
||||
* <p>
|
||||
* Where possible it would be expected practice to put the statement in a orm
|
||||
* xml file (named update) and use {@link #createNamedSqlUpdate(String)} .
|
||||
* </p>
|
||||
*/
|
||||
public static SqlUpdate createSqlUpdate(String sql) {
|
||||
return serverMgr.getDefaultServer().createSqlUpdate(sql);
|
||||
@@ -961,144 +910,6 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().createCallableSql(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a named sql update.
|
||||
* <p>
|
||||
* The statement (an Insert Update or Delete statement) will be defined in a
|
||||
* deployment orm xml file.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Use a namedQuery
|
||||
* UpdateSql update = Ebean.createNamedSqlUpdate("update.topic.count");
|
||||
*
|
||||
* update.setParameter("count", 1);
|
||||
* update.setParameter("topicId", 50);
|
||||
*
|
||||
* int modifiedCount = update.execute();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static SqlUpdate createNamedSqlUpdate(String namedQuery) {
|
||||
return serverMgr.getDefaultServer().createNamedSqlUpdate(namedQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a named Query that will have defined fetch paths, predicates etc.
|
||||
* <p>
|
||||
* The query is created from a statement that will be defined in a deployment
|
||||
* orm xml file or NamedQuery annotations. The query will typically already
|
||||
* define fetch paths, predicates, order by clauses etc so often you will just
|
||||
* need to bind required parameters and then execute the query.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // example
|
||||
* Query<Order> query = Ebean.createNamedQuery(Order.class, "new.for.customer");
|
||||
* query.setParameter("customerId", 23);
|
||||
* List<Order> newOrders = query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType
|
||||
* the class of entity to be fetched
|
||||
* @param namedQuery
|
||||
* the name of the query
|
||||
*/
|
||||
public static <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery) {
|
||||
|
||||
return serverMgr.getDefaultServer().createNamedQuery(beanType, namedQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query using the query language.
|
||||
* <p>
|
||||
* Note that you are allowed to add additional clauses using where() as well
|
||||
* as use fetch() and setOrderBy() after the query has been created.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that this method signature used to map to named queries and that has
|
||||
* moved to {@link #createNamedQuery(Class, String)}.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String q = "find order fetch details where status = :st";
|
||||
*
|
||||
* List<Order> newOrders = Ebean.>findOrder.class, q)
|
||||
* .setParameter("st", Order.Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param query
|
||||
* the object query
|
||||
*/
|
||||
public static <T> Query<T> createQuery(Class<T> beanType, String query) {
|
||||
return serverMgr.getDefaultServer().createQuery(beanType, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a named orm update. The update statement is specified via the
|
||||
* NamedUpdate annotation.
|
||||
* <p>
|
||||
* The orm update differs from the SqlUpdate in that it uses the bean name and
|
||||
* bean property names rather than table and column names.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that named update statements can be specified in raw sql (with column
|
||||
* and table names) or using bean name and bean property names. This can be
|
||||
* specified with the isSql flag.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example named updates:
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* package app.data;
|
||||
*
|
||||
* import ...
|
||||
*
|
||||
* @NamedUpdates(value = {
|
||||
* @NamedUpdate( name = "setTitle",
|
||||
* isSql = false,
|
||||
* notifyCache = false,
|
||||
* update = "update topic set title = :title, postCount = :postCount where id = :id"),
|
||||
* @NamedUpdate( name = "setPostCount",
|
||||
* notifyCache = false,
|
||||
* update = "update f_topic set post_count = :postCount where id = :id"),
|
||||
* @NamedUpdate( name = "incrementPostCount",
|
||||
* notifyCache = false,
|
||||
* isSql = false,
|
||||
* update = "update Topic set postCount = postCount + 1 where id = :id") })
|
||||
* @Entity
|
||||
* @Table(name = "f_topic")
|
||||
* public class Topic { ...
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Example using a named update:
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Update<Topic> update = Ebean.createNamedUpdate(Topic.class, "setPostCount");
|
||||
* update.setParameter("postCount", 10);
|
||||
* update.setParameter("id", 3);
|
||||
*
|
||||
* int rows = update.execute();
|
||||
* System.out.println("rows updated: " + rows);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static <T> Update<T> createNamedUpdate(Class<T> beanType, String namedUpdate) {
|
||||
|
||||
return serverMgr.getDefaultServer().createNamedUpdate(beanType, namedUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a orm update where you will supply the insert/update or delete
|
||||
* statement (rather than using a named one that is already defined using the
|
||||
@@ -1141,6 +952,21 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().createCsvReader(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a named query.
|
||||
* <p>
|
||||
* For RawSql the named query is expected to be in ebean.xml.
|
||||
* </p>
|
||||
*
|
||||
* @param beanType The type of entity bean
|
||||
* @param namedQuery The name of the query
|
||||
* @param <T> The type of entity bean
|
||||
* @return The query
|
||||
*/
|
||||
public static <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery) {
|
||||
return serverMgr.getDefaultServer().createNamedQuery(beanType, namedQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query for a type of entity bean.
|
||||
* <p>
|
||||
@@ -1156,39 +982,7 @@ public final class Ebean {
|
||||
* {@link Query#findSet()} etc will execute against the same EbeanServer from
|
||||
* which is was created.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* // Find order 2 additionally fetching the customer, details and details.product
|
||||
* // name.
|
||||
*
|
||||
* Order order = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .fetch("details")
|
||||
* .fetch("detail.product", "name")
|
||||
* .setId(2)
|
||||
* .findUnique();
|
||||
*
|
||||
* // Find order 2 additionally fetching the customer, details and details.product
|
||||
* // name.
|
||||
* // Note: same query as above but using the query language
|
||||
* // Note: using a named query would be preferred practice
|
||||
*
|
||||
* String oql = "find order fetch customer fetch details fetch details.product (name) where id = :orderId ";
|
||||
*
|
||||
* Query<Order> query = Ebean.find(Order.class);
|
||||
* query.setQuery(oql);
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* // Using a named query
|
||||
* Query<Order> query = Ebean.find(Order.class, "with.details");
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* @param beanType
|
||||
* the class of entity to be fetched
|
||||
* @return A ORM Query object for this beanType
|
||||
@@ -1198,6 +992,47 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().createQuery(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the Ebean query language statement returning the query which can then
|
||||
* be modified (add expressions, change order by clause, change maxRows, change
|
||||
* fetch and select paths etc).
|
||||
*
|
||||
* <h3>Example</h3>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
*
|
||||
* // Find order additionally fetching the customer, details and details.product name.
|
||||
*
|
||||
* String eql = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class, eql);
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* // This is the same as:
|
||||
*
|
||||
* Order order = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .fetch("details")
|
||||
* .fetch("detail.product", "name")
|
||||
* .setId(2)
|
||||
* .findUnique();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The type of bean to fetch
|
||||
* @param eql The Ebean query
|
||||
* @param <T> The type of the entity bean
|
||||
*
|
||||
* @return The query with expressions defined as per the parsed query statement
|
||||
*/
|
||||
public static <T> Query<T> createQuery(Class<T> beanType, String eql) {
|
||||
|
||||
return serverMgr.getDefaultServer().createQuery(beanType, eql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query for a type of entity bean.
|
||||
* <p>
|
||||
@@ -1215,6 +1050,28 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().find(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Update query to perform a bulk update.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = Ebean.update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The type of entity bean to update
|
||||
* @param <T> The type of entity bean
|
||||
* @return The update query to use
|
||||
*/
|
||||
public static <T> UpdateQuery<T> update(Class<T> beanType) {
|
||||
return serverMgr.getDefaultServer().update(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a filter for sorting and filtering lists of entities locally without
|
||||
* going back to the database.
|
||||
@@ -1484,29 +1341,6 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().getBackgroundExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the cache warming queries on all bean types that have one defined for
|
||||
* the default/primary EbeanServer.
|
||||
* <p>
|
||||
* A cache warming query can be defined via {@link CacheStrategy}.
|
||||
* </p>
|
||||
*/
|
||||
public static void runCacheWarming() {
|
||||
serverMgr.getDefaultServer().runCacheWarming();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the cache warming query for a specific bean type for the
|
||||
* default/primary EbeanServer.
|
||||
* <p>
|
||||
* A cache warming query can be defined via {@link CacheStrategy}.
|
||||
* </p>
|
||||
*/
|
||||
public static void runCacheWarming(Class<?> beanType) {
|
||||
|
||||
serverMgr.getDefaultServer().runCacheWarming(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JsonContext for reading/writing JSON.
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -133,7 +133,7 @@ public class EbeanServerFactory {
|
||||
/**
|
||||
* Create the container instance using the configuration.
|
||||
*/
|
||||
private static SpiContainer createContainer(ContainerConfig containerConfig) {
|
||||
protected static SpiContainer createContainer(ContainerConfig containerConfig) {
|
||||
|
||||
String implClassName = System.getProperty("ebean.container", DEFAULT_CONTAINER);
|
||||
|
||||
|
||||
@@ -209,6 +209,20 @@ public class Expr {
|
||||
return Ebean.getExpressionFactory().icontains(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* For collection properties that are empty (have not existing elements).
|
||||
*/
|
||||
public static Expression isEmpty(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isEmpty(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* For collection properties that are not empty (have existing elements).
|
||||
*/
|
||||
public static Expression isNotEmpty(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNotEmpty(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the array of values.
|
||||
*/
|
||||
|
||||
@@ -87,6 +87,38 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression jsonBetween(String propertyName, String path, Object lowerValue, Object upperValue);
|
||||
|
||||
/**
|
||||
* Array contains all the given values.
|
||||
* <p>
|
||||
* Array support is effectively limited to Postgres at this time.
|
||||
* </p>
|
||||
*/
|
||||
Expression arrayContains(String propertyName, Object... values);
|
||||
|
||||
/**
|
||||
* Array does not contain the given values.
|
||||
* <p>
|
||||
* Array support is effectively limited to Postgres at this time.
|
||||
* </p>
|
||||
*/
|
||||
Expression arrayNotContains(String propertyName, Object... values);
|
||||
|
||||
/**
|
||||
* Array is empty - for the given array property.
|
||||
* <p>
|
||||
* Array support is effectively limited to Postgres at this time.
|
||||
* </p>
|
||||
*/
|
||||
Expression arrayIsEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Array is not empty - for the given array property.
|
||||
* <p>
|
||||
* Array support is effectively limited to Postgres at this time.
|
||||
* </p>
|
||||
*/
|
||||
Expression arrayIsNotEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
@@ -103,6 +135,11 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression ieq(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case Insensitive Equal To that allows for named parameter use.
|
||||
*/
|
||||
Expression ieqObject(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
@@ -160,6 +197,11 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType);
|
||||
|
||||
/**
|
||||
* Like with support for named parameters.
|
||||
*/
|
||||
Expression like(String propertyName, Object value, boolean caseInsensitive, LikeType likeType);
|
||||
|
||||
/**
|
||||
* Like - property like value where the value contains the SQL wild card
|
||||
* characters % (percentage) and _ (underscore).
|
||||
@@ -246,6 +288,16 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression notExists(Query<?> subQuery);
|
||||
|
||||
/**
|
||||
* Is empty expression for collection properties.
|
||||
*/
|
||||
Expression isEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Is not empty expression for collection properties.
|
||||
*/
|
||||
Expression isNotEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Id Equal to - ID property is equal to the value.
|
||||
*/
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.util.Set;
|
||||
* more methods than you would initially expect (the ones duplicated from
|
||||
* Query).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @see Query#where()
|
||||
*/
|
||||
public interface ExpressionList<T> {
|
||||
@@ -83,14 +83,14 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Add an orderBy clause to the query.
|
||||
*
|
||||
*
|
||||
* @see Query#orderBy(String)
|
||||
*/
|
||||
Query<T> orderBy(String orderBy);
|
||||
|
||||
/**
|
||||
* Add an orderBy clause to the query.
|
||||
*
|
||||
*
|
||||
* @see Query#orderBy(String)
|
||||
*/
|
||||
Query<T> setOrderBy(String orderBy);
|
||||
@@ -116,12 +116,6 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Query<T> asDraft();
|
||||
|
||||
/**
|
||||
* Deprecated in favour of setIncludeSoftDeletes().
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> includeSoftDeletes();
|
||||
|
||||
/**
|
||||
* Execute the query including soft deleted rows.
|
||||
*/
|
||||
@@ -135,13 +129,21 @@ public interface ExpressionList<T> {
|
||||
* optimal depending on the database platform.
|
||||
* </p>
|
||||
*
|
||||
* @return the number of beans/rows that were deleted.
|
||||
* @return the number of rows that were deleted.
|
||||
*/
|
||||
int delete();
|
||||
|
||||
/**
|
||||
* Execute as a update query.
|
||||
*
|
||||
* @return the number of rows that were updated.
|
||||
* @see UpdateQuery
|
||||
*/
|
||||
int update();
|
||||
|
||||
/**
|
||||
* Execute the query iterating over the results.
|
||||
*
|
||||
*
|
||||
* @see Query#findIterate()
|
||||
*/
|
||||
QueryIterator<T> findIterate();
|
||||
@@ -163,17 +165,17 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Execute the query returning a list.
|
||||
*
|
||||
*
|
||||
* @see Query#findList()
|
||||
*/
|
||||
List<T> findList();
|
||||
|
||||
/**
|
||||
* Execute the query returning the list of Id's.
|
||||
*
|
||||
*
|
||||
* @see Query#findIds()
|
||||
*/
|
||||
List<Object> findIds();
|
||||
<A> List<A> findIds();
|
||||
|
||||
/**
|
||||
* Return the count of entities this query should return.
|
||||
@@ -181,26 +183,53 @@ public interface ExpressionList<T> {
|
||||
* This is the number of 'top level' or 'root level' entities.
|
||||
* </p>
|
||||
*/
|
||||
int findRowCount();
|
||||
int findCount();
|
||||
|
||||
/**
|
||||
* Execute the query returning a set.
|
||||
*
|
||||
*
|
||||
* @see Query#findSet()
|
||||
*/
|
||||
Set<T> findSet();
|
||||
|
||||
/**
|
||||
* Execute the query returning a map.
|
||||
*
|
||||
*
|
||||
* @see Query#findMap()
|
||||
*/
|
||||
Map<?, T> findMap();
|
||||
<K> Map<K, T> findMap();
|
||||
|
||||
/**
|
||||
* Return a typed map specifying the key property and type.
|
||||
* Execute the query returning a list of values for a single property.
|
||||
*
|
||||
* <h3>Example 1:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* .select("name")
|
||||
* .orderBy().asc("name")
|
||||
* .findSingleAttributeList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Example 2:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .where().eq("status", Customer.Status.NEW)
|
||||
* .orderBy().asc("name")
|
||||
* .setMaxRows(100)
|
||||
* .findSingleAttributeList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @return the list of values for the selected property
|
||||
*/
|
||||
<K> Map<K, T> findMap(String keyProperty, Class<K> keyType);
|
||||
<A> List<A> findSingleAttributeList();
|
||||
|
||||
/**
|
||||
* Execute the query returning a single bean or null (if no matching
|
||||
@@ -224,10 +253,10 @@ public interface ExpressionList<T> {
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return a Future object for the row count query
|
||||
*/
|
||||
FutureRowCount<T> findFutureRowCount();
|
||||
FutureRowCount<T> findFutureCount();
|
||||
|
||||
/**
|
||||
* Execute find Id's query in a background thread.
|
||||
@@ -236,7 +265,7 @@ public interface ExpressionList<T> {
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return a Future object for the list of Id's
|
||||
*/
|
||||
FutureIds<T> findFutureIds();
|
||||
@@ -248,32 +277,11 @@ public interface ExpressionList<T> {
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return a Future object for the list result of the query
|
||||
*/
|
||||
FutureList<T> findFutureList();
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query using pageIndex and pageSize.
|
||||
* <p>
|
||||
* The benefit of using this over just using the normal {@link Query#setFirstRow(int)} and
|
||||
* {@link Query#setMaxRows(int)} is that it additionally wraps an optional call to
|
||||
* {@link Query#findFutureRowCount()} to determine total row count, total page count etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* Internally this works using {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} on
|
||||
* the query. This translates into SQL that uses limit offset, rownum or row_number
|
||||
* function to limit the result set.
|
||||
* </p>
|
||||
*
|
||||
* @param pageIndex
|
||||
* The zero based index of the page.
|
||||
* @param pageSize
|
||||
* The number of beans to return per page.
|
||||
* @return The PagedList
|
||||
*/
|
||||
PagedList<T> findPagedList(int pageIndex, int pageSize);
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query using firstRow and maxRows.
|
||||
* <p>
|
||||
@@ -332,7 +340,7 @@ public interface ExpressionList<T> {
|
||||
/**
|
||||
* Specify specific properties to fetch on the main/root bean (aka partial
|
||||
* object).
|
||||
*
|
||||
*
|
||||
* @see Query#select(String)
|
||||
*/
|
||||
Query<T> select(String properties);
|
||||
@@ -357,28 +365,28 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Set the first row to fetch.
|
||||
*
|
||||
*
|
||||
* @see Query#setFirstRow(int)
|
||||
*/
|
||||
Query<T> setFirstRow(int firstRow);
|
||||
|
||||
/**
|
||||
* Set the maximum number of rows to fetch.
|
||||
*
|
||||
*
|
||||
* @see Query#setMaxRows(int)
|
||||
*/
|
||||
Query<T> setMaxRows(int maxRows);
|
||||
|
||||
/**
|
||||
* Set the name of the property which values become the key of a map.
|
||||
*
|
||||
*
|
||||
* @see Query#setMapKey(String)
|
||||
*/
|
||||
Query<T> setMapKey(String mapKey);
|
||||
|
||||
/**
|
||||
* Set to true to use the query for executing this query.
|
||||
*
|
||||
*
|
||||
* @see Query#setUseCache(boolean)
|
||||
*/
|
||||
Query<T> setUseCache(boolean useCache);
|
||||
@@ -639,7 +647,7 @@ public interface ExpressionList<T> {
|
||||
* To get control over the options you can create an ExampleExpression and set
|
||||
* those options such as case insensitive etc.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // create an example bean and set the properties
|
||||
@@ -647,26 +655,26 @@ public interface ExpressionList<T> {
|
||||
* Customer example = new Customer();
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
*
|
||||
* List<Customer> list = Ebean.find(Customer.class).where()
|
||||
* // pass the bean into the where() clause
|
||||
* .exampleLike(example)
|
||||
* // you can add other expressions to the same query
|
||||
* .gt("id", 2).findList();
|
||||
*
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* Similarly you can create an ExampleExpression
|
||||
*
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer example = new Customer();
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
*
|
||||
* // create a ExampleExpression with more control
|
||||
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO).includeZeros();
|
||||
*
|
||||
*
|
||||
* List<Customer> list = Ebean.find(Customer.class).where().add(qbe).findList();
|
||||
*
|
||||
* }</pre>
|
||||
@@ -754,11 +762,21 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> notIn(String propertyName, Query<?> subQuery);
|
||||
|
||||
/**
|
||||
* Is empty expression for collection properties.
|
||||
*/
|
||||
ExpressionList<T> isEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Is not empty expression for collection properties.
|
||||
*/
|
||||
ExpressionList<T> isNotEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Exists expression
|
||||
*/
|
||||
ExpressionList<T> exists(Query<?> subQuery);
|
||||
|
||||
|
||||
/**
|
||||
* Not exists expression
|
||||
*/
|
||||
@@ -785,12 +803,41 @@ public interface ExpressionList<T> {
|
||||
* Expression where all the property names in the map are equal to the
|
||||
* corresponding value.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param propertyMap
|
||||
* a map keyed by property names.
|
||||
*/
|
||||
ExpressionList<T> allEq(Map<String, Object> propertyMap);
|
||||
|
||||
/**
|
||||
* Array property contains entries with the given values.
|
||||
*/
|
||||
ExpressionList<T> arrayContains(String propertyName, Object... values);
|
||||
|
||||
/**
|
||||
* Array does not contain the given values.
|
||||
* <p>
|
||||
* Array support is effectively limited to Postgres at this time.
|
||||
* </p>
|
||||
*/
|
||||
ExpressionList<T> arrayNotContains(String propertyName, Object... values);
|
||||
|
||||
/**
|
||||
* Array is empty - for the given array property.
|
||||
* <p>
|
||||
* Array support is effectively limited to Postgres at this time.
|
||||
* </p>
|
||||
*/
|
||||
ExpressionList<T> arrayIsEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Array is not empty - for the given array property.
|
||||
* <p>
|
||||
* Array support is effectively limited to Postgres at this time.
|
||||
* </p>
|
||||
*/
|
||||
ExpressionList<T> arrayIsNotEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Add raw expression with a single parameter.
|
||||
* <p>
|
||||
@@ -906,7 +953,7 @@ public interface ExpressionList<T> {
|
||||
* This is exactly the same as conjunction();
|
||||
* </p>
|
||||
* <p>
|
||||
* Use endJunction() to end the AND junction.
|
||||
* Use endAnd() or endJunction() to end the AND junction.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that a where() clause defaults to an AND junction so
|
||||
@@ -924,11 +971,11 @@ public interface ExpressionList<T> {
|
||||
* .and() // nested and
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end AND junction
|
||||
* .endAnd()
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction() // end AND junction
|
||||
* .endAnd()
|
||||
* .orderBy().asc("name")
|
||||
* .findList();
|
||||
* }</pre>
|
||||
@@ -940,7 +987,7 @@ public interface ExpressionList<T> {
|
||||
* This is exactly the same as disjunction();
|
||||
*
|
||||
* <p>
|
||||
* Use endJunction() to end the OR junction.
|
||||
* Use endOr() or endJunction() to end the OR junction.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
@@ -954,11 +1001,11 @@ public interface ExpressionList<T> {
|
||||
* .and()
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end AND junction
|
||||
* .endAnd()
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction() // end AND junction
|
||||
* .endAnd()
|
||||
* .orderBy().asc("name")
|
||||
* .findList();
|
||||
*
|
||||
@@ -969,7 +1016,7 @@ public interface ExpressionList<T> {
|
||||
/**
|
||||
* Return a list of expressions that will be wrapped by NOT.
|
||||
* <p>
|
||||
* Use endJunction() to end expressions being added to the
|
||||
* Use endNot() or endJunction() to end expressions being added to the
|
||||
* NOT expression list.
|
||||
* </p>
|
||||
*
|
||||
@@ -979,7 +1026,7 @@ public interface ExpressionList<T> {
|
||||
* .not()
|
||||
* .gt("id", 1)
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end the not expressions
|
||||
* .endNot()
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
@@ -993,7 +1040,7 @@ public interface ExpressionList<T> {
|
||||
* .not()
|
||||
* .gt("id", 1)
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction() // end the not expressions
|
||||
* .endNot()
|
||||
* .orderBy()
|
||||
* .asc("name")
|
||||
* .findList();
|
||||
@@ -1066,4 +1113,19 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> endJunction();
|
||||
|
||||
/**
|
||||
* End a AND junction - synonym for endJunction().
|
||||
*/
|
||||
ExpressionList<T> endAnd();
|
||||
|
||||
/**
|
||||
* End a AND junction - synonym for endJunction().
|
||||
*/
|
||||
ExpressionList<T> endOr();
|
||||
|
||||
/**
|
||||
* End a NOT junction - synonym for endJunction().
|
||||
*/
|
||||
ExpressionList<T> endNot();
|
||||
|
||||
}
|
||||
|
||||
@@ -29,8 +29,7 @@ import java.io.Serializable;
|
||||
* // Find Orders join details using a single SQL query
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL
|
||||
* queries
|
||||
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL queries
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
@@ -117,7 +116,7 @@ import java.io.Serializable;
|
||||
* <pre>{@code
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer","name", new FetchConfig().lazy(5))
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .where().eq("status",Order.Status.NEW)
|
||||
* .findList();
|
||||
@@ -125,12 +124,7 @@ import java.io.Serializable;
|
||||
* // query 1) find order where status = Order.Status.NEW
|
||||
* //
|
||||
* // .. if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* find customer (name)
|
||||
* fetch customer.contacts (contactName, phone, email)
|
||||
* fetch customer.shippingAddress (*)
|
||||
* where id in (?,?,?,?,?)
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
|
||||
@@ -9,8 +9,6 @@ import java.util.concurrent.Future;
|
||||
* It extends the java.util.concurrent.Future with the ability to get the Id's
|
||||
* while the query is still executing in the background.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface FutureIds<T> extends Future<List<Object>> {
|
||||
|
||||
@@ -19,16 +17,4 @@ public interface FutureIds<T> extends Future<List<Object>> {
|
||||
*/
|
||||
Query<T> getQuery();
|
||||
|
||||
/**
|
||||
* Return the list of Id's which could be partially populated.
|
||||
* <p>
|
||||
* That is the query getting the id's could still be running and adding id's
|
||||
* to this list.
|
||||
* </p>
|
||||
* <p>
|
||||
* To get the list of Id's ensuring the query has finished use the
|
||||
* {@link Future#get()} method instead of this one.
|
||||
* </p>
|
||||
*/
|
||||
List<Object> getPartialIds();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.util.concurrent.Future;
|
||||
* It extends the java.util.concurrent.Future.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the BeanType
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface FutureRowCount<T> extends Future<Integer> {
|
||||
|
||||
@@ -59,11 +59,11 @@ package com.avaje.ebean;
|
||||
* .and()
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction()
|
||||
* .endAnd()
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction()
|
||||
* .endAnd()
|
||||
* .order().asc("name");
|
||||
*
|
||||
* q.findList();
|
||||
@@ -84,39 +84,46 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
|
||||
/**
|
||||
* AND group.
|
||||
*/
|
||||
AND(" and ", ""),
|
||||
AND(" and ", "", false),
|
||||
|
||||
/**
|
||||
* OR group.
|
||||
*/
|
||||
OR(" or ", ""),
|
||||
OR(" or ", "", false),
|
||||
|
||||
/**
|
||||
* NOT group.
|
||||
*/
|
||||
NOT(" and ", "not "),
|
||||
NOT(" and ", "not ", false),
|
||||
|
||||
/**
|
||||
* FILTER group (for internal use only).
|
||||
*/
|
||||
FILTER("filter", "", true),
|
||||
|
||||
/**
|
||||
* Text search AND group.
|
||||
*/
|
||||
MUST("must", ""),
|
||||
MUST("must", "", true),
|
||||
|
||||
/**
|
||||
* Text search NOT group.
|
||||
*/
|
||||
MUST_NOT("must_not", ""),
|
||||
MUST_NOT("must_not", "", true),
|
||||
|
||||
/**
|
||||
* Text search OR group.
|
||||
*/
|
||||
SHOULD("should", "");
|
||||
SHOULD("should", "", true);
|
||||
|
||||
String prefix;
|
||||
String literal;
|
||||
private String prefix;
|
||||
private String literal;
|
||||
private boolean text;
|
||||
|
||||
Type(String literal, String prefix) {
|
||||
Type(String literal, String prefix, boolean text) {
|
||||
this.literal = literal;
|
||||
this.prefix = prefix;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,6 +139,14 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
|
||||
public String prefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a text type.
|
||||
*/
|
||||
public boolean isText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -362,29 +362,6 @@ public abstract class Model {
|
||||
super(serverName, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Please migrate to use {@link Find} or constructor <code>Finder(Class)</code> that
|
||||
* does not have the idType parameter.
|
||||
* <p/>
|
||||
* Create with the type of the ID property and entity bean and specific server name.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public Finder(Class<I> idType, Class<T> type) {
|
||||
super(null, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Please migrate to use the constructor <code>Finder(String, Class)</code> that
|
||||
* does not have the idType parameter.
|
||||
* <p/>
|
||||
* Create with the type of the ID property and entity bean and specific server name.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public Finder(String serverName, Class<I> idType, Class<T> type) {
|
||||
super(serverName, type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -518,7 +495,7 @@ public abstract class Model {
|
||||
/**
|
||||
* Return typically a different EbeanServer to the default.
|
||||
* <p>
|
||||
* This is equivilent to {@link Ebean#getServer(String)}
|
||||
* This is equivalent to {@link Ebean#getServer(String)}
|
||||
*
|
||||
* @param server
|
||||
* The name of the EbeanServer. If this is null then the default EbeanServer is
|
||||
@@ -535,7 +512,7 @@ public abstract class Model {
|
||||
* Create and return a new Finder for a different server.
|
||||
*/
|
||||
public Finder<I, T> on(String server) {
|
||||
return new Finder<I, T>(server, type);
|
||||
return new Finder<>(server, type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -621,7 +598,7 @@ public abstract class Model {
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findIds()}
|
||||
*/
|
||||
public List<Object> findIds() {
|
||||
public <A> List<A> findIds() {
|
||||
return query().findIds();
|
||||
}
|
||||
|
||||
@@ -683,46 +660,43 @@ public abstract class Model {
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findMap()}
|
||||
*/
|
||||
public Map<?, T> findMap() {
|
||||
public <K> Map<K, T> findMap() {
|
||||
return query().findMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the query and returns the results as a map of the objects specifying the map key
|
||||
* property.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findMap(String, Class)}
|
||||
*/
|
||||
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
|
||||
return query().findMap(keyProperty, keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a PagedList of all entities of the given type (use where() to specify predicates as
|
||||
* needed).
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findPagedList(int, int)}
|
||||
*/
|
||||
public PagedList<T> findPagedList(int pageIndex, int pageSize) {
|
||||
return query().findPagedList(pageIndex, pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a find row count query in a background thread.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findFutureRowCount()}
|
||||
* 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().findFutureRowCount();
|
||||
return query().findFutureCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of entities for this type. *
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findRowCount()}
|
||||
* Equivalent to {@link Query#findCount()}
|
||||
*/
|
||||
public int findCount() {
|
||||
return query().findCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated in favor of findCount().
|
||||
* @deprecated
|
||||
*/
|
||||
public int findRowCount() {
|
||||
return query().findRowCount();
|
||||
return query().findCount();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -866,15 +840,6 @@ public abstract class Model {
|
||||
return query().setId(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new query using the OQL.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#createQuery(Class, String)}
|
||||
*/
|
||||
public Query<T> setQuery(String oql) {
|
||||
return db().createQuery(type, oql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new query based on the <code>RawSql</code>.
|
||||
* <p>
|
||||
|
||||
@@ -28,9 +28,9 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Create an empty OrderBy with no associated query.
|
||||
*/
|
||||
public OrderBy() {
|
||||
this.list = new ArrayList<Property>(3);
|
||||
this.list = new ArrayList<>(3);
|
||||
}
|
||||
|
||||
|
||||
private OrderBy(List<Property> list) {
|
||||
this.list = list;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
*/
|
||||
public OrderBy(Query<T> query, String orderByClause) {
|
||||
this.query = query;
|
||||
this.list = new ArrayList<Property>(3);
|
||||
this.list = new ArrayList<>(3);
|
||||
parse(orderByClause);
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Reverse the ascending/descending order on all the properties.
|
||||
*/
|
||||
public void reverse() {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
list.get(i).reverse();
|
||||
for (Property aList : list) {
|
||||
aList.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,8 +88,8 @@ public final class OrderBy<T> implements Serializable {
|
||||
*/
|
||||
public boolean containsProperty(String propertyName) {
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (propertyName.equals(list.get(i).getProperty())) {
|
||||
for (Property aList : list) {
|
||||
if (propertyName.equals(aList.getProperty())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -100,13 +100,13 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Return a copy of this OrderBy with the path trimmed.
|
||||
*/
|
||||
public OrderBy<T> copyWithTrim(String path) {
|
||||
List<Property> newList = new ArrayList<Property>(list.size());
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
newList.add(list.get(i).copyWithTrim(path));
|
||||
List<Property> newList = new ArrayList<>(list.size());
|
||||
for (Property aList : list) {
|
||||
newList.add(aList.copyWithTrim(path));
|
||||
}
|
||||
return new OrderBy<T>(newList);
|
||||
return new OrderBy<>(newList);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the properties for this OrderBy.
|
||||
*/
|
||||
@@ -141,13 +141,20 @@ public final class OrderBy<T> implements Serializable {
|
||||
*/
|
||||
public OrderBy<T> copy() {
|
||||
|
||||
OrderBy<T> copy = new OrderBy<T>();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
copy.add(list.get(i).copy());
|
||||
OrderBy<T> copy = new OrderBy<>();
|
||||
for (Property aList : list) {
|
||||
copy.add(aList.copy());
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the order by by parsing a raw expression.
|
||||
*/
|
||||
public void add(String rawExpression) {
|
||||
parse(rawExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property to the order by.
|
||||
*/
|
||||
@@ -185,7 +192,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
if (!(obj instanceof OrderBy<?>)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
OrderBy<?> e = (OrderBy<?>) obj;
|
||||
return e.list.equals(list);
|
||||
}
|
||||
@@ -206,8 +213,9 @@ public final class OrderBy<T> implements Serializable {
|
||||
* order by clause and replace.
|
||||
* </p>
|
||||
*/
|
||||
public void clear() {
|
||||
public OrderBy<T> clear() {
|
||||
list.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,24 +229,39 @@ public final class OrderBy<T> implements Serializable {
|
||||
|
||||
private boolean ascending;
|
||||
|
||||
private String nulls;
|
||||
|
||||
private String highLow;
|
||||
|
||||
public Property(String property, boolean ascending) {
|
||||
this.property = property;
|
||||
this.ascending = ascending;
|
||||
}
|
||||
|
||||
public Property(String property, boolean ascending, String nulls, String highLow) {
|
||||
this.property = property;
|
||||
this.ascending = ascending;
|
||||
this.nulls = nulls;
|
||||
this.highLow = highLow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this Property with the path trimmed.
|
||||
*/
|
||||
public Property copyWithTrim(String path) {
|
||||
return new Property(property.substring(path.length() + 1), ascending);
|
||||
return new Property(property.substring(path.length() + 1), ascending, nulls, highLow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc = property.hashCode();
|
||||
hc = hc * 31 + (ascending ? 0 : 1);
|
||||
hc = hc * 31 + (nulls == null ? 0 : nulls.hashCode());
|
||||
hc = hc * 31 + (highLow == null ? 0 : highLow.hashCode());
|
||||
return hc;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
@@ -246,10 +269,11 @@ public final class OrderBy<T> implements Serializable {
|
||||
if (!(obj instanceof Property)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Property e = (Property) obj;
|
||||
return e.ascending == ascending
|
||||
&& e.property.equals(property);
|
||||
if (ascending != e.ascending) return false;
|
||||
if (!property.equals(e.property)) return false;
|
||||
if (nulls != null ? !nulls.equals(e.nulls) : e.nulls != null) return false;
|
||||
return highLow != null ? highLow.equals(e.highLow) : e.highLow == null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
@@ -257,10 +281,20 @@ public final class OrderBy<T> implements Serializable {
|
||||
}
|
||||
|
||||
public String toStringFormat() {
|
||||
if (ascending) {
|
||||
return property;
|
||||
if (nulls == null) {
|
||||
if (ascending) {
|
||||
return property;
|
||||
} else {
|
||||
return property + " desc";
|
||||
}
|
||||
} else {
|
||||
return property + " desc";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(property);
|
||||
if (!ascending) {
|
||||
sb.append(" ").append("desc");
|
||||
}
|
||||
sb.append(" ").append(nulls).append(" ").append(highLow);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,7 +316,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Return a copy of this property.
|
||||
*/
|
||||
public Property copy() {
|
||||
return new Property(property, ascending);
|
||||
return new Property(property, ascending, nulls, highLow);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -322,9 +356,8 @@ public final class OrderBy<T> implements Serializable {
|
||||
}
|
||||
|
||||
String[] chunks = orderByClause.split(",");
|
||||
for (int i = 0; i < chunks.length; i++) {
|
||||
|
||||
String[] pairs = chunks[i].split(" ");
|
||||
for (String chunk : chunks) {
|
||||
String[] pairs = chunk.split(" ");
|
||||
Property p = parseProperty(pairs);
|
||||
if (p != null) {
|
||||
list.add(p);
|
||||
@@ -337,10 +370,10 @@ public final class OrderBy<T> implements Serializable {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<String> wordList = new ArrayList<String>(pairs.length);
|
||||
for (int i = 0; i < pairs.length; i++) {
|
||||
if (!isEmptyString(pairs[i])) {
|
||||
wordList.add(pairs[i]);
|
||||
ArrayList<String> wordList = new ArrayList<>(pairs.length);
|
||||
for (String pair : pairs) {
|
||||
if (!isEmptyString(pair)) {
|
||||
wordList.add(pair);
|
||||
}
|
||||
}
|
||||
if (wordList.isEmpty()) {
|
||||
@@ -353,8 +386,12 @@ public final class OrderBy<T> implements Serializable {
|
||||
boolean asc = isAscending(wordList.get(1));
|
||||
return new Property(wordList.get(0), asc);
|
||||
}
|
||||
String m = "Expecting a max of 2 words in [" + Arrays.toString(pairs)
|
||||
+ "] but got " + wordList.size();
|
||||
if (wordList.size() == 4) {
|
||||
// nulls high or nulls low as 3rd and 4th
|
||||
boolean asc = isAscending(wordList.get(1));
|
||||
return new Property(wordList.get(0), asc, wordList.get(2), wordList.get(3));
|
||||
}
|
||||
String m = "Expecting a 1, 2 or 4 words in [" + Arrays.toString(pairs) + "] but got " + wordList;
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
|
||||
@@ -371,6 +408,6 @@ public final class OrderBy<T> implements Serializable {
|
||||
}
|
||||
|
||||
private boolean isEmptyString(String s) {
|
||||
return s == null || s.length() == 0;
|
||||
return s == null || s.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.concurrent.Future;
|
||||
* <p>
|
||||
* The benefit of using PagedList over just using the normal Query with
|
||||
* {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} is that it additionally wraps
|
||||
* functionality that can call {@link Query#findFutureRowCount()} to determine total row count,
|
||||
* functionality that can call {@link Query#findFutureCount()} to determine total row count,
|
||||
* total page count etc.
|
||||
* </p>
|
||||
* <p>
|
||||
@@ -44,30 +44,6 @@ import java.util.concurrent.Future;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h4>Example: typical use including total row count</h4>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // We want to find the first 100 new orders
|
||||
* // ... 0 means first page
|
||||
* // ... page size is 100
|
||||
*
|
||||
* PagedList<Order> pagedList
|
||||
* = ebeanServer.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .findPagedList(0, 100);
|
||||
*
|
||||
* // Optional: initiate the loading of the total
|
||||
* // row count in a background thread
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // get the total row count (from the future)
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h4>Example: No total row count required</h4>
|
||||
* <pre>{@code
|
||||
@@ -84,7 +60,7 @@ import java.util.concurrent.Future;
|
||||
* @param <T>
|
||||
* the entity bean type
|
||||
*
|
||||
* @see Query#findPagedList(int, int)
|
||||
* @see Query#findPagedList()
|
||||
*/
|
||||
public interface PagedList<T> {
|
||||
|
||||
@@ -110,7 +86,7 @@ public interface PagedList<T> {
|
||||
* wrapped in the unchecked PersistenceException (which might be preferrable).
|
||||
* </p>
|
||||
*/
|
||||
void loadRowCount();
|
||||
void loadCount();
|
||||
|
||||
/**
|
||||
* Return the Future row count. You might get this if you wish to cancel the total row count query
|
||||
@@ -138,7 +114,7 @@ public interface PagedList<T> {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Future<Integer> getFutureRowCount();
|
||||
Future<Integer> getFutureCount();
|
||||
|
||||
/**
|
||||
* Return the list of entities for this page.
|
||||
@@ -170,7 +146,7 @@ public interface PagedList<T> {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
int getTotalRowCount();
|
||||
int getTotalCount();
|
||||
|
||||
/**
|
||||
* Return the total number of pages based on the page size and total row count.
|
||||
@@ -181,20 +157,19 @@ public interface PagedList<T> {
|
||||
*/
|
||||
int getTotalPageCount();
|
||||
|
||||
/**
|
||||
* Return the index position of this page. Zero based.
|
||||
* <p>
|
||||
* Note that if firstRows/maxRows is used rather than pageIndex/pageSize then
|
||||
* this always returns 0.
|
||||
* </p>
|
||||
*/
|
||||
int getPageIndex();
|
||||
|
||||
/**
|
||||
* Return the page size used for this query. This is the same value as maxRows used by the query.
|
||||
*/
|
||||
int getPageSize();
|
||||
|
||||
/**
|
||||
* Return the index position of this page (Zero based).
|
||||
* <p>
|
||||
* This is a calculated value based on firstRow/maxRows.
|
||||
* </p>
|
||||
*/
|
||||
int getPageIndex();
|
||||
|
||||
/**
|
||||
* Return true if there is a next page.
|
||||
* <p>
|
||||
|
||||
@@ -7,6 +7,8 @@ import javax.persistence.PersistenceException;
|
||||
*/
|
||||
public class PersistenceIOException extends PersistenceException {
|
||||
|
||||
private static final long serialVersionUID = -7630050437148176148L;
|
||||
|
||||
public PersistenceIOException(String msg, Exception cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
@@ -78,6 +78,6 @@ class PrimaryServer {
|
||||
* Return true if the string is null or empty.
|
||||
*/
|
||||
private static boolean isEmpty(String value) {
|
||||
return value == null || value.trim().length() == 0;
|
||||
return value == null || value.trim().isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,28 +10,35 @@ import java.util.Iterator;
|
||||
* 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
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* 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 associated resources
|
||||
* it.close();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -53,37 +53,37 @@ import com.avaje.ebean.util.CamelCaseHelper;
|
||||
* </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")
|
||||
@@ -93,35 +93,35 @@ import com.avaje.ebean.util.CamelCaseHelper;
|
||||
* // 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())
|
||||
@@ -131,7 +131,7 @@ import com.avaje.ebean.util.CamelCaseHelper;
|
||||
* .order().desc("totalAmount")
|
||||
* .setMaxRows(10)
|
||||
* .findList();
|
||||
*
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
@@ -167,14 +167,14 @@ import com.avaje.ebean.util.CamelCaseHelper;
|
||||
* <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;
|
||||
@@ -192,7 +192,7 @@ public final class RawSql implements Serializable {
|
||||
this.sql = null;
|
||||
this.columnMapping = new ColumnMapping(propertyNames);
|
||||
}
|
||||
|
||||
|
||||
protected RawSql(ResultSet resultSet, Sql sql, ColumnMapping columnMapping) {
|
||||
this.resultSet = resultSet;
|
||||
this.sql = sql;
|
||||
@@ -214,7 +214,7 @@ public final class RawSql implements Serializable {
|
||||
String unParsedSql = (sql == null) ? "" : sql.unparsedSql;
|
||||
return new Key(parsed, unParsedSql, columnMapping);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the resultSet if this is a ResultSet based RawSql.
|
||||
*/
|
||||
@@ -386,7 +386,7 @@ public final class RawSql implements Serializable {
|
||||
private final LinkedHashMap<String, Column> dbColumnMap;
|
||||
|
||||
private final Map<String, String> propertyMap;
|
||||
|
||||
|
||||
private final Map<String, Column> propertyColumnMap;
|
||||
|
||||
private final boolean parsed;
|
||||
@@ -401,10 +401,9 @@ public final class RawSql implements Serializable {
|
||||
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.getDbColumn(), c);
|
||||
this.dbColumnMap = new LinkedHashMap<>();
|
||||
for (Column c : columns) {
|
||||
dbColumnMap.put(c.getDbColumnKey(), c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,9 +415,9 @@ public final class RawSql implements Serializable {
|
||||
this.parsed = false;
|
||||
this.propertyMap = null;
|
||||
this.propertyColumnMap = null;
|
||||
this.dbColumnMap = new LinkedHashMap<String, Column>();
|
||||
this.dbColumnMap = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct for ResultSet use.
|
||||
*/
|
||||
@@ -426,7 +425,7 @@ public final class RawSql implements Serializable {
|
||||
this.immutable = false;
|
||||
this.parsed = false;
|
||||
this.propertyMap = null;
|
||||
this.dbColumnMap = new LinkedHashMap<String, Column>();
|
||||
this.dbColumnMap = new LinkedHashMap<>();
|
||||
|
||||
int pos = 0;
|
||||
for (String prop : propertyNames) {
|
||||
@@ -443,8 +442,8 @@ public final class RawSql implements Serializable {
|
||||
this.parsed = parsed;
|
||||
this.dbColumnMap = dbColumnMap;
|
||||
|
||||
HashMap<String, Column> pcMap = new HashMap<String, Column>();
|
||||
HashMap<String, String> pMap = new HashMap<String, String>();
|
||||
HashMap<String, Column> pcMap = new HashMap<>();
|
||||
HashMap<String, String> pMap = new HashMap<>();
|
||||
|
||||
for (Column c : dbColumnMap.values()) {
|
||||
pMap.put(c.getPropertyName(), c.getDbColumn());
|
||||
@@ -476,7 +475,7 @@ public final class RawSql implements Serializable {
|
||||
|
||||
/**
|
||||
* Creates an immutable copy of this ColumnMapping.
|
||||
*
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* when a propertyName has not been defined for a column.
|
||||
*/
|
||||
@@ -500,8 +499,7 @@ public final class RawSql implements Serializable {
|
||||
} else {
|
||||
Column column = dbColumnMap.get(dbColumn);
|
||||
if (column == null) {
|
||||
String msg = "DB Column [" + dbColumn + "] not found in mapping. Expecting one of ["
|
||||
+ dbColumnMap.keySet() + "]";
|
||||
String msg = "DB Column [" + dbColumn + "] not found in mapping. Expecting one of [" + dbColumnMap.keySet() + "]";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
column.setPropertyName(propertyName);
|
||||
@@ -607,9 +605,9 @@ public final class RawSql implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
private static String derivePropertyName(String dbAlias, String dbColumn) {
|
||||
protected static String derivePropertyName(String dbAlias, String dbColumn) {
|
||||
if (dbAlias != null) {
|
||||
return dbAlias;
|
||||
return CamelCaseHelper.toCamelFromUnderscore(dbAlias);
|
||||
}
|
||||
int dotPos = dbColumn.indexOf('.');
|
||||
if (dotPos > -1) {
|
||||
@@ -657,6 +655,14 @@ public final class RawSql implements Serializable {
|
||||
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).
|
||||
*/
|
||||
@@ -664,13 +670,6 @@ public final class RawSql implements Serializable {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB column alias (if it has one).
|
||||
*/
|
||||
public String getDbAlias() {
|
||||
return dbAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean property this column is mapped to.
|
||||
*/
|
||||
|
||||
@@ -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,47 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* The SqlFutureList represents the result of a background SQL query execution.
|
||||
*
|
||||
* <p>
|
||||
* It extends the java.util.concurrent.Future.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // create a query
|
||||
* String sql = ... ;
|
||||
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
|
||||
*
|
||||
* // execute the query in a background thread
|
||||
* SqlFutureList sqlFuture = sqlQuery.findFutureList();
|
||||
*
|
||||
* // do something else ... we will sleep
|
||||
* Thread.sleep(3000);
|
||||
* System.out.println("end of sleep");
|
||||
*
|
||||
* if (!futureList.isDone()){
|
||||
* // we can cancel the query execution
|
||||
* futureList.cancel(true);
|
||||
* }
|
||||
*
|
||||
* System.out.println("and... done:"+futureList.isDone());
|
||||
*
|
||||
* if (!futureList.isCancelled()){
|
||||
* // wait for the query to finish and return the list
|
||||
* List<SqlRow> list = futureList.get();
|
||||
* System.out.println("list:"+list);
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author rob
|
||||
*
|
||||
*/
|
||||
public interface SqlFutureList extends Future<List<SqlRow>> {
|
||||
|
||||
SqlQuery getQuery();
|
||||
|
||||
}
|
||||
@@ -2,8 +2,6 @@ package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Query object for performing native SQL queries that return SqlRow's.
|
||||
@@ -21,45 +19,48 @@ import java.util.Set;
|
||||
* conversion support added.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // its typically a good idea to use a named query
|
||||
* // and put the sql in the orm.xml instead of in your code
|
||||
* <pre>{@code
|
||||
*
|
||||
* // its typically a good idea to use a named query
|
||||
* // and put the sql in the orm.xml instead of in your code
|
||||
*
|
||||
* String sql = "select id, name from customer where name like :name and status_code = :status";
|
||||
* String sql = "select id, name from customer where name like :name and status_code = :status";
|
||||
*
|
||||
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
|
||||
* sqlQuery.setParameter("name", "Acme%");
|
||||
* sqlQuery.setParameter("status", "ACTIVE");
|
||||
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
|
||||
* sqlQuery.setParameter("name", "Acme%");
|
||||
* sqlQuery.setParameter("status", "ACTIVE");
|
||||
*
|
||||
* // execute the query returning a List of MapBean objects
|
||||
* List<SqlRow> list = sqlQuery.findList();
|
||||
* </pre>
|
||||
* // execute the query returning a List of MapBean objects
|
||||
* List<SqlRow> list = sqlQuery.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
public interface SqlQuery extends Serializable {
|
||||
|
||||
/**
|
||||
* Cancel the query if support by the underlying database and driver.
|
||||
* <p>
|
||||
* This must be called from a different thread to the one executing the query.
|
||||
* </p>
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* Execute the query returning a list.
|
||||
*/
|
||||
List<SqlRow> findList();
|
||||
|
||||
/**
|
||||
* Execute the query returning a set.
|
||||
* Execute the SqlQuery iterating a row at a time.
|
||||
* <p>
|
||||
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
|
||||
* </p>
|
||||
*/
|
||||
Set<SqlRow> findSet();
|
||||
void findEach(QueryEachConsumer<SqlRow> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query returning a map.
|
||||
* Execute the SqlQuery iterating a row at a time with the ability to stop consuming part way through.
|
||||
* <p>
|
||||
* Returning false after processing a row stops the iteration through the query results.
|
||||
* </p>
|
||||
* <p>
|
||||
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
|
||||
* </p>
|
||||
*/
|
||||
Map<?, SqlRow> findMap();
|
||||
void findEachWhile(QueryEachWhileConsumer<SqlRow> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query returning a single row or null.
|
||||
@@ -70,19 +71,6 @@ public interface SqlQuery extends Serializable {
|
||||
*/
|
||||
SqlRow findUnique();
|
||||
|
||||
/**
|
||||
* Execute find list SQL query in a background thread.
|
||||
* <p>
|
||||
* This returns a Future object which can be used to cancel, check the
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
* @return a Future object for the list result of the query
|
||||
* @deprecated
|
||||
*/
|
||||
SqlFutureList findFutureList();
|
||||
|
||||
/**
|
||||
* The same as bind for named parameters.
|
||||
*/
|
||||
@@ -93,19 +81,6 @@ public interface SqlQuery extends Serializable {
|
||||
*/
|
||||
SqlQuery setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set a listener to process the query on a row by row basis.
|
||||
* <p>
|
||||
* It this case the rows are not loaded into the persistence context and
|
||||
* instead can be processed by the query listener.
|
||||
* </p>
|
||||
* <p>
|
||||
* Use this when you want to process a large query and do not want to hold the
|
||||
* entire query result in memory.
|
||||
* </p>
|
||||
*/
|
||||
SqlQuery setListener(SqlQueryListener queryListener);
|
||||
|
||||
/**
|
||||
* Set the index of the first row of the results to return.
|
||||
*/
|
||||
@@ -116,16 +91,6 @@ public interface SqlQuery extends Serializable {
|
||||
*/
|
||||
SqlQuery setMaxRows(int maxRows);
|
||||
|
||||
/**
|
||||
* Set the index after which fetching continues in a background thread.
|
||||
*/
|
||||
SqlQuery setBackgroundFetchAfter(int backgroundFetchAfter);
|
||||
|
||||
/**
|
||||
* Set the column to use to determine the keys for a Map.
|
||||
*/
|
||||
SqlQuery setMapKey(String mapKey);
|
||||
|
||||
/**
|
||||
* Set a timeout on this query.
|
||||
* <p>
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Provides a mechanism for processing a SqlQuery one SqlRow at a time.
|
||||
* <p>
|
||||
* This is useful when the query will return a large number of results and you
|
||||
* want to process the beans one at a time rather than have all of the beans in
|
||||
* memory at once.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* SqlQueryListener listener = ...;
|
||||
*
|
||||
* SqlQuery query = Ebean.createSqlQuery("my.large.query");
|
||||
*
|
||||
* // set the listener that will process each row one at a time
|
||||
* query.setListener(listener);
|
||||
*
|
||||
* // execute the query. Note that the returned
|
||||
* // list will be empty ... so don't bother assigning it...
|
||||
* query.findList();
|
||||
* </pre>
|
||||
*/
|
||||
public interface SqlQueryListener {
|
||||
|
||||
/**
|
||||
* Process the bean that has just been read.
|
||||
* <p>
|
||||
* Note this bean will not be added to the List Set or Map.
|
||||
* </p>
|
||||
*/
|
||||
void process(SqlRow bean);
|
||||
}
|
||||
@@ -26,7 +26,7 @@ package com.avaje.ebean;
|
||||
*
|
||||
* int modifiedCount = Ebean.execute(update);
|
||||
*
|
||||
* String msg = "There where " + modifiedCount + "rows updated"
|
||||
* String msg = "There were " + modifiedCount + " rows updated"
|
||||
* </pre>
|
||||
*
|
||||
* @see Update
|
||||
@@ -117,8 +117,7 @@ public interface SqlUpdate {
|
||||
SqlUpdate setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set a null parameter via its index position. Exactly the same as
|
||||
* {@link #setNull(int, int)}.
|
||||
* Set a null parameter via its index position.
|
||||
*/
|
||||
SqlUpdate setNull(int position, int jdbcType);
|
||||
|
||||
@@ -143,4 +142,4 @@ public interface SqlUpdate {
|
||||
*/
|
||||
SqlUpdate setNullParameter(String name, int jdbcType);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.ebean;
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
import com.avaje.ebean.config.DocStoreConfig;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.RollbackException;
|
||||
@@ -53,13 +54,52 @@ public interface Transaction extends Closeable {
|
||||
*/
|
||||
void setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Commits the transaction at this point with the expectation that another
|
||||
* commit (or rollback or end) will occur later to complete the transaction.
|
||||
* <p>
|
||||
* This is similar to commit() but leaves the transaction "Active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <ul>
|
||||
* <li>Flush the JDBC batch buffer</li>
|
||||
* <li>Call commit on the underlying JDBC connection</li>
|
||||
* <li>Trigger any registered TransactionCallbacks</li>
|
||||
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
|
||||
* </ul>
|
||||
*/
|
||||
void commitAndContinue() throws RollbackException;
|
||||
|
||||
/**
|
||||
* Commit the transaction.
|
||||
* <p>
|
||||
* This performs commit and completes the transaction closing underlying resources and
|
||||
* marking the transaction as "In active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <ul>
|
||||
* <li>Flush the JDBC batch buffer</li>
|
||||
* <li>Call commit on the underlying JDBC connection</li>
|
||||
* <li>Trigger any registered TransactionCallbacks</li>
|
||||
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
|
||||
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
|
||||
* <li>Mark the transaction as "Inactive"</li>
|
||||
* </ul>
|
||||
*/
|
||||
void commit() throws RollbackException;
|
||||
|
||||
/**
|
||||
* Rollback the transaction.
|
||||
* <p>
|
||||
* This performs rollback, closes underlying resources and marks the transaction as "In active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <ul>
|
||||
* <li>Call rollback on the underlying JDBC connection</li>
|
||||
* <li>Trigger any registered TransactionCallbacks</li>
|
||||
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
|
||||
* <li>Mark the transaction as "Inactive"</li>
|
||||
* </ul>
|
||||
*/
|
||||
void rollback() throws PersistenceException;
|
||||
|
||||
@@ -73,6 +113,16 @@ public interface Transaction extends Closeable {
|
||||
*/
|
||||
void rollback(Throwable e) throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Mark the transaction for rollback only.
|
||||
*/
|
||||
void setRollbackOnly();
|
||||
|
||||
/**
|
||||
* Return true if the transaction is marked as rollback only.
|
||||
*/
|
||||
boolean isRollbackOnly();
|
||||
|
||||
/**
|
||||
* If the transaction is active then perform rollback. Otherwise do nothing.
|
||||
*/
|
||||
@@ -125,13 +175,78 @@ public interface Transaction extends Closeable {
|
||||
* Set to true when you want all loaded properties to be included in the update
|
||||
* (rather than just the changed properties).
|
||||
* <p>
|
||||
* You might set this when using JDBC batch in order to get multiple updates
|
||||
* with slightly different sets of changed properties into the same statement
|
||||
* and hence better JDBC batch performance.
|
||||
* You might set this when using JDBC batch in order to get multiple updates
|
||||
* with slightly different sets of changed properties into the same statement
|
||||
* and hence better JDBC batch performance.
|
||||
* </p>
|
||||
*/
|
||||
void setUpdateAllLoadedProperties(boolean updateAllLoadedProperties);
|
||||
|
||||
/**
|
||||
* Set if the L2 cache should be skipped for "find by id" and "find by natural key" queries.
|
||||
* <p>
|
||||
* By default {@link ServerConfig#isSkipCacheAfterWrite()} is true and that means that for
|
||||
* "find by id" and "find by natural key" queries which normally hit L2 bean cache automatically
|
||||
* - will not do so after a persist/write on the transaction.
|
||||
* </p>
|
||||
* <p>
|
||||
* This method provides explicit control over whether "find by id" and "find by natural key"
|
||||
* will skip the L2 bean cache or not (regardless of whether the transaction is considered "read only").
|
||||
* </p>
|
||||
* <p>
|
||||
* Refer to {@link ServerConfig#setSkipCacheAfterWrite(boolean)} for configuring the default behavior
|
||||
* for using the L2 bean cache in transactions spanning multiple query/persist requests.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // assume Customer has L2 bean caching enabled ...
|
||||
*
|
||||
* Transaction transaction = Ebean.beginTransaction();
|
||||
* try {
|
||||
*
|
||||
* // this uses L2 bean cache as the transaction
|
||||
* // ... is considered "query only" at this point
|
||||
* Customer.find.byId(42);
|
||||
*
|
||||
* // transaction no longer "query only" once
|
||||
* // ... a bean has been saved etc
|
||||
* Ebean.save(someBean);
|
||||
*
|
||||
* // will NOT use L2 bean cache as the transaction
|
||||
* // ... is no longer considered "query only"
|
||||
* Customer.find.byId(55);
|
||||
*
|
||||
*
|
||||
*
|
||||
* // explicit control - please use L2 bean cache
|
||||
*
|
||||
* transaction.setSkipCache(false);
|
||||
* Customer.find.byId(77); // hit the l2 bean cache
|
||||
*
|
||||
*
|
||||
* // explicit control - please don't use L2 bean cache
|
||||
*
|
||||
* transaction.setSkipCache(true);
|
||||
* Customer.find.byId(99); // skips l2 bean cache
|
||||
*
|
||||
*
|
||||
* } finally {
|
||||
* transaction.end();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see ServerConfig#isSkipCacheAfterWrite()
|
||||
*/
|
||||
void setSkipCache(boolean skipCache);
|
||||
|
||||
/**
|
||||
* Return true if the L2 cache should be skipped. More accurately if true then find by id
|
||||
* and find by natural key queries should NOT automatically use the L2 bean cache.
|
||||
*/
|
||||
boolean isSkipCache();
|
||||
|
||||
/**
|
||||
* Turn on or off statement batching. Statement batching can be transparent
|
||||
* for drivers and databases that support getGeneratedKeys. Otherwise you may
|
||||
@@ -351,9 +466,8 @@ public interface Transaction extends Closeable {
|
||||
|
||||
/**
|
||||
* Add an arbitrary user object to the transaction. The objects added have no
|
||||
* impact on any internals of ebena and are solely meant as a convenient
|
||||
* method push user information to e.g. the
|
||||
* {@link com.avaje.ebean.event.TransactionEventListener}.
|
||||
* impact on any internals of ebean and are solely meant as a convenient
|
||||
* method push user information (although somewhat replaced by TransactionCallback).
|
||||
*/
|
||||
void putUserObject(String name, Object value);
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import java.util.ArrayList;
|
||||
* This object is used internally with the enhancement of a method with
|
||||
* Transactional annotation.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @see TxCallable
|
||||
* @see TxRunnable
|
||||
* @see Ebean#execute(TxScope, TxCallable)
|
||||
@@ -36,33 +36,14 @@ public final class TxScope {
|
||||
|
||||
int batchSize;
|
||||
|
||||
boolean skipGeneratedKeys;
|
||||
|
||||
boolean readOnly;
|
||||
|
||||
ArrayList<Class<? extends Throwable>> rollbackFor;
|
||||
|
||||
ArrayList<Class<? extends Throwable>> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with REQUIRES.
|
||||
*/
|
||||
@@ -128,6 +109,44 @@ public final class TxScope {
|
||||
+ "] 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.
|
||||
*/
|
||||
@@ -188,6 +207,21 @@ public final class TxScope {
|
||||
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.
|
||||
*/
|
||||
@@ -248,7 +282,7 @@ public final class TxScope {
|
||||
*/
|
||||
public TxScope setRollbackFor(Class<? extends Throwable> rollbackThrowable) {
|
||||
if (rollbackFor == null) {
|
||||
rollbackFor = new ArrayList<Class<? extends Throwable>>(2);
|
||||
rollbackFor = new ArrayList<>(2);
|
||||
}
|
||||
rollbackFor.add(rollbackThrowable);
|
||||
return this;
|
||||
@@ -260,10 +294,10 @@ public final class TxScope {
|
||||
@SuppressWarnings("unchecked")
|
||||
public TxScope setRollbackFor(Class<?>[] rollbackThrowables) {
|
||||
if (rollbackFor == null) {
|
||||
rollbackFor = new ArrayList<Class<? extends Throwable>>(rollbackThrowables.length);
|
||||
rollbackFor = new ArrayList<>(rollbackThrowables.length);
|
||||
}
|
||||
for (int i = 0; i < rollbackThrowables.length; i++) {
|
||||
rollbackFor.add((Class<? extends Throwable>) rollbackThrowables[i]);
|
||||
for (Class<?> rollbackThrowable : rollbackThrowables) {
|
||||
rollbackFor.add((Class<? extends Throwable>) rollbackThrowable);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -282,7 +316,7 @@ public final class TxScope {
|
||||
*/
|
||||
public TxScope setNoRollbackFor(Class<? extends Throwable> noRollback) {
|
||||
if (noRollbackFor == null) {
|
||||
noRollbackFor = new ArrayList<Class<? extends Throwable>>(2);
|
||||
noRollbackFor = new ArrayList<>(2);
|
||||
}
|
||||
this.noRollbackFor.add(noRollback);
|
||||
return this;
|
||||
@@ -294,10 +328,10 @@ public final class TxScope {
|
||||
@SuppressWarnings("unchecked")
|
||||
public TxScope setNoRollbackFor(Class<?>[] noRollbacks) {
|
||||
if (noRollbackFor == null) {
|
||||
noRollbackFor = new ArrayList<Class<? extends Throwable>>(noRollbacks.length);
|
||||
noRollbackFor = new ArrayList<>(noRollbacks.length);
|
||||
}
|
||||
for (int i = 0; i < noRollbacks.length; i++) {
|
||||
noRollbackFor.add((Class<? extends Throwable>) noRollbacks[i]);
|
||||
for (Class<?> noRollback : noRollbacks) {
|
||||
noRollbackFor.add((Class<? extends Throwable>) noRollback);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* An update query typically intended to perform a bulk update of many rows that match the query.
|
||||
* <p>
|
||||
* Also note that you can also just use a raw SQL update via {@link SqlUpdate} which is pretty light and simple.
|
||||
* This UpdateQuery is more for the cases where we want to build the where expression of the update using the
|
||||
* {@link ExpressionList} "Criteria API" that is used with a normal ORM query.
|
||||
* </p>
|
||||
*
|
||||
* <h4>Example: Simple update</h4>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
* <pre>{@code sql
|
||||
*
|
||||
* update o_customer set status=?, updtime=? where id > ?
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Note that if the where() clause contains a join then the SQL update changes to use a
|
||||
* <code> WHERE ID IN () </code> form.
|
||||
* </p>
|
||||
*
|
||||
* <h4>Example: Update with a JOIN</h4>
|
||||
* <p>
|
||||
* In this example the expression <code>.eq("billingAddress.country", nz)</code> requires a join
|
||||
* to the address table.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
* .eq("status", Customer.Status.NEW)
|
||||
* .eq("billingAddress.country", nz)
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
* }</pre>
|
||||
*
|
||||
* <pre>{@code sql
|
||||
*
|
||||
* update o_customer set status=?, updtime=?
|
||||
* where id in (
|
||||
* select t0.id c0
|
||||
* from o_customer t0
|
||||
* left join o_address t1 on t1.id = t0.billing_address_id
|
||||
* where t0.status = ?
|
||||
* and t1.country_code = ?
|
||||
* and t0.id > ? )
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T> The type of entity bean being updated
|
||||
*
|
||||
* @see SqlUpdate
|
||||
*/
|
||||
public interface UpdateQuery<T> {
|
||||
|
||||
/**
|
||||
* Set the value of a property.
|
||||
*
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param property The bean property to be set
|
||||
* @param value The value to set the property to
|
||||
*/
|
||||
UpdateQuery<T> set(String property, Object value);
|
||||
|
||||
/**
|
||||
* Set the property to be null.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .setNull("notes")
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param property The property to be set to null.
|
||||
*/
|
||||
UpdateQuery<T> setNull(String property);
|
||||
|
||||
/**
|
||||
*
|
||||
* Set using a property expression that does not need any bind values.
|
||||
* <p>
|
||||
* The property expression typically contains database functions.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .setRaw("status = coalesce(status, 'A')")
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyExpression A property expression
|
||||
*/
|
||||
UpdateQuery<T> setRaw(String propertyExpression);
|
||||
|
||||
/**
|
||||
* Set using a property expression that can contain <code>?</code> bind value placeholders.
|
||||
* <p>
|
||||
* For each <code>?</code> in the property expression there should be a matching bind value supplied.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .setRaw("status = coalesce(status, ?)", Customer.Status.ACTIVE)
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyExpression A raw property expression
|
||||
* @param values The values to bind with the property expression
|
||||
*/
|
||||
UpdateQuery<T> setRaw(String propertyExpression, Object... values);
|
||||
|
||||
/**
|
||||
* Return the query expression list to add predicates to.
|
||||
*/
|
||||
ExpressionList<T> where();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
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 to be an aggregation formula.
|
||||
* <p>
|
||||
* The aggregation formula should be a sum, count, avg, min or max.
|
||||
* By default aggregation properties are treated as transient and not
|
||||
* included in a query. To populate the aggregation property it must be
|
||||
* explicitly included in the select().
|
||||
* </p>
|
||||
*
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Aggregation("count(details)")
|
||||
* Long totalCount;
|
||||
*
|
||||
* @Aggregation("sum(details.quantity*details.unitPrice)")
|
||||
* Long totalAmount;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Example query</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<TEventOne> list = Ebean.find(TEventOne.class)
|
||||
* .select("name, totalCount, totalUnits, totalAmount")
|
||||
* .where()
|
||||
* .startsWith("logs.description", "a")
|
||||
* .having()
|
||||
* .ge("count", 1)
|
||||
* .orderBy().asc("name")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Aggregation {
|
||||
|
||||
/**
|
||||
* Aggregation formula using sum, count, avg, min, max.
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
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;
|
||||
}
|
||||
+2
-2
@@ -6,14 +6,14 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify cache tuning for a specific entity type.
|
||||
* 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 CacheTuning {
|
||||
public @interface CacheQueryTuning {
|
||||
|
||||
/**
|
||||
* The maximum size for the cache.
|
||||
@@ -1,58 +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;
|
||||
|
||||
/**
|
||||
* Specify the default cache use specific entity type.
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CacheStrategy {
|
||||
|
||||
/**
|
||||
* When set to true the bean cache will be used unless explicitly stated not
|
||||
* to in a query via {@link Query#setUseCache(boolean)}.
|
||||
*/
|
||||
boolean useBeanCache() default true;
|
||||
|
||||
/**
|
||||
* A single 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;
|
||||
|
||||
/**
|
||||
* Specify a query that can be used to warm the cache.
|
||||
* <p>
|
||||
* All the beans fetched by this query will be loaded into the bean cache and
|
||||
* the query itself will be loaded into the query cache.
|
||||
* </p>
|
||||
* <p>
|
||||
* The warming query will typically be executed at startup time after a short
|
||||
* delay (defaults to a 30 seconds delay).
|
||||
* </p>
|
||||
*/
|
||||
String warmingQuery() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
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;
|
||||
}
|
||||
@@ -23,4 +23,8 @@ import java.lang.annotation.Target;
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DbHstore {
|
||||
|
||||
/**
|
||||
* For VARCHAR storage specify the column length (defaults to 1000).
|
||||
*/
|
||||
int length() default 0;
|
||||
}
|
||||
@@ -36,4 +36,8 @@ import java.lang.annotation.Target;
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DbJsonB {
|
||||
|
||||
/**
|
||||
* For VARCHAR storage specify the column length.
|
||||
*/
|
||||
int length() default 0;
|
||||
}
|
||||
@@ -1,21 +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;
|
||||
|
||||
/**
|
||||
* Deprecated in favor of @DocEmbedded (i.e. renamed to @DocEmbedded)
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Deprecated
|
||||
public @interface DocStoreEmbedded {
|
||||
|
||||
/**
|
||||
* The properties on the embedded bean to include in the index.
|
||||
*/
|
||||
String doc() 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;
|
||||
|
||||
/**
|
||||
* Specify explicit ConcurrencyMode for entity bean.
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EntityConcurrencyMode {
|
||||
|
||||
/**
|
||||
* The ConcurrencyMode value.
|
||||
*/
|
||||
ConcurrencyMode value();
|
||||
}
|
||||
@@ -1,90 +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 mapping the values of an Enum to and from Database values.
|
||||
* <p>
|
||||
* Also refer to the {@link EnumValue} approach which probably the preferred now
|
||||
* (preferred over using this EnumMapping annotation).
|
||||
* </p>
|
||||
* <p>
|
||||
* Both of the approaches defined in the JPA have significant problems!!!
|
||||
* </p>
|
||||
* <p>
|
||||
* Using the ordinal value is VERY RISKY because that depends on the compile
|
||||
* order of the enum values. Aka if you change the order of the enum values you
|
||||
* have changed their ordinal values and now your DB values are WRONG - a HUGE
|
||||
* disaster!!!.
|
||||
* </p>
|
||||
* <p>
|
||||
* Using the String values of enums is fairly restrictive because in a Database
|
||||
* these values are usually truncated into short codes (e.g. "A" short for
|
||||
* "ACTIVE") so space used in the database is minimised. Making your enum names
|
||||
* match the database values would give them very short less meaningful names -
|
||||
* not a great solution.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can use this annotation to control the mapping of your enums to database
|
||||
* values.
|
||||
* </p>
|
||||
* <p>
|
||||
* The design of this using nameValuePairs is not optimal for safety or
|
||||
* refactoring so if you have a better solution I'm all ears. The other
|
||||
* solutions would probably involve modifying each enumeration with a method
|
||||
* which may be ok.
|
||||
* </p>
|
||||
* <p>
|
||||
* An example mapping the UserState enum.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* ...
|
||||
* @EnumMapping(nameValuePairs="NEW=N, ACTIVE=A, INACTIVE=I")
|
||||
* public enum UserState {
|
||||
* NEW,
|
||||
* ACTIVE,
|
||||
* INACTIVE;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see EnumValue
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EnumMapping {
|
||||
|
||||
/**
|
||||
* A comma delimited list of name=value pairs.
|
||||
* <p>
|
||||
* e.g. "ACTIVE=A, INACTIVE=I, NEW=N".
|
||||
* </p>
|
||||
* <p>
|
||||
* Where ACTIVE, INACTIVE and NEW are the enumeration values and "A", "I" and
|
||||
* "N" are the database values.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is not really an optimal approach so if you have a better one I'm all
|
||||
* ears - thanks.
|
||||
* </p>
|
||||
*/
|
||||
String nameValuePairs();
|
||||
|
||||
/**
|
||||
* Defaults to mapping values to database VARCHAR type. If this is set to true
|
||||
* then the values will be converted to INTEGER and mapped to the database
|
||||
* integer type.
|
||||
* <p>
|
||||
* e.g. "ACTIVE=1, INACTIVE=0, NEW=2".
|
||||
* </p>
|
||||
*/
|
||||
boolean integerType() default false;
|
||||
|
||||
/**
|
||||
* The length of DB column if mapping to string values.
|
||||
*/
|
||||
int length() default 0;
|
||||
}
|
||||
@@ -82,7 +82,7 @@ public @interface Formula {
|
||||
* as count, sum etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* The join string should start with either "left outer join" or "join".
|
||||
* The join string should start with either "left join" or "join".
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
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 on a single column.
|
||||
* An annotation for declaring an index.
|
||||
*
|
||||
* @author rvbiljouw
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(Indices.class)
|
||||
public @interface Index {
|
||||
|
||||
/**
|
||||
@@ -27,6 +29,9 @@ public @interface Index {
|
||||
/**
|
||||
* 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 {};
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
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,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;
|
||||
|
||||
/**
|
||||
* An Update statement for a particular entity bean type.
|
||||
* <p>
|
||||
* The update can either be a sql insert,update or delete statement with tables
|
||||
* and columns etc or the equivalent statement but with table names and columns
|
||||
* expressed as bean types and bean properties.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NamedUpdate {
|
||||
|
||||
/**
|
||||
* The name of the update.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* The insert, update or delete statement.
|
||||
*/
|
||||
String update();
|
||||
|
||||
/**
|
||||
* Set this to false if you do not want the cache to be notified. If true the
|
||||
* cache will invalidate appropriate objects from the cache (after a
|
||||
* successful transaction commit).
|
||||
*/
|
||||
boolean notifyCache() 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;
|
||||
|
||||
/**
|
||||
* Holds an array of named Update statements for a particular entity bean type.
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NamedUpdates {
|
||||
|
||||
/**
|
||||
* An array of named updates.
|
||||
*/
|
||||
NamedUpdate[] value();
|
||||
|
||||
}
|
||||
@@ -6,19 +6,13 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify explicit sql for multiple select statements. Need to use this if you
|
||||
* have more than one SqlSelect for a given bean.
|
||||
* Mark and entity bean that is used solely via RawSql.
|
||||
* <p>
|
||||
* FUTURE: Support explicit sql for SqlInsert, SqlUpdate and SqlDelete.
|
||||
* This means the entity bean has no base table specified (via @Table).
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Sql {
|
||||
|
||||
/**
|
||||
* The sql select statements.
|
||||
*/
|
||||
SqlSelect[] select() default { @SqlSelect };
|
||||
|
||||
}
|
||||
|
||||
@@ -1,298 +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;
|
||||
|
||||
/**
|
||||
* Specify an explicit sql select statement to use for querying an entity bean.
|
||||
* <p>
|
||||
* The reason for using explicit sql is that you want better control over the
|
||||
* exact sql or sql that Ebean does not generate for you (such as group by,
|
||||
* union, intersection, window functions, recursive queries).
|
||||
* </p>
|
||||
* <p>
|
||||
* An example of two sql select queries deployed on the ReportTopic entity bean.
|
||||
* The first one has no name specified so it becomes the default query. The
|
||||
* second query extends the first adding a where clause with a named parameter.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* ...
|
||||
* @Entity
|
||||
* @Sql(select = {
|
||||
* @SqlSelect(query =
|
||||
* "select t.id, t.title, count(p.id) as score "+
|
||||
* "from f_topic t "+
|
||||
* "join f_topic_post p on p.topic_id = t.id "+
|
||||
* "group by t.id, t.title"),
|
||||
* @SqlSelect(
|
||||
* name = "with.title",
|
||||
* extend = "default",
|
||||
* debug = true,
|
||||
* where = "title like :likeTitle")
|
||||
* })
|
||||
* public class ReportTopic
|
||||
* @Id Integer id;
|
||||
* String title;
|
||||
* Double score;
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* An example using the first "default" query.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* List<ReportTopic> list =
|
||||
* Ebean.find(ReportTopic.class)
|
||||
* .having().gt("score", 0)
|
||||
* .findList();
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* The resulting sql, note the having clause has been added.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* select t.id, t.title, count(p.id) as score
|
||||
* from f_topic t join f_topic_post p on p.topic_id = t.id
|
||||
* group by t.id, t.title
|
||||
* having count(p.id) > ?
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* An example using the second query. Note the named parameter "likeTitle" must
|
||||
* be set.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* List<ReportTopic> list =
|
||||
* Ebean.find(ReportTopic.class, "with.title")
|
||||
* .set("likeTitle", "a%")
|
||||
* .findList();
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Ebean tries to parse the sql in the query to determine 4 things
|
||||
* <li>Location for inserting WHERE expressions (if required)</li>
|
||||
* <li>Location for inserting HAVING expressions (if required)</li>
|
||||
* <li>Mapping of columns to bean properties</li>
|
||||
* <li>The order by clause</li>
|
||||
* </p>
|
||||
* <p>
|
||||
* If Ebean is unable to parse out this information (perhaps because the sql
|
||||
* contains multiple select from keywords etc) then you need to manually specify
|
||||
* it.
|
||||
* </p>
|
||||
* <p>
|
||||
* Insert ${where} or ${andWhere} into the location where Ebean can insert any
|
||||
* expressions added to the where clause. Use ${andWhere} if the sql already has
|
||||
* the WHERE keyword and Ebean will instead start with a AND keyword.
|
||||
* </p>
|
||||
* <p>
|
||||
* Insert ${having} or ${andHaving} into the location where Ebean can insert any
|
||||
* expressions added to the having clause. Use ${andHaving} if the sql already
|
||||
* has a HAVING keyword and Ebean will instead start with a AND keyword.
|
||||
* </p>
|
||||
* <p>
|
||||
* Use the columnMapping property if Ebean is unable to determine the columns
|
||||
* and map them to bean properties.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example with ${andWhere} & ${having}.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* @SqlSelect(
|
||||
* name = "explicit.where",
|
||||
* query =
|
||||
* "select t.id, t.title, count(p.id) as score "+
|
||||
* "from f_topic t, f_topic_post p "+
|
||||
* "where p.topic_id = t.id ${andWhere} "+
|
||||
* "group by t.id, t.title ${having}"),
|
||||
* </pre>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Deprecated
|
||||
public @interface SqlSelect {
|
||||
|
||||
/**
|
||||
* The name of the query. If left blank this is assumed to be the default
|
||||
* query for this bean type.
|
||||
* <p>
|
||||
* This will default to "default" and in that case becomes the default query
|
||||
* used for the bean.
|
||||
* </p>
|
||||
*/
|
||||
String name() default "default";
|
||||
|
||||
/**
|
||||
* The tableAlias used when adding where expressions to the query.
|
||||
*/
|
||||
String tableAlias() default "";
|
||||
|
||||
/**
|
||||
* The sql select statement.
|
||||
* <p>
|
||||
* If this query <em>extends</em> another then this string is appended to the
|
||||
* parent query string. Often when using <em>extend</em> you will leave the
|
||||
* query part blank and just specify a where and/or having clauses.
|
||||
* </p>
|
||||
* <p>
|
||||
* This sql <em>CAN NOT</em> contain named parameters. You have to put these
|
||||
* in the separate where and/or having sections.
|
||||
* </p>
|
||||
* <p>
|
||||
* Ebean automatically tries to determine the location in the sql string for
|
||||
* putting in additional where or having clauses. If Ebean is unable to
|
||||
* successfully determine this then you have to explicitly specify these
|
||||
* locations by including
|
||||
* <em>${where} or ${andWhere} and ${having} or ${andHaving}</em> in the sql.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>${where}</b> location of where clause (and will add WHERE ... ) <br/>
|
||||
* Use this when there is no where clause in the sql. If expressions are added
|
||||
* to the where clause Ebean will put them in at this location starting with
|
||||
* the WHERE keyword.
|
||||
* <p>
|
||||
* <p>
|
||||
* <b>${andWhere}</b> <br/>
|
||||
* Use this instead of ${where} if there IS an existing where clause in the
|
||||
* sql. Ebean will add the expressions starting with the AND keyword.
|
||||
* <p>
|
||||
* <b>${having}</b> location of having clause (and will add HAVING... ) <br/>
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>${andHaving}</b> <br/>
|
||||
* Use this instead of ${having} when there IS an existing HAVING clause.
|
||||
* Ebean will add the expressions starting with the AND keyword.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can include one of ${where} OR ${andWhere} but not both.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can include one of ${having} OR ${andHaving} but not both.
|
||||
* </p>
|
||||
*/
|
||||
String query() default "";
|
||||
|
||||
/**
|
||||
* Specify the name of a sql-select query that this one 'extends'.
|
||||
* <p>
|
||||
* When a query is extended the sql query contents are appended together. The
|
||||
* where and having clauses are NOT appended but overridden.
|
||||
* </p>
|
||||
*/
|
||||
String extend() default "";
|
||||
|
||||
/**
|
||||
* Specify a where clause typically containing named parameters.
|
||||
* <p>
|
||||
* If a where clause is specified with named parameters then they will need to
|
||||
* be set on the query via {@link Query#setParameter(String, Object)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* In the example below the query specifies a where clause that includes a
|
||||
* named parameter "likeTitle".
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* ...
|
||||
* @Entity
|
||||
* @Sql(select = {
|
||||
* ...
|
||||
* @SqlSelect(
|
||||
* name = "with.title",
|
||||
* extend = "default",
|
||||
* debug = true,
|
||||
* where = "title like :likeTitle")
|
||||
* })
|
||||
* public class ReportTopic
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Example use of the above named query.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<ReportTopic> query0 = Ebean.createQuery(ReportTopic.class, "with.title");
|
||||
*
|
||||
* query0.set("likeTitle", "Bana%");
|
||||
*
|
||||
* List<ReportTopic> list0 = query0.findList();
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
String where() default "";
|
||||
|
||||
/**
|
||||
* Specify a having clause typically containing named parameters.
|
||||
* <p>
|
||||
* If a having clause is specified with named parameters then they will need
|
||||
* to be set on the query via {@link Query#setParameter(String, Object)}.
|
||||
* </p>
|
||||
*/
|
||||
String having() default "";
|
||||
|
||||
/**
|
||||
* (Optional) Explicitly specify column to property mapping.
|
||||
* <p>
|
||||
* This is required when Ebean is unable to parse the sql. This could occur if
|
||||
* the sql contains multiple select keywords etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* Specify the columns and property names they map to in the format.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* column1 propertyName1, column2 propertyName2, ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Optionally put a AS keyword between the column and property.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // the AS keyword is optional
|
||||
* column1 AS propertyName1, column2 propertyName2, ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* <b>column</b> should contain the table alias if there is one
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>propertyName</b> should match the property name.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Example mapping 5 columns to properties.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* columnMapping="t.id, t.bug_body description, t.bug_title as title, count(p.id) as scoreValue",
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Without this set Ebean will parse the sql looking for the select clause and
|
||||
* try to map the columns to property names. It is expected that Ebean will
|
||||
* not be able to successfully parse some sql and for those cases you should
|
||||
* specify the column to property mapping explicitly.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
String columnMapping() default "";
|
||||
|
||||
/**
|
||||
* Set this to true to have debug output when Ebean parses the sql-select.
|
||||
*/
|
||||
boolean debug() default false;
|
||||
}
|
||||
@@ -90,6 +90,16 @@ public @interface Transactional {
|
||||
*/
|
||||
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>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
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 {};
|
||||
}
|
||||
@@ -31,6 +31,11 @@ public interface BeanCollection<E> extends Serializable {
|
||||
ALL
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the disableLazyLoad state.
|
||||
*/
|
||||
void setDisableLazyLoad(boolean disableLazyLoad);
|
||||
|
||||
/**
|
||||
* Load bean from another collection.
|
||||
*/
|
||||
@@ -54,10 +59,12 @@ public interface BeanCollection<E> extends Serializable {
|
||||
void reset(EntityBean ownerBean, String propertyName);
|
||||
|
||||
/**
|
||||
* Return true if the collection is empty and untouched. Used to detect if a
|
||||
* collection was 'cleared' deliberately or just un-initialised.
|
||||
* Return true if the collection is uninitialised or is empty without any held modifications.
|
||||
* <p>
|
||||
* Returning true means can safely skip cascade save for this bean collection.
|
||||
* </p>
|
||||
*/
|
||||
boolean isEmptyAndUntouched();
|
||||
boolean isSkipSave();
|
||||
|
||||
/**
|
||||
* Return the bean that owns this collection.
|
||||
@@ -92,11 +99,6 @@ public interface BeanCollection<E> extends Serializable {
|
||||
*/
|
||||
void setFilterMany(ExpressionList<?> filterMany);
|
||||
|
||||
/**
|
||||
* Set a listener to be notified when the BeanCollection is first touched.
|
||||
*/
|
||||
void setBeanCollectionTouched(BeanCollectionTouched notify);
|
||||
|
||||
/**
|
||||
* Return true if the collection has been registered with the batch loading context.
|
||||
*/
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Used to specify a listener to be notified when a BeanCollection is first
|
||||
* used.
|
||||
* <p>
|
||||
* To use this you can set a BeanCollectionTouched onto a BeanCollection before
|
||||
* it has been used. When the BeanCollection is first used by the client code
|
||||
* then the BeanCollectionTouched is notified. It can only be notified once.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface BeanCollectionTouched {
|
||||
|
||||
/**
|
||||
* Notify the listener that the bean collection has been used.
|
||||
*/
|
||||
void notifyTouched(BeanCollection<?> c);
|
||||
}
|
||||
@@ -34,12 +34,12 @@ public final class CallStack implements Serializable {
|
||||
|
||||
public int hashCode() {
|
||||
int hc = 0;
|
||||
for (int i = 0; i < callStack.length; i++) {
|
||||
hc = 31 * hc + callStack[i].hashCode();
|
||||
for (StackTraceElement aCallStack : callStack) {
|
||||
hc = 31 * hc + aCallStack.hashCode();
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
@@ -88,8 +88,8 @@ public final class CallStack implements Serializable {
|
||||
*/
|
||||
public String description(String newLine) {
|
||||
StringBuilder sb = new StringBuilder(400);
|
||||
for (int i = 0; i < callStack.length; i++) {
|
||||
sb.append(callStack[i].toString()).append(newLine);
|
||||
for (StackTraceElement aCallStack : callStack) {
|
||||
sb.append(aCallStack.toString()).append(newLine);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
private static final int STATE_NEW = 0;
|
||||
private static final int STATE_REFERENCE = 1;
|
||||
private static final int STATE_LOADED = 2;
|
||||
|
||||
|
||||
private transient NodeUsageCollector nodeUsageCollector;
|
||||
|
||||
private transient PropertyChangeSupport pcs;
|
||||
@@ -39,6 +39,8 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
|
||||
private transient BeanLoader beanLoader;
|
||||
|
||||
private transient PreGetterCallback preGetterCallback;
|
||||
|
||||
private String ebeanServerName;
|
||||
|
||||
/**
|
||||
@@ -53,11 +55,11 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* One of NEW, REF, UPD.
|
||||
*/
|
||||
private int state;
|
||||
|
||||
|
||||
private boolean readOnly;
|
||||
|
||||
|
||||
private boolean dirty;
|
||||
|
||||
|
||||
/**
|
||||
* Flag set to disable lazy loading - typically for SQL "report" type entity beans.
|
||||
*/
|
||||
@@ -72,14 +74,14 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* Used when a bean is partially filled.
|
||||
*/
|
||||
private final boolean[] loadedProps;
|
||||
|
||||
|
||||
private boolean fullyLoadedBean;
|
||||
|
||||
/**
|
||||
* Set of changed properties.
|
||||
*/
|
||||
private boolean[] changedProps;
|
||||
|
||||
|
||||
/**
|
||||
* Flags indicating if a property is a dirty embedded bean. Used to distingush
|
||||
* between an embedded bean being completely overwritten and one of its
|
||||
@@ -178,7 +180,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public Object getEmbeddedOwner() {
|
||||
return embeddedOwner;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the property index (for the parent) of this embedded bean.
|
||||
*/
|
||||
@@ -186,6 +188,21 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
return embeddedOwnerIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the getter callback.
|
||||
*/
|
||||
public void clearGetterCallback() {
|
||||
this.preGetterCallback = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the callback to be triggered when getter is called.
|
||||
* This is used primarily to automatically flush the JDBC batch.
|
||||
*/
|
||||
public void registerGetterCallback(PreGetterCallback getterCallback) {
|
||||
this.preGetterCallback = getterCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the embedded beans owning bean.
|
||||
*/
|
||||
@@ -223,8 +240,8 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* Check each property to see if the bean is partially loaded.
|
||||
*/
|
||||
public boolean isPartial() {
|
||||
for (int i = 0; i < loadedProps.length; i++) {
|
||||
if (!loadedProps[i]) {
|
||||
for (boolean loadedProp : loadedProps) {
|
||||
if (!loadedProp) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -246,7 +263,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
this.dirty = true;
|
||||
setEmbeddedPropertyDirty(embeddedProperty);
|
||||
}
|
||||
|
||||
|
||||
public void setDirty(boolean dirty) {
|
||||
this.dirty = dirty;
|
||||
}
|
||||
@@ -273,12 +290,12 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
if (i == idIndex) {
|
||||
if (!loadedProps[i]) return false;
|
||||
} else if (loadedProps[i]) {
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the entity is a reference.
|
||||
*/
|
||||
@@ -295,7 +312,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
// For cases where properties are set on constructor
|
||||
// set every non Id property to unloaded (for lazy loading)
|
||||
for (int i=0; i< loadedProps.length; i++) {
|
||||
if (i != idPos) {
|
||||
if (i != idPos) {
|
||||
loadedProps[i] = false;
|
||||
}
|
||||
}
|
||||
@@ -325,6 +342,13 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
return state == STATE_LOADED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean into NEW state.
|
||||
*/
|
||||
public void setNew() {
|
||||
this.state = STATE_NEW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the loaded state to true.
|
||||
* <p>
|
||||
@@ -424,7 +448,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
return origValues[propertyIndex];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds the index position of a given property. Returns -1 if the property
|
||||
* can not be found.
|
||||
@@ -438,7 +462,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the property name for the given property.
|
||||
*/
|
||||
@@ -448,7 +472,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
return owner._ebean_getPropertyName(propertyIndex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the number of properties.s
|
||||
*/
|
||||
@@ -474,7 +498,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public void setPropertyUnloaded(int propertyIndex) {
|
||||
loadedProps[propertyIndex] = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the property to be loaded.
|
||||
*/
|
||||
@@ -501,7 +525,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* embedded properties is dirty.
|
||||
*/
|
||||
public boolean isDirtyProperty(int propertyIndex) {
|
||||
return (changedProps != null && changedProps[propertyIndex]
|
||||
return (changedProps != null && changedProps[propertyIndex]
|
||||
|| embeddedDirty != null && embeddedDirty[propertyIndex]);
|
||||
}
|
||||
|
||||
@@ -512,7 +536,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
setChangedProperty(propertyIndex);
|
||||
setDirty(true);
|
||||
}
|
||||
|
||||
|
||||
public void setChangedProperty(int propertyIndex) {
|
||||
if (changedProps == null) {
|
||||
changedProps = new boolean[owner._ebean_getPropertyNames().length];
|
||||
@@ -529,7 +553,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
embeddedDirty[propertyIndex] = true;
|
||||
}
|
||||
|
||||
|
||||
private void setOriginalValue(int propertyIndex, Object value) {
|
||||
if (origValues == null) {
|
||||
origValues = new Object[owner._ebean_getPropertyNames().length];
|
||||
@@ -543,19 +567,19 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* For forced update on a 'New' bean set all the loaded properties to changed.
|
||||
*/
|
||||
public void setNewBeanForUpdate() {
|
||||
|
||||
|
||||
if (changedProps == null) {
|
||||
changedProps = new boolean[owner._ebean_getPropertyNames().length];
|
||||
}
|
||||
|
||||
|
||||
for (int i=0; i< loadedProps.length; i++) {
|
||||
if (loadedProps[i]) {
|
||||
changedProps[i] = true;
|
||||
changedProps[i] = true;
|
||||
}
|
||||
}
|
||||
setDirty(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the set of property names for a partially loaded bean.
|
||||
*/
|
||||
@@ -563,7 +587,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
if (fullyLoadedBean) {
|
||||
return null;
|
||||
}
|
||||
Set<String> props = new LinkedHashSet<String>();
|
||||
Set<String> props = new LinkedHashSet<>();
|
||||
for (int i=0; i<loadedProps.length; i++) {
|
||||
if (loadedProps[i]) {
|
||||
props.add(getProperty(i));
|
||||
@@ -593,11 +617,11 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* Return the set of dirty properties.
|
||||
*/
|
||||
public Set<String> getDirtyPropertyNames() {
|
||||
Set<String> props = new LinkedHashSet<String>();
|
||||
Set<String> props = new LinkedHashSet<>();
|
||||
addDirtyPropertyNames(props, null);
|
||||
return props;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recursively add dirty properties.
|
||||
*/
|
||||
@@ -642,11 +666,11 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* Return a map of dirty properties with their new and old values.
|
||||
*/
|
||||
public Map<String,ValuePair> getDirtyValues() {
|
||||
Map<String,ValuePair> dirtyValues = new LinkedHashMap<String, ValuePair>();
|
||||
Map<String,ValuePair> dirtyValues = new LinkedHashMap<>();
|
||||
addDirtyPropertyValues(dirtyValues, null);
|
||||
return dirtyValues;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recursively add dirty properties.
|
||||
*/
|
||||
@@ -660,7 +684,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
Object oldVal = getOrigValue(i);
|
||||
|
||||
dirtyValues.put(propName, new ValuePair(newVal, oldVal));
|
||||
|
||||
|
||||
} else if (embeddedDirty != null && embeddedDirty[i]) {
|
||||
// an embedded property has been changed - recurse
|
||||
EntityBean embeddedBean = (EntityBean)owner._ebean_getField(i);
|
||||
@@ -668,14 +692,14 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a dirty property hash taking into account embedded beans.
|
||||
*/
|
||||
public int getDirtyPropertyHash() {
|
||||
return addDirtyPropertyHash(37);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add and return a dirty property hash recursing into embedded beans.
|
||||
*/
|
||||
@@ -725,7 +749,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public int getLazyLoadPropertyIndex() {
|
||||
return lazyLoadProperty;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the property that triggered the lazy load.
|
||||
*/
|
||||
@@ -825,26 +849,38 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
return obj1.equals(obj2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when a BeanCollection is initialised automatically.
|
||||
*/
|
||||
public void initialisedMany(int propertyIndex) {
|
||||
loadedProps[propertyIndex] = true;
|
||||
}
|
||||
|
||||
|
||||
private final void preGetterCallback() {
|
||||
if (preGetterCallback != null) {
|
||||
preGetterCallback.preGetterTrigger();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called prior to Id property getter.
|
||||
*/
|
||||
public void preGetId() {
|
||||
preGetterCallback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called prior to a getter method on the actual entity.
|
||||
*/
|
||||
public void preGetter(int propertyIndex) {
|
||||
preGetterCallback();
|
||||
if (state == STATE_NEW || disableLazyLoad) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isLoadedProperty(propertyIndex)) {
|
||||
loadBean(propertyIndex);
|
||||
}
|
||||
|
||||
if (nodeUsageCollector != null) {
|
||||
nodeUsageCollector.addUsed(getProperty(propertyIndex));
|
||||
}
|
||||
@@ -884,7 +920,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
if (readOnly) {
|
||||
throw new IllegalStateException("This bean is readOnly");
|
||||
}
|
||||
|
||||
|
||||
setLoadedProperty(propertyIndex);
|
||||
|
||||
// Bean itself not considered dirty when many changed
|
||||
@@ -894,7 +930,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setChangedPropertyValue(int propertyIndex, boolean setDirtyState, Object origValue) {
|
||||
|
||||
if (readOnly) {
|
||||
@@ -905,7 +941,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
if (setDirtyState) {
|
||||
setOriginalValue(propertyIndex, origValue);
|
||||
if (!dirty) {
|
||||
dirty = true;
|
||||
dirty = true;
|
||||
if (embeddedOwner != null) {
|
||||
// Cascade dirty state from Embedded bean to parent bean
|
||||
embeddedOwner._ebean_getIntercept().setEmbeddedDirty(embeddedOwnerIndex);
|
||||
@@ -916,7 +952,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check to see if the values are not equal. If they are not equal then create
|
||||
* the old values for use with ConcurrencyMode.ALL.
|
||||
@@ -926,15 +962,15 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
if (state == STATE_NEW) {
|
||||
setLoadedProperty(propertyIndex);
|
||||
} else if (!areEqual(oldValue, newValue)) {
|
||||
setChangedPropertyValue(propertyIndex, intercept, oldValue);
|
||||
setChangedPropertyValue(propertyIndex, intercept, oldValue);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
|
||||
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check for primitive boolean.
|
||||
*/
|
||||
@@ -971,13 +1007,13 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, long oldValue, long newValue) {
|
||||
|
||||
if (state == STATE_NEW) {
|
||||
setLoadedProperty(propertyIndex);
|
||||
setLoadedProperty(propertyIndex);
|
||||
} else if (oldValue != newValue) {
|
||||
setChangedPropertyValue(propertyIndex, intercept, oldValue);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
|
||||
}
|
||||
|
||||
@@ -989,7 +1025,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
if (state == STATE_NEW) {
|
||||
setLoadedProperty(propertyIndex);
|
||||
} else if (oldValue != newValue) {
|
||||
setChangedPropertyValue(propertyIndex, intercept, oldValue);
|
||||
setChangedPropertyValue(propertyIndex, intercept, oldValue);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public final class NodeUsageCollector {
|
||||
/**
|
||||
* The properties used at this profile point.
|
||||
*/
|
||||
private final Set<String> used = new LinkedHashSet<String>();
|
||||
private final Set<String> used = new LinkedHashSet<>();
|
||||
|
||||
/**
|
||||
* set to true if the bean is modified (setter called)
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
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,7 +1,5 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
|
||||
/**
|
||||
* Represents part of the "L2" server side cache.
|
||||
* <p>
|
||||
@@ -17,27 +15,6 @@ import com.avaje.ebean.EbeanServer;
|
||||
*/
|
||||
public interface ServerCache {
|
||||
|
||||
/**
|
||||
* Just after a cache is created this init method is called. This is so that a
|
||||
* cache implementation can make use of the BackgroundExecutor service to
|
||||
* trim/cleanup itself or use the EbeanServer to populate itself.
|
||||
* <p>
|
||||
* This method is called after the cache is constructed but before the cache
|
||||
* is made available for use.
|
||||
* </p>
|
||||
*/
|
||||
void init(EbeanServer ebeanServer);
|
||||
|
||||
/**
|
||||
* Return the configuration options for this cache.
|
||||
*/
|
||||
ServerCacheOptions getOptions();
|
||||
|
||||
/**
|
||||
* Update the configuration options for this cache.
|
||||
*/
|
||||
void setOptions(ServerCacheOptions options);
|
||||
|
||||
/**
|
||||
* Return the value given the key.
|
||||
*/
|
||||
|
||||
+1
-14
@@ -1,26 +1,13 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
|
||||
/**
|
||||
* Defines method for constructing caches for beans and queries.
|
||||
*/
|
||||
public interface ServerCacheFactory {
|
||||
|
||||
/**
|
||||
* Just after the ServerCacheFactory is constructed this method is called
|
||||
* passing the EbeanServer.
|
||||
* <p>
|
||||
* This is so that a cache implementation can utilise the EbeanServer to
|
||||
* populate itself or use the BackgroundExecutor service to schedule periodic
|
||||
* cache trimming/cleanup.
|
||||
* </p>
|
||||
*/
|
||||
void init(EbeanServer ebeanServer);
|
||||
|
||||
/**
|
||||
* Create the cache for the given type with options.
|
||||
*/
|
||||
ServerCache createCache(String cacheKey, ServerCacheOptions cacheOptions);
|
||||
ServerCache createCache(ServerCacheType type, String cacheKey, ServerCacheOptions cacheOptions);
|
||||
|
||||
}
|
||||
|
||||
+7
-10
@@ -1,24 +1,18 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
|
||||
/**
|
||||
* The cache service for server side caching of beans and query results.
|
||||
*/
|
||||
public interface ServerCacheManager {
|
||||
|
||||
/**
|
||||
* This method is called just after the construction of the
|
||||
* ServerCacheManager.
|
||||
* Return true if the L2 caching is local.
|
||||
* <p>
|
||||
* The EbeanServer is provided so that cache implementations can make use of
|
||||
* EbeanServer and BackgroundExecutor for automatically populating and
|
||||
* background trimming of the cache.
|
||||
* Local L2 caching means that the cache updates should occur in foreground
|
||||
* rather than background processing.
|
||||
* </p>
|
||||
*/
|
||||
void init(EbeanServer server);
|
||||
|
||||
void setCaching(Class<?> beanType, boolean useCache);
|
||||
boolean isLocalL2Caching();
|
||||
|
||||
/**
|
||||
* Return true if there is an active bean cache for this type of bean.
|
||||
@@ -35,6 +29,9 @@ public interface ServerCacheManager {
|
||||
*/
|
||||
ServerCache getBeanCache(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the cache for associated many properties of a bean type.
|
||||
*/
|
||||
ServerCache getCollectionIdsCache(Class<?> beanType, String propertyName);
|
||||
|
||||
/**
|
||||
|
||||
+13
-12
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheTuning;
|
||||
import com.avaje.ebean.annotation.CacheQueryTuning;
|
||||
import com.avaje.ebean.annotation.CacheBeanTuning;
|
||||
|
||||
/**
|
||||
* Options for controlling a cache.
|
||||
@@ -22,23 +23,23 @@ public class ServerCacheOptions {
|
||||
/**
|
||||
* Create from the cacheTuning deployment annotation.
|
||||
*/
|
||||
public ServerCacheOptions(CacheTuning cacheTuning) {
|
||||
public ServerCacheOptions(CacheBeanTuning tuning) {
|
||||
this.maxSize = tuning.maxSize();
|
||||
this.maxIdleSecs = tuning.maxIdleSecs();
|
||||
this.maxSecsToLive = tuning.maxSecsToLive();
|
||||
this.trimFrequency = tuning.trimFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from the cacheTuning deployment annotation.
|
||||
*/
|
||||
public ServerCacheOptions(CacheQueryTuning cacheTuning) {
|
||||
this.maxSize = cacheTuning.maxSize();
|
||||
this.maxIdleSecs = cacheTuning.maxIdleSecs();
|
||||
this.maxSecsToLive = cacheTuning.maxSecsToLive();
|
||||
this.trimFrequency = cacheTuning.trimFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create merging default options with the deployment specified ones.
|
||||
*/
|
||||
public ServerCacheOptions(ServerCacheOptions defaults) {
|
||||
this.maxSize = defaults.getMaxSize();
|
||||
this.maxIdleSecs = defaults.getMaxIdleSecs();
|
||||
this.maxSecsToLive = defaults.getMaxIdleSecs();
|
||||
this.trimFrequency = defaults.getTrimFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any settings from the default settings that have not already been
|
||||
* specifically set.
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
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,16 +1,14 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
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.BeanCollectionTouched;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Base class for List Set and Map implementations of BeanCollection.
|
||||
*
|
||||
@@ -22,6 +20,8 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
protected boolean readOnly;
|
||||
|
||||
protected boolean disableLazyLoad;
|
||||
|
||||
/**
|
||||
* The EbeanServer this is associated with. (used for lazy fetch).
|
||||
*/
|
||||
@@ -36,8 +36,6 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
protected String ebeanServerName;
|
||||
|
||||
protected transient BeanCollectionTouched beanCollectionTouched;
|
||||
|
||||
/**
|
||||
* The owning bean (used for lazy fetch).
|
||||
*/
|
||||
@@ -55,12 +53,6 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
protected boolean modifyRemoveListening;
|
||||
protected boolean modifyListening;
|
||||
|
||||
/**
|
||||
* Flag used to tell if empty collections have been cleared etc or just
|
||||
* uninitialised.
|
||||
*/
|
||||
protected boolean touched;
|
||||
|
||||
/**
|
||||
* Constructor not non-lazy loading collection.
|
||||
*/
|
||||
@@ -94,6 +86,11 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
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);
|
||||
@@ -109,25 +106,6 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
checkEmptyLazyLoad();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touched. If setFlag is false then typically an isEmpty() call and still
|
||||
* considering that to be untouched.
|
||||
*/
|
||||
protected void touched(boolean setFlag) {
|
||||
if (setFlag) {
|
||||
touched = true;
|
||||
}
|
||||
if (beanCollectionTouched != null) {
|
||||
// only call this once
|
||||
beanCollectionTouched.notifyTouched(this);
|
||||
beanCollectionTouched = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setBeanCollectionTouched(BeanCollectionTouched notify) {
|
||||
this.beanCollectionTouched = notify;
|
||||
}
|
||||
|
||||
public boolean isRegisteredWithLoadContext() {
|
||||
return registeredWithLoadContext;
|
||||
}
|
||||
@@ -181,7 +159,7 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
protected ModifyHolder<E> getModifyHolder() {
|
||||
if (modifyHolder == null) {
|
||||
modifyHolder = new ModifyHolder<E>();
|
||||
modifyHolder = new ModifyHolder<>();
|
||||
}
|
||||
return modifyHolder;
|
||||
}
|
||||
@@ -219,4 +197,11 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
return modifyHolder.getModifyRemovals();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are underlying additions or removals.
|
||||
*/
|
||||
public boolean holdsModifications() {
|
||||
return modifyHolder != null && modifyHolder.hasModifications();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
* Uses an ArrayList as the underlying List implementation.
|
||||
*/
|
||||
public BeanList() {
|
||||
this(new ArrayList<E>());
|
||||
this(new ArrayList<>());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,12 +52,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.list = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (list == null || list.isEmpty());
|
||||
public boolean isSkipSave() {
|
||||
return list == null || (list.isEmpty() && !holdsModifications());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -69,7 +68,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
@SuppressWarnings("unchecked")
|
||||
public void loadFrom(BeanCollection<?> other) {
|
||||
if (list == null) {
|
||||
list = new ArrayList<E>();
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
list.addAll((Collection<? extends E>) other.getActualDetails());
|
||||
}
|
||||
@@ -77,7 +76,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalAdd(Object bean) {
|
||||
if (list == null) {
|
||||
list = new ArrayList<E>();
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
if (bean != null) {
|
||||
list.add((E) bean);
|
||||
@@ -93,7 +92,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
|
||||
public boolean checkEmptyLazyLoad() {
|
||||
if (list == null) {
|
||||
list = new ArrayList<E>();
|
||||
list = new ArrayList<>();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -103,30 +102,24 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
private void initClear() {
|
||||
synchronized (this) {
|
||||
if (list == null) {
|
||||
if (modifyListening) {
|
||||
if (!disableLazyLoad && modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
} else {
|
||||
list = new ArrayList<E>();
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (list == null) {
|
||||
lazyLoadCollection(false);
|
||||
if (disableLazyLoad) {
|
||||
list = new ArrayList<>();
|
||||
} else {
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,8 +261,8 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
// and fetch just the Id's
|
||||
initClear();
|
||||
if (modifyRemoveListening) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
getModifyHolder().modifyRemoval(list.get(i));
|
||||
for (E aList : list) {
|
||||
getModifyHolder().modifyRemoval(aList);
|
||||
}
|
||||
}
|
||||
list.clear();
|
||||
@@ -296,18 +289,18 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
init();
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
public Iterator<E> iterator() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return new ReadOnlyListIterator<E>(list.listIterator());
|
||||
return new ReadOnlyListIterator<>(list.listIterator());
|
||||
}
|
||||
if (modifyListening) {
|
||||
Iterator<E> it = list.iterator();
|
||||
return new ModifyIterator<E>(this, it);
|
||||
return new ModifyIterator<>(this, it);
|
||||
}
|
||||
return list.iterator();
|
||||
}
|
||||
@@ -320,11 +313,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
public ListIterator<E> listIterator() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return new ReadOnlyListIterator<E>(list.listIterator());
|
||||
return new ReadOnlyListIterator<>(list.listIterator());
|
||||
}
|
||||
if (modifyListening) {
|
||||
ListIterator<E> it = list.listIterator();
|
||||
return new ModifyListIterator<E>(this, it);
|
||||
return new ModifyListIterator<>(this, it);
|
||||
}
|
||||
return list.listIterator();
|
||||
}
|
||||
@@ -332,11 +325,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
public ListIterator<E> listIterator(int index) {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return new ReadOnlyListIterator<E>(list.listIterator(index));
|
||||
return new ReadOnlyListIterator<>(list.listIterator(index));
|
||||
}
|
||||
if (modifyListening) {
|
||||
ListIterator<E> it = list.listIterator(index);
|
||||
return new ModifyListIterator<E>(this, it);
|
||||
return new ModifyListIterator<>(this, it);
|
||||
}
|
||||
return list.listIterator(index);
|
||||
}
|
||||
@@ -432,7 +425,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
return Collections.unmodifiableList(list.subList(fromIndex, toIndex));
|
||||
}
|
||||
if (modifyListening) {
|
||||
return new ModifyList<E>(this, list.subList(fromIndex, toIndex));
|
||||
return new ModifyList<>(this, list.subList(fromIndex, toIndex));
|
||||
}
|
||||
return list.subList(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
* Create using a underlying LinkedHashMap.
|
||||
*/
|
||||
public BeanMap() {
|
||||
this(new LinkedHashMap<K, E>());
|
||||
this(new LinkedHashMap<>());
|
||||
}
|
||||
|
||||
public BeanMap(BeanCollectionLoader ebeanServer, EntityBean ownerBean, String propertyName) {
|
||||
@@ -45,11 +45,10 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.map = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (map == null || map.isEmpty());
|
||||
public boolean isSkipSave() {
|
||||
return map == null || (map.isEmpty() && !holdsModifications());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,14 +61,14 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
|
||||
public void internalPutNull() {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
map = new LinkedHashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalPut(Object key, Object bean) {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
map = new LinkedHashMap<>();
|
||||
}
|
||||
if (key != null) {
|
||||
map.put((K) key, (E) bean);
|
||||
@@ -109,7 +108,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
|
||||
public boolean checkEmptyLazyLoad() {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
map = new LinkedHashMap<>();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -122,27 +121,17 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
if (modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
} else {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
map = new LinkedHashMap<>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (map == null) {
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +238,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
init();
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
@@ -276,7 +265,6 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void putAll(Map<? extends K, ? extends E> puts) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
@@ -325,7 +313,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
}
|
||||
if (modifyListening) {
|
||||
Collection<E> c = map.values();
|
||||
return new ModifyCollection<E>(this, c);
|
||||
return new ModifyCollection<>(this, c);
|
||||
}
|
||||
return map.values();
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
* Create using an underlying LinkedHashSet.
|
||||
*/
|
||||
public BeanSet() {
|
||||
this(new LinkedHashSet<E>());
|
||||
this(new LinkedHashSet<>());
|
||||
}
|
||||
|
||||
public BeanSet(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
|
||||
@@ -46,11 +46,10 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.set = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (set == null || set.isEmpty());
|
||||
public boolean isSkipSave() {
|
||||
return set == null || (set.isEmpty() && !holdsModifications());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -62,7 +61,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
@SuppressWarnings("unchecked")
|
||||
public void loadFrom(BeanCollection<?> other) {
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<E>();
|
||||
set = new LinkedHashSet<>();
|
||||
}
|
||||
set.addAll((Collection<? extends E>) other.getActualDetails());
|
||||
}
|
||||
@@ -77,7 +76,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalAdd(Object bean) {
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<E>();
|
||||
set = new LinkedHashSet<>();
|
||||
}
|
||||
if (bean != null) {
|
||||
set.add((E) bean);
|
||||
@@ -101,7 +100,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
|
||||
public boolean checkEmptyLazyLoad() {
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<E>();
|
||||
set = new LinkedHashSet<>();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -114,27 +113,17 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
if (modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
} else {
|
||||
set = new LinkedHashSet<E>();
|
||||
set = new LinkedHashSet<>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (set == null) {
|
||||
lazyLoadCollection(true);
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,17 +249,17 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
init();
|
||||
return set.isEmpty();
|
||||
}
|
||||
|
||||
public Iterator<E> iterator() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return new ReadOnlyIterator<E>(set.iterator());
|
||||
return new ReadOnlyIterator<>(set.iterator());
|
||||
}
|
||||
if (modifyListening) {
|
||||
return new ModifyIterator<E>(this, set.iterator());
|
||||
return new ModifyIterator<>(this, set.iterator());
|
||||
}
|
||||
return set.iterator();
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ class ModifyCollection<E> implements Collection<E> {
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
Iterator<E> it = c.iterator();
|
||||
return new ModifyIterator<E>(owner, it);
|
||||
return new ModifyIterator<>(owner, it);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,16 +21,16 @@ class ModifyHolder<E> implements Serializable {
|
||||
/**
|
||||
* Deletions list for manyToMany persistence.
|
||||
*/
|
||||
private Set<E> modifyDeletions = new LinkedHashSet<E>();
|
||||
private Set<E> modifyDeletions = new LinkedHashSet<>();
|
||||
|
||||
/**
|
||||
* Additions list for manyToMany persistence.
|
||||
*/
|
||||
private Set<E> modifyAdditions = new LinkedHashSet<E>();
|
||||
private Set<E> modifyAdditions = new LinkedHashSet<>();
|
||||
|
||||
void reset() {
|
||||
modifyDeletions = new LinkedHashSet<E>();
|
||||
modifyAdditions = new LinkedHashSet<E>();
|
||||
modifyDeletions = new LinkedHashSet<>();
|
||||
modifyAdditions = new LinkedHashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,4 +71,11 @@ class ModifyHolder<E> implements Serializable {
|
||||
Set<E> getModifyRemovals() {
|
||||
return modifyDeletions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there additions or removals.
|
||||
*/
|
||||
boolean hasModifications() {
|
||||
return !modifyDeletions.isEmpty() || !modifyAdditions.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,11 +61,11 @@ class ModifyList<E> extends ModifyCollection<E> implements List<E> {
|
||||
}
|
||||
|
||||
public ListIterator<E> listIterator() {
|
||||
return new ModifyListIterator<E>(owner, list.listIterator());
|
||||
return new ModifyListIterator<>(owner, list.listIterator());
|
||||
}
|
||||
|
||||
public ListIterator<E> listIterator(int index) {
|
||||
return new ModifyListIterator<E>(owner, list.listIterator(index));
|
||||
return new ModifyListIterator<>(owner, list.listIterator(index));
|
||||
}
|
||||
|
||||
public E remove(int index) {
|
||||
@@ -82,7 +82,7 @@ class ModifyList<E> extends ModifyCollection<E> implements List<E> {
|
||||
}
|
||||
|
||||
public List<E> subList(int fromIndex, int toIndex) {
|
||||
return new ModifyList<E>(owner, list.subList(fromIndex, toIndex));
|
||||
return new ModifyList<>(owner, list.subList(fromIndex, toIndex));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
* Checks string is null or empty .
|
||||
*/
|
||||
protected boolean isEmpty(String s) {
|
||||
return s == null || s.trim().length() == 0;
|
||||
return s == null || s.trim().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* Helper to find classes taking into account the context class loader.
|
||||
*/
|
||||
@@ -29,6 +33,13 @@ public class ClassLoadConfig {
|
||||
return isPresent("java.time.LocalDate");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Java7 is present.
|
||||
*/
|
||||
public boolean isJava7Present() {
|
||||
return isPresent("java.nio.file.Path");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the Joda types are available and should be supported.
|
||||
*/
|
||||
@@ -70,10 +81,17 @@ public class ClassLoadConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resources for the given name.
|
||||
*/
|
||||
public Enumeration<URL> getResources(String name) throws IOException {
|
||||
return context.getResources(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given class is present.
|
||||
*/
|
||||
protected boolean isPresent(String className) {
|
||||
public boolean isPresent(String className) {
|
||||
try {
|
||||
forName(className);
|
||||
return true;
|
||||
@@ -122,6 +140,13 @@ public class ClassLoadConfig {
|
||||
return (loader != null) ? loader: callerLoader;
|
||||
}
|
||||
|
||||
Enumeration<URL> getResources(String name) throws IOException {
|
||||
if (preferredLoader != null) {
|
||||
return preferredLoader.getResources(name);
|
||||
}
|
||||
return contextLoader().getResources(name);
|
||||
}
|
||||
|
||||
Class<?> forName(String name) throws ClassNotFoundException {
|
||||
|
||||
if (preferredLoader != null) {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
@@ -12,453 +10,51 @@ import java.util.Properties;
|
||||
*/
|
||||
public class ContainerConfig {
|
||||
|
||||
protected boolean clusterActive;
|
||||
|
||||
protected Properties properties;
|
||||
|
||||
/**
|
||||
* Communication mode used for clustering.
|
||||
* Return true if clustering is active.
|
||||
*/
|
||||
public enum ClusterMode {
|
||||
|
||||
/**
|
||||
* No clustering.
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* Use Multicast networking for cluster wide communication.
|
||||
*/
|
||||
MULTICAST,
|
||||
|
||||
/**
|
||||
* Use TCP Sockets for cluster wide communication.
|
||||
*/
|
||||
SOCKET
|
||||
public boolean isClusterActive() {
|
||||
return clusterActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cluster mode to use.
|
||||
* Set to true for clustering to be active.
|
||||
*/
|
||||
ClusterMode mode = ClusterMode.NONE;
|
||||
|
||||
/**
|
||||
* Configuration if using TCP sockets for clustering communication.
|
||||
*/
|
||||
SocketConfig socketConfig = new SocketConfig();
|
||||
|
||||
/**
|
||||
* Configuration if using Multicast for clustering communication.
|
||||
*/
|
||||
MulticastConfig multicastConfig = new MulticastConfig();
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// MulticastConfig
|
||||
|
||||
/**
|
||||
* The configuration for clustering using Multicast networking.
|
||||
*/
|
||||
public static class MulticastConfig {
|
||||
|
||||
int managerSleepMillis = 80;
|
||||
int lastSendTimeFreqSecs = 300;//5mins
|
||||
int lastStatusTimeFreqSecs = 600;//10mins
|
||||
int maxResendOutgoingAttempts = 200;
|
||||
int maxResendIncomingRequests = 50;
|
||||
|
||||
int listenPort;
|
||||
String listenAddress;
|
||||
int sendPort;
|
||||
String sendAddress;
|
||||
|
||||
// Note 1500 is Ethernet MTU and this must be less than UDP max packet size of 65507
|
||||
int maxSendPacketSize = 1500;
|
||||
|
||||
// Whether to send packets even when there are no other members online
|
||||
boolean sendWithNoMembers = true;
|
||||
|
||||
// When multiple instances are on same box you need to broadcast back locally
|
||||
boolean disableLoopback;
|
||||
int listenTimeToLive = -1;
|
||||
int listenTimeout = 1000;
|
||||
int listenBufferSize = 65500;
|
||||
// For multihomed environment the address the listener should bind to
|
||||
String listenBindAddress;
|
||||
|
||||
/**
|
||||
* Return the manager sleep millis.
|
||||
*/
|
||||
public int getManagerSleepMillis() {
|
||||
return managerSleepMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the manager sleep millis.
|
||||
*/
|
||||
public void setManagerSleepMillis(int managerSleepMillis) {
|
||||
this.managerSleepMillis = managerSleepMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last send time frequency.
|
||||
*/
|
||||
public int getLastSendTimeFreqSecs() {
|
||||
return lastSendTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last send time frequency.
|
||||
*/
|
||||
public void setLastSendTimeFreqSecs(int lastSendTimeFreqSecs) {
|
||||
this.lastSendTimeFreqSecs = lastSendTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last status time frequency.
|
||||
*/
|
||||
public int getLastStatusTimeFreqSecs() {
|
||||
return lastStatusTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last status time frequency.
|
||||
*/
|
||||
public void setLastStatusTimeFreqSecs(int lastStatusTimeFreqSecs) {
|
||||
this.lastStatusTimeFreqSecs = lastStatusTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of times we will try to re-send a given packet before giving up sending
|
||||
*/
|
||||
public int getMaxResendOutgoingAttempts() {
|
||||
return maxResendOutgoingAttempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum retry attempts for outgoing messages.
|
||||
*/
|
||||
public void setMaxResendOutgoingAttempts(int maxResendOutgoingAttempts) {
|
||||
this.maxResendOutgoingAttempts = maxResendOutgoingAttempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of times we will ask for a packet to be resent to us before giving up asking.
|
||||
*/
|
||||
public int getMaxResendIncomingRequests() {
|
||||
return maxResendIncomingRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum retry attempts for incoming messages.
|
||||
*/
|
||||
public void setMaxResendIncomingRequests(int maxResendIncomingRequests) {
|
||||
this.maxResendIncomingRequests = maxResendIncomingRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen port.
|
||||
*/
|
||||
public int getListenPort() {
|
||||
return listenPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen port.
|
||||
*/
|
||||
public void setListenPort(int port) {
|
||||
this.listenPort = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen address.
|
||||
*/
|
||||
public String getListenAddress() {
|
||||
return listenAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen address.
|
||||
*/
|
||||
public void setListenAddress(String listenAddress) {
|
||||
this.listenAddress = listenAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the send port.
|
||||
*/
|
||||
public int getSendPort() {
|
||||
return sendPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the send port.
|
||||
*/
|
||||
public void setSendPort(int sendPort) {
|
||||
this.sendPort = sendPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the send address.
|
||||
*/
|
||||
public String getSendAddress() {
|
||||
return sendAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the send address.
|
||||
*/
|
||||
public void setSendAddress(String sendAddress) {
|
||||
this.sendAddress = sendAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum send packet size.
|
||||
*/
|
||||
public int getMaxSendPacketSize() {
|
||||
return maxSendPacketSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum send packet size. Note 1500 is Ethernet MTU and this must be less than UDP max packet size of 65507.
|
||||
*/
|
||||
public void setMaxSendPacketSize(int maxSendPacketSize) {
|
||||
this.maxSendPacketSize = maxSendPacketSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if send messages when no other members in the cluster are up.
|
||||
*/
|
||||
public boolean isSendWithNoMembers() {
|
||||
return sendWithNoMembers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set true if send messages when no other members in the cluster are up.
|
||||
*/
|
||||
public void setSendWithNoMembers(boolean sendWithNoMembers) {
|
||||
this.sendWithNoMembers = sendWithNoMembers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if loopback is disabled. When multiple instances are on same box you need to broadcast back locally.
|
||||
*/
|
||||
public boolean isDisableLoopback() {
|
||||
return disableLoopback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if loopback is disabled. When multiple instances are on same box you need to broadcast back locally.
|
||||
*/
|
||||
public void setDisableLoopback(boolean disableLoopback) {
|
||||
this.disableLoopback = disableLoopback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen time to live.
|
||||
*/
|
||||
public int getListenTimeToLive() {
|
||||
return listenTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen time to live.
|
||||
*/
|
||||
public void setListenTimeToLive(int listenTimeToLive) {
|
||||
this.listenTimeToLive = listenTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen timeout.
|
||||
*/
|
||||
public int getListenTimeout() {
|
||||
return listenTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the listen timeout.
|
||||
*/
|
||||
public void setListenTimeout(int listenTimeout) {
|
||||
this.listenTimeout = listenTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen buffer size.
|
||||
*/
|
||||
public int getListenBufferSize() {
|
||||
return listenBufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen buffer size.
|
||||
*/
|
||||
public void setListenBufferSize(int listenBufferSize) {
|
||||
this.listenBufferSize = listenBufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listener bind address (optional). For multihomed environment the address the listener should bind to.
|
||||
*/
|
||||
public String getListenBindAddress() {
|
||||
return listenBindAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listener bind address (optional). For multihomed environment the address the listener should bind to.
|
||||
*/
|
||||
public void setListenBindAddress(String listenBindAddress) {
|
||||
this.listenBindAddress = listenBindAddress;
|
||||
}
|
||||
public void setClusterActive(boolean clusterActive) {
|
||||
this.clusterActive = clusterActive;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// SocketConfig
|
||||
|
||||
/**
|
||||
* Configuration for clustering using TCP sockets.
|
||||
* <p>
|
||||
* This is good for when there are relatively small number of cluster members.
|
||||
* Return the deployment properties.
|
||||
*/
|
||||
public static class SocketConfig {
|
||||
|
||||
/**
|
||||
* This local server in host:port format.
|
||||
*/
|
||||
String localHostPort;
|
||||
|
||||
/**
|
||||
* All the cluster members in host:port format.
|
||||
*/
|
||||
List<String> members = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* core threads for the associated thread pool.
|
||||
*/
|
||||
int coreThreads = 2;
|
||||
|
||||
/**
|
||||
* Max threads for the associated thread pool.
|
||||
*/
|
||||
int maxThreads = 16;
|
||||
|
||||
String threadPoolName = "EbeanCluster";
|
||||
|
||||
/**
|
||||
* Return the host and port for this server instance.
|
||||
*/
|
||||
public String getLocalHostPort() {
|
||||
return localHostPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the host and port for this server instance.
|
||||
*/
|
||||
public void setLocalHostPort(String localHostPort) {
|
||||
this.localHostPort = localHostPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the host and port for all the members of the cluster.
|
||||
*/
|
||||
public List<String> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all the host and port for all the members of the cluster.
|
||||
*/
|
||||
public void setMembers(List<String> members) {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of core threads to use.
|
||||
*/
|
||||
public int getCoreThreads() {
|
||||
return coreThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of core threads to use.
|
||||
*/
|
||||
public void setCoreThreads(int coreThreads) {
|
||||
this.coreThreads = coreThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of max threads to use.
|
||||
*/
|
||||
public int getMaxThreads() {
|
||||
return maxThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of max threads to use.
|
||||
*/
|
||||
public void setMaxThreads(int maxThreads) {
|
||||
this.maxThreads = maxThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the thread pool name.
|
||||
*/
|
||||
public String getThreadPoolName() {
|
||||
return threadPoolName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the thread pool name.
|
||||
*/
|
||||
public void setThreadPoolName(String threadPoolName) {
|
||||
this.threadPoolName = threadPoolName;
|
||||
}
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// Members
|
||||
/**
|
||||
* Set the deployment properties.
|
||||
*/
|
||||
public void setProperties(Properties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from properties.
|
||||
*/
|
||||
public void loadFromProperties(Properties properties) {
|
||||
//TODO
|
||||
this.properties = properties;
|
||||
this.clusterActive = getProperty(properties, "ebean.cluster.active", clusterActive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cluster mode.
|
||||
* Return the boolean property setting.
|
||||
*/
|
||||
public ClusterMode getMode() {
|
||||
return mode;
|
||||
protected boolean getProperty(Properties properties, String key, boolean defaultValue) {
|
||||
return "true".equalsIgnoreCase(properties.getProperty(key, Boolean.toString(defaultValue)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cluster mode.
|
||||
*/
|
||||
public void setMode(ClusterMode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the socket communication configuration.
|
||||
*/
|
||||
public SocketConfig getSocketConfig() {
|
||||
return socketConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the socket communication configuration.
|
||||
*/
|
||||
public void setSocketConfig(SocketConfig socketConfig) {
|
||||
this.socketConfig = socketConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the multicast communication configuration.
|
||||
*/
|
||||
public MulticastConfig getMulticastConfig() {
|
||||
return multicastConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the multicast communication configuration.
|
||||
*/
|
||||
public void setMulticastConfig(MulticastConfig multicastConfig) {
|
||||
this.multicastConfig = multicastConfig;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
|
||||
/**
|
||||
* Custom mappings for DB types that override the default.
|
||||
*
|
||||
* @see ServerConfig#addCustomMapping(DbType, String)
|
||||
*/
|
||||
public class CustomDbTypeMapping {
|
||||
|
||||
protected final DbType type;
|
||||
|
||||
protected final String columnDefinition;
|
||||
|
||||
protected final Platform platform;
|
||||
|
||||
/**
|
||||
* Create a mapping.
|
||||
*/
|
||||
public CustomDbTypeMapping(DbType type, String columnDefinition, Platform platform) {
|
||||
this.type = type;
|
||||
this.columnDefinition = columnDefinition;
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mapping that should apply to all the database platforms.
|
||||
*/
|
||||
public CustomDbTypeMapping(DbType type, String columnDefinition) {
|
||||
this(type, columnDefinition, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB type the mapping applies to.
|
||||
*/
|
||||
public DbType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB column definition to use.
|
||||
*/
|
||||
public String getColumnDefinition() {
|
||||
return columnDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the platform this mapping should apply to. Null means it applied to all platforms.
|
||||
*/
|
||||
public Platform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
}
|
||||
@@ -78,8 +78,8 @@ public class DbConstraintNormalise {
|
||||
public boolean notQuoted(String tableName) {
|
||||
|
||||
// remove quoted identifier characters
|
||||
for (int i = 0; i < quotedIdentifiers.length; i++) {
|
||||
if (tableName.contains(quotedIdentifiers[i])) {
|
||||
for (String quotedIdentifier : quotedIdentifiers) {
|
||||
if (tableName.contains(quotedIdentifier)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -95,8 +95,8 @@ public class DbConstraintNormalise {
|
||||
return "";
|
||||
}
|
||||
// remove quoted identifier characters
|
||||
for (int i = 0; i < quotedIdentifiers.length; i++) {
|
||||
tableName = tableName.replace(quotedIdentifiers[i], "");
|
||||
for (String quotedIdentifier : quotedIdentifiers) {
|
||||
tableName = tableName.replace(quotedIdentifier, "");
|
||||
}
|
||||
return tableName;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformName;
|
||||
import com.avaje.ebean.dbmigration.DbMigration;
|
||||
import org.avaje.dbmigration.MigrationConfig;
|
||||
import org.avaje.dbmigration.MigrationRunner;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Configuration for the DB migration processing.
|
||||
*/
|
||||
@@ -16,7 +19,7 @@ public class DbMigrationConfig {
|
||||
/**
|
||||
* The database platform to generate migration DDL for.
|
||||
*/
|
||||
protected DbPlatformName platform;
|
||||
protected Platform platform;
|
||||
|
||||
/**
|
||||
* Set to true if the DB migration should be generated on server start.
|
||||
@@ -58,6 +61,11 @@ public class DbMigrationConfig {
|
||||
|
||||
protected String applySuffix = ".sql";
|
||||
|
||||
/**
|
||||
* Set this to "V" to be compatible with FlywayDB.
|
||||
*/
|
||||
protected String applyPrefix = "";
|
||||
|
||||
protected String modelSuffix = ".model.xml";
|
||||
|
||||
protected boolean includeGeneratedFileComment;
|
||||
@@ -67,20 +75,50 @@ public class DbMigrationConfig {
|
||||
*/
|
||||
protected String generatePendingDrop;
|
||||
|
||||
/**
|
||||
* For running migration the DB table that holds migration execution status.
|
||||
*/
|
||||
protected String metaTable = "db_migration";
|
||||
|
||||
/**
|
||||
* Flag set to true means to run any outstanding migrations on startup.
|
||||
*/
|
||||
protected boolean runMigration;
|
||||
|
||||
/**
|
||||
* Comma and equals delimited key/value placeholders to replace in DDL scripts.
|
||||
*/
|
||||
protected String runPlaceholders;
|
||||
|
||||
/**
|
||||
* Map of key/value placeholders to replace in DDL scripts.
|
||||
*/
|
||||
protected Map<String,String> runPlaceholderMap;
|
||||
|
||||
/**
|
||||
* DB user used to run the DB migration.
|
||||
*/
|
||||
protected String dbUsername;
|
||||
|
||||
/**
|
||||
* DB password used to run the DB migration.
|
||||
*/
|
||||
protected String dbPassword;
|
||||
|
||||
/**
|
||||
* Return the DB platform to generate migration DDL for.
|
||||
*
|
||||
* We typically need to explicitly specify this as migration can often be generated
|
||||
* when running against H2.
|
||||
*/
|
||||
public DbPlatformName getPlatform() {
|
||||
public Platform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB platform to generate migration DDL for.
|
||||
*/
|
||||
public void setPlatform(DbPlatformName platform) {
|
||||
public void setPlatform(Platform platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
@@ -145,6 +183,20 @@ public class DbMigrationConfig {
|
||||
this.applySuffix = applySuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the apply prefix.
|
||||
*/
|
||||
public String getApplyPrefix() {
|
||||
return applyPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the apply prefix. This might be set to "V" for use with FlywayDB.
|
||||
*/
|
||||
public void setApplyPrefix(String applyPrefix) {
|
||||
this.applyPrefix = applyPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the generated file comment should be included.
|
||||
*/
|
||||
@@ -192,34 +244,144 @@ public class DbMigrationConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the model, rollback and drop paths to be empty such that all the migration files are generated
|
||||
* into a single directory.
|
||||
* Return the table name that holds the migration run details
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public void singleDirectory() {
|
||||
this.modelPath = "";
|
||||
public String getMetaTable() {
|
||||
return metaTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table name that holds the migration run details
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public void setMetaTable(String metaTable) {
|
||||
this.metaTable = metaTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a comma and equals delimited placeholders that are substituted in SQL scripts when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public String getRunPlaceholders() {
|
||||
// environment properties take precedence
|
||||
String placeholders = readEnvironment("ddl.migration.placeholders");
|
||||
if (placeholders != null) {
|
||||
return placeholders;
|
||||
}
|
||||
return runPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a comma and equals delimited placeholders that are substituted in SQL scripts when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public void setRunPlaceholders(String runPlaceholders) {
|
||||
this.runPlaceholders = runPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of placeholder values that are substituted in SQL scripts when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public Map<String, String> getRunPlaceholderMap() {
|
||||
return runPlaceholderMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a map of placeholder values that are substituted when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public void setRunPlaceholderMap(Map<String, String> runPlaceholderMap) {
|
||||
this.runPlaceholderMap = runPlaceholderMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the DB migration should be run on startup.
|
||||
*/
|
||||
public boolean isRunMigration() {
|
||||
// environment properties take precedence
|
||||
String run = readEnvironment("ddl.migration.run");
|
||||
if (run != null) {
|
||||
return "true".equalsIgnoreCase(run.trim());
|
||||
}
|
||||
return runMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to run the DB migration on startup.
|
||||
*/
|
||||
public void setRunMigration(boolean runMigration) {
|
||||
this.runMigration = runMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB username to use for running DB migrations.
|
||||
*/
|
||||
public String getDbUsername() {
|
||||
// environment properties take precedence
|
||||
String user = readEnvironment("ddl.migration.user");
|
||||
if (user != null) {
|
||||
return user;
|
||||
}
|
||||
return dbUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB username to use for running DB migrations.
|
||||
*/
|
||||
public void setDbUsername(String dbUsername) {
|
||||
this.dbUsername = dbUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB password to use for running DB migrations.
|
||||
*/
|
||||
public String getDbPassword() {
|
||||
String user = readEnvironment("ddl.migration.password");
|
||||
if (user != null) {
|
||||
return user;
|
||||
}
|
||||
return dbPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB password to use for running DB migrations.
|
||||
*/
|
||||
public void setDbPassword(String dbPassword) {
|
||||
this.dbPassword = dbPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from the PropertiesWrapper.
|
||||
*/
|
||||
public void loadSettings(PropertiesWrapper properties) {
|
||||
public void loadSettings(PropertiesWrapper properties, String serverName) {
|
||||
|
||||
migrationPath = properties.get("migration.migrationPath", migrationPath);
|
||||
if (properties.getBoolean("migration.singleDirectory", false)) {
|
||||
singleDirectory();
|
||||
} else {
|
||||
modelPath = properties.get("migration.modelPath", modelPath);
|
||||
}
|
||||
modelPath = properties.get("migration.modelPath", modelPath);
|
||||
applyPrefix = properties.get("migration.applyPrefix", applyPrefix);
|
||||
applySuffix = properties.get("migration.applySuffix", applySuffix);
|
||||
modelSuffix = properties.get("migration.modelSuffix", modelSuffix);
|
||||
includeGeneratedFileComment = properties.getBoolean("migration.includeGeneratedFileComment", includeGeneratedFileComment);
|
||||
generatePendingDrop = properties.get("migration.generatePendingDrop", generatePendingDrop);
|
||||
|
||||
platform = properties.getEnum(DbPlatformName.class, "migration.platform", platform);
|
||||
platform = properties.getEnum(Platform.class, "migration.platform", platform);
|
||||
|
||||
generate = properties.getBoolean("migration.generate", generate);
|
||||
version = properties.get("migration.version", version);
|
||||
name = properties.get("migration.name", name);
|
||||
|
||||
runMigration = properties.getBoolean("migration.run", runMigration);
|
||||
metaTable = properties.get("migration.metaTable", metaTable);
|
||||
runPlaceholders = properties.get("migration.placeholders", runPlaceholders);
|
||||
|
||||
String adminUser = properties.get("datasource."+serverName+".username", dbUsername);
|
||||
adminUser = properties.get("datasource."+serverName+".adminusername", adminUser);
|
||||
dbUsername = properties.get("migration.dbusername", adminUser);
|
||||
|
||||
String adminPwd = properties.get("datasource."+serverName+".password", dbPassword);
|
||||
adminPwd = properties.get("datasource."+serverName+".adminpassword", adminPwd);
|
||||
dbPassword = properties.get("migration.dbpassword", adminPwd);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,4 +483,20 @@ public class DbMigrationConfig {
|
||||
return val == null || val.trim().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the MigrationRunner to run migrations if necessary.
|
||||
*/
|
||||
public MigrationRunner createRunner(ClassLoader classLoader) {
|
||||
|
||||
MigrationConfig runnerConfig = new MigrationConfig();
|
||||
runnerConfig.setMetaTable(metaTable);
|
||||
runnerConfig.setApplySuffix(applySuffix);
|
||||
runnerConfig.setMigrationPath(migrationPath);
|
||||
runnerConfig.setRunPlaceholderMap(runPlaceholderMap);
|
||||
runnerConfig.setRunPlaceholders(runPlaceholders);
|
||||
runnerConfig.setDbUsername(getDbUsername());
|
||||
runnerConfig.setDbPassword(getDbPassword());
|
||||
runnerConfig.setClassLoader(classLoader);
|
||||
return new MigrationRunner(runnerConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.avaje.ebean.config.dbplatform.IdType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Configuration for DB types such as UUID, Geometry etc.
|
||||
*/
|
||||
public class DbTypeConfig {
|
||||
|
||||
/**
|
||||
* The Geometry SRID value (default 4326).
|
||||
*/
|
||||
private int geometrySRID = 4326;
|
||||
|
||||
/**
|
||||
* Set for DB's that support both Sequence and Identity (and the default choice is not desired).
|
||||
*/
|
||||
private IdType idType;
|
||||
|
||||
/**
|
||||
* Setting to indicate if UUID should be stored as binary(16) or varchar(40) or native DB type (for H2 and Postgres).
|
||||
*/
|
||||
private ServerConfig.DbUuid dbUuid = ServerConfig.DbUuid.AUTO_VARCHAR;
|
||||
|
||||
/**
|
||||
* Modify the default mapping of standard types such as default precision for DECIMAL etc.
|
||||
*/
|
||||
private List<CustomDbTypeMapping> customDbTypeMappings = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Return the Geometry SRID.
|
||||
*/
|
||||
public int getGeometrySRID() {
|
||||
return geometrySRID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Geometry SRID.
|
||||
*/
|
||||
public void setGeometrySRID(int geometrySRID) {
|
||||
this.geometrySRID = geometrySRID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB type used to store UUID.
|
||||
*/
|
||||
public ServerConfig.DbUuid getDbUuid() {
|
||||
return dbUuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB type used to store UUID.
|
||||
*/
|
||||
public void setDbUuid(ServerConfig.DbUuid dbUuid) {
|
||||
this.dbUuid = dbUuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the IdType to use (or null for the default choice).
|
||||
*/
|
||||
public IdType getIdType() {
|
||||
return idType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the IdType to use (when the DB supports both SEQUENCE and IDENTITY and the default is not desired).
|
||||
*/
|
||||
public void setIdType(IdType idType) {
|
||||
this.idType = idType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom type mapping.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set the default mapping for BigDecimal.class/decimal
|
||||
* serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
|
||||
*
|
||||
* // set the default mapping for String.class/varchar but only for Postgres
|
||||
* serverConfig.addCustomMapping(DbType.VARCHAR, "text", Platform.POSTGRES);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param type The DB type this mapping should apply to
|
||||
* @param columnDefinition The column definition that should be used
|
||||
* @param platform Optionally specify the platform this mapping should apply to.
|
||||
*/
|
||||
public void addCustomMapping(DbType type, String columnDefinition, Platform platform) {
|
||||
customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition, platform));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom type mapping that applies to all platforms.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set the default mapping for BigDecimal/decimal
|
||||
* serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
|
||||
*
|
||||
* // set the default mapping for String/varchar
|
||||
* serverConfig.addCustomMapping(DbType.VARCHAR, "text");
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param type The DB type this mapping should apply to
|
||||
* @param columnDefinition The column definition that should be used
|
||||
*/
|
||||
public void addCustomMapping(DbType type, String columnDefinition) {
|
||||
customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of custom type mappings.
|
||||
*/
|
||||
public List<CustomDbTypeMapping> getCustomTypeMappings() {
|
||||
return customDbTypeMappings;
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,6 @@ public class DocStoreConfig {
|
||||
if (systemValue != null) {
|
||||
return systemValue;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
@@ -100,6 +99,10 @@ public class DocStoreConfig {
|
||||
* Return true if Ebean should generate mapping files on server startup.
|
||||
*/
|
||||
public boolean isGenerateMapping() {
|
||||
String systemValue = System.getProperty("ebean.docstore.generateMapping");
|
||||
if (systemValue != null) {
|
||||
return Boolean.parseBoolean(systemValue);
|
||||
}
|
||||
return generateMapping;
|
||||
}
|
||||
|
||||
@@ -114,6 +117,10 @@ public class DocStoreConfig {
|
||||
* Return true if the document store should recreate mapped indexes.
|
||||
*/
|
||||
public boolean isDropCreate() {
|
||||
String systemValue = System.getProperty("ebean.docstore.dropCreate");
|
||||
if (systemValue != null) {
|
||||
return Boolean.parseBoolean(systemValue);
|
||||
}
|
||||
return dropCreate;
|
||||
}
|
||||
|
||||
@@ -129,6 +136,10 @@ public class DocStoreConfig {
|
||||
* This is only used if dropCreate is false.
|
||||
*/
|
||||
public boolean isCreate() {
|
||||
String systemValue = System.getProperty("ebean.docstore.create");
|
||||
if (systemValue != null) {
|
||||
return Boolean.parseBoolean(systemValue);
|
||||
}
|
||||
return create;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* A customer Id generator that can be registered with Ebean and
|
||||
* assigned to @Id properties using the name attribute of @GeneratedValue.
|
||||
*/
|
||||
public interface IdGenerator {
|
||||
|
||||
/**
|
||||
* Return the next Id value.
|
||||
*/
|
||||
Object nextValue();
|
||||
|
||||
/**
|
||||
* Return the name of the IdGenerator.
|
||||
* <p>
|
||||
* The name is used to assign the IdGenerator to a property using
|
||||
* <code>@GeneratedValue(name="myGeneratorName")</code>
|
||||
* </p>
|
||||
*/
|
||||
String getName();
|
||||
}
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Built in supported platforms.
|
||||
*/
|
||||
public enum DbPlatformName {
|
||||
public enum Platform {
|
||||
|
||||
/**
|
||||
* Generic base platform configured via properties or code.
|
||||
@@ -16,7 +16,7 @@ public final class PropertyMap implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
|
||||
private final LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* Return properties loaded from test-ebean.properties.
|
||||
@@ -31,6 +31,11 @@ public final class PropertyMap implements Serializable {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ final class PropertyMapLoader {
|
||||
* Load the <code>test-ebean.properties</code>.
|
||||
*/
|
||||
public static PropertyMap loadTestProperties() {
|
||||
if (!PropertyMap.loadTestProperties()) {
|
||||
return new PropertyMap();
|
||||
}
|
||||
return load(null, "test-ebean.properties");
|
||||
}
|
||||
|
||||
@@ -31,7 +34,7 @@ final class PropertyMapLoader {
|
||||
if (fileName == null) {
|
||||
fileName = System.getProperty("ebean.props.file");
|
||||
if (fileName == null) {
|
||||
loadTestProperties = true;
|
||||
loadTestProperties = PropertyMap.loadTestProperties();
|
||||
fileName = "ebean.properties";
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -146,6 +146,6 @@ public final class TableName {
|
||||
* @return true, if is valid
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return name != null && name.length() > 0;
|
||||
return name != null && !name.isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Adds ANSI based OFFSET FETCH NEXT clauses to a SQL query.
|
||||
*/
|
||||
public class BasicSqlAnsiLimiter implements BasicSqlLimiter {
|
||||
|
||||
@Override
|
||||
public String limit(String dbSql, int firstRow, int maxRows) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(50 + dbSql.length());
|
||||
|
||||
sb.append(dbSql);
|
||||
if (firstRow > 0) {
|
||||
sb.append(" ").append("offset");
|
||||
sb.append(" ").append(firstRow).append(" rows");
|
||||
}
|
||||
if (maxRows > 0) {
|
||||
sb.append(" fetch next ").append(maxRows).append(" rows only");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Adds LIMIT OFFSET clauses to a SQL query.
|
||||
*/
|
||||
public class BasicSqlLimitOffset implements BasicSqlLimiter {
|
||||
|
||||
/**
|
||||
* LIMIT keyword.
|
||||
*/
|
||||
private static final String LIMIT = "limit";
|
||||
|
||||
/**
|
||||
* OFFSET keyword.
|
||||
*/
|
||||
private static final String OFFSET = "offset";
|
||||
|
||||
@Override
|
||||
public String limit(String dbSql, int firstRow, int maxRows) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(50 + dbSql.length());
|
||||
|
||||
sb.append(dbSql);
|
||||
|
||||
if (maxRows > 0) {
|
||||
sb.append(" ").append(LIMIT);
|
||||
sb.append(" ").append(maxRows);
|
||||
}
|
||||
if (firstRow > 0) {
|
||||
sb.append(" ").append(OFFSET).append(" ");
|
||||
sb.append(firstRow);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Simple SQL limiter for use with SqlQuery.
|
||||
*/
|
||||
public interface BasicSqlLimiter {
|
||||
|
||||
/**
|
||||
* Add basic offset/limit clause to SqlQuery query.
|
||||
*/
|
||||
String limit(String dbSql, int firstRow, int maxRows);
|
||||
}
|
||||
@@ -24,9 +24,9 @@ public class DB2Platform extends DatabasePlatform {
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
booleanDbType = Types.BOOLEAN;
|
||||
dbTypeMap.put(Types.REAL, new DbType("real"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 15));
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("real"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 15));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,8 +34,8 @@ public class DB2Platform extends DatabasePlatform {
|
||||
* sequence values.
|
||||
*/
|
||||
@Override
|
||||
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be,
|
||||
DataSource ds, String seqName, int batchSize) {
|
||||
public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be,
|
||||
DataSource ds, String seqName, int batchSize) {
|
||||
|
||||
return new DB2SequenceIdGenerator(be, ds, seqName, batchSize);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@ package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.config.CustomDbTypeMapping;
|
||||
import com.avaje.ebean.config.DbTypeConfig;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
import com.avaje.ebean.config.Platform;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
|
||||
@@ -9,6 +13,10 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
@@ -28,12 +36,6 @@ public class DatabasePlatform {
|
||||
*/
|
||||
ROLLBACK,
|
||||
|
||||
/**
|
||||
* Just close the transaction. Valid at READ_COMMITTED isolation and preferred on some Databases
|
||||
* as a performance optimisation.
|
||||
*/
|
||||
CLOSE,
|
||||
|
||||
/**
|
||||
* Commit the transaction
|
||||
*/
|
||||
@@ -66,10 +68,15 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected SqlLimiter sqlLimiter = new LimitOffsetSqlLimiter();
|
||||
|
||||
/**
|
||||
* Limit/offset support for SqlQuery only.
|
||||
*/
|
||||
protected BasicSqlLimiter basicSqlLimiter = new BasicSqlLimitOffset();
|
||||
|
||||
/**
|
||||
* Mapping of JDBC to Database types.
|
||||
*/
|
||||
protected DbTypeMap dbTypeMap = new DbTypeMap();
|
||||
protected DbPlatformTypeMapping dbTypeMap = new DbPlatformTypeMapping();
|
||||
|
||||
/**
|
||||
* Default values for DB columns.
|
||||
@@ -145,11 +152,9 @@ public class DatabasePlatform {
|
||||
protected boolean forwardOnlyHintOnFindIterate;
|
||||
|
||||
/**
|
||||
* Flag set for SQL Server due to lack of support of getGeneratedKeys in
|
||||
* batch mode (meaning for batch inserts you should explicitly turn off
|
||||
* getGeneratedKeys - joy).
|
||||
* By default we use JDBC batch when cascading (except for SQL Server).
|
||||
*/
|
||||
protected boolean disallowBatchOnCascade;
|
||||
protected PersistBatch persistBatchOnCascade = PersistBatch.ALL;
|
||||
|
||||
protected PlatformDdl platformDdl;
|
||||
|
||||
@@ -165,12 +170,53 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected int maxConstraintNameLength = 60;
|
||||
|
||||
protected boolean supportsNativeIlike;
|
||||
|
||||
/**
|
||||
* Instantiates a new database platform.
|
||||
*/
|
||||
public DatabasePlatform() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure UUID Storage etc based on ServerConfig settings.
|
||||
*/
|
||||
public void configure(DbTypeConfig config) {
|
||||
addGeoTypes(config.getGeometrySRID());
|
||||
configureIdType(config.getIdType());
|
||||
dbTypeMap.config(nativeUuidType, config.getDbUuid());
|
||||
for (CustomDbTypeMapping mapping : config.getCustomTypeMappings()) {
|
||||
if (platformMatch(mapping.getPlatform())) {
|
||||
dbTypeMap.put(mapping.getType(), parse(mapping.getColumnDefinition()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void configureIdType(IdType idType) {
|
||||
if (idType != null) {
|
||||
this.dbIdentity.setIdType(idType);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addGeoTypes(int srid) {
|
||||
// default has no geo type support
|
||||
}
|
||||
|
||||
private DbPlatformType parse(String columnDefinition) {
|
||||
return DbPlatformType.parse(columnDefinition);
|
||||
}
|
||||
|
||||
private boolean platformMatch(Platform platform) {
|
||||
return platform == null || platform.name().equalsIgnoreCase(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this matches the given platform.
|
||||
*/
|
||||
public boolean isPlatform(Platform platform) {
|
||||
return platform.name().equalsIgnoreCase(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the DatabasePlatform.
|
||||
* <p>
|
||||
@@ -182,6 +228,13 @@ public class DatabasePlatform {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this database platform supports native ILIKE expression.
|
||||
*/
|
||||
public boolean isSupportsNativeIlike() {
|
||||
return supportsNativeIlike;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum table name length.
|
||||
* <p>
|
||||
@@ -233,7 +286,7 @@ public class DatabasePlatform {
|
||||
* @param seqName the name of the sequence
|
||||
* @param batchSize the number of sequences that should be loaded
|
||||
*/
|
||||
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
|
||||
public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -291,7 +344,7 @@ public class DatabasePlatform {
|
||||
*
|
||||
* @return the db type map
|
||||
*/
|
||||
public DbTypeMap getDbTypeMap() {
|
||||
public DbPlatformTypeMapping getDbTypeMap() {
|
||||
return dbTypeMap;
|
||||
}
|
||||
|
||||
@@ -436,6 +489,13 @@ public class DatabasePlatform {
|
||||
return sqlLimiter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BasicSqlLimiter for limit/offset of SqlQuery queries.
|
||||
*/
|
||||
public BasicSqlLimiter getBasicSqlLimiter() {
|
||||
return basicSqlLimiter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB TRUE literal (from the registered boolean ScalarType)
|
||||
*/
|
||||
@@ -462,7 +522,7 @@ public class DatabasePlatform {
|
||||
*/
|
||||
public String convertQuotedIdentifiers(String dbName) {
|
||||
// Ignore null values e.g. schema name or catalog
|
||||
if (dbName != null && dbName.length() > 0) {
|
||||
if (dbName != null && !dbName.isEmpty()) {
|
||||
if (dbName.charAt(0) == BACK_TICK) {
|
||||
if (dbName.charAt(dbName.length() - 1) == BACK_TICK) {
|
||||
|
||||
@@ -512,14 +572,34 @@ public class DatabasePlatform {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the persistBatchOnCascade setting should be ignored.
|
||||
* <p>
|
||||
* This is primarily for SQL Server which does not support getGeneratedKeys with jdbc batch mode
|
||||
* so can't really be transparently used.
|
||||
* </p>
|
||||
* Return the platform default JDBC batch mode for persist cascade.
|
||||
*/
|
||||
public boolean isDisallowBatchOnCascade() {
|
||||
return disallowBatchOnCascade;
|
||||
public PersistBatch getPersistBatchOnCascade() {
|
||||
return persistBatchOnCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the table exists.
|
||||
*/
|
||||
public boolean tableExists(Connection connection, String catalog, String schema, String table) throws SQLException {
|
||||
|
||||
DatabaseMetaData metaData = connection.getMetaData();
|
||||
ResultSet tables = metaData.getTables(catalog, schema, table, null);
|
||||
try {
|
||||
return tables.next();
|
||||
} finally {
|
||||
close(tables);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the resultSet.
|
||||
*/
|
||||
protected void close(ResultSet resultSet) {
|
||||
try {
|
||||
resultSet.close();
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error closing resultSet", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public class DbDefaultValue {
|
||||
*/
|
||||
public static final String NOW = "now";
|
||||
|
||||
protected Map<String,String> map = new LinkedHashMap<String,String>();
|
||||
protected Map<String,String> map = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* Set the DB now function.
|
||||
|
||||
@@ -6,11 +6,13 @@ package com.avaje.ebean.config.dbplatform;
|
||||
public interface DbHistorySupport {
|
||||
|
||||
/**
|
||||
* Return true if the 'As of' predicate is part of the from clause
|
||||
* (more standard sql2011). So true for Oracle total recall and false
|
||||
* for Postgres and MySql (where we use views and history tables).
|
||||
* Return true if the implementation is SQL2011 standards based.
|
||||
* <p>
|
||||
* Non standards based means we need to add additional predicates into the
|
||||
* JOIN ON clause and add an additional predicate for the base table.
|
||||
* </p>
|
||||
*/
|
||||
boolean isBindWithFromClause();
|
||||
boolean isStandardsBased();
|
||||
|
||||
/**
|
||||
* Return the number of columns bound in a 'As Of' predicate.
|
||||
|
||||
@@ -135,9 +135,9 @@ public class DbIdentity {
|
||||
return supportsSequence ? IdType.SEQUENCE : idType;
|
||||
case IDENTITY:
|
||||
return supportsIdentity ? IdType.IDENTITY : idType;
|
||||
default:
|
||||
return idType;
|
||||
}
|
||||
|
||||
// use the default
|
||||
return idType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Represents a DB type with name, length, precision, and scale.
|
||||
* <p>
|
||||
* The length is for VARCHAR types and precision/scale for DECIMAL types.
|
||||
* </p>
|
||||
*/
|
||||
public class DbPlatformType implements ExtraDbTypes {
|
||||
|
||||
/**
|
||||
* The data type name (VARCHAR, INTEGER ...)
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The default length or precision.
|
||||
*/
|
||||
private final int defaultLength;
|
||||
|
||||
/**
|
||||
* The default scale (decimal).
|
||||
*/
|
||||
private final int defaultScale;
|
||||
|
||||
/**
|
||||
* Set to true if the type should never have a length or scale.
|
||||
*/
|
||||
private final boolean canHaveLength;
|
||||
|
||||
/**
|
||||
* Parse a type definition into a DbPlatformType.
|
||||
* <p>
|
||||
* e.g. "decimal(18,6)"
|
||||
* e.g. "text"
|
||||
* </p>
|
||||
*/
|
||||
public static DbPlatformType parse(String columnDefinition) {
|
||||
return DbPlatformTypeParser.parse(columnDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with no length or scale.
|
||||
*/
|
||||
public DbPlatformType(String name) {
|
||||
this(name, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a given length.
|
||||
*/
|
||||
public DbPlatformType(String name, int defaultLength) {
|
||||
this(name, defaultLength, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for Decimal with precision and scale.
|
||||
*/
|
||||
public DbPlatformType(String name, int defaultPrecision, int defaultScale) {
|
||||
this.name = name;
|
||||
this.defaultLength = defaultPrecision;
|
||||
this.defaultScale = defaultScale;
|
||||
this.canHaveLength = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use with canHaveLength=false for types that should never have a length.
|
||||
*
|
||||
* @param name
|
||||
* the type name
|
||||
* @param canHaveLength
|
||||
* set this to false for type that should never have a length
|
||||
*/
|
||||
public DbPlatformType(String name, boolean canHaveLength) {
|
||||
this.name = name;
|
||||
this.defaultLength = 0;
|
||||
this.defaultScale = 0;
|
||||
this.canHaveLength = canHaveLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default length/precision.
|
||||
*/
|
||||
public int getDefaultLength() {
|
||||
return defaultLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default scale.
|
||||
*/
|
||||
public int getDefaultScale() {
|
||||
return defaultScale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for a specific property that incorporates the name, length,
|
||||
* precision and scale.
|
||||
* <p>
|
||||
* The deployLength and deployScale are for the property we are rendering the
|
||||
* DB type for.
|
||||
* </p>
|
||||
*
|
||||
* @param deployLength
|
||||
* the length or precision defined by deployment on a specific
|
||||
* property.
|
||||
* @param deployScale
|
||||
* the scale defined by deployment on a specific property.
|
||||
*/
|
||||
public String renderType(int deployLength, int deployScale) {
|
||||
return renderType(deployLength, deployScale, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the type defining strict mode.
|
||||
* <p>
|
||||
* If strict mode if OFF then this will render with a scale value even if
|
||||
* that is not strictly supported. The reason for supporting this is to enable
|
||||
* use to use types like jsonb(200) as a "logical" type that maps to JSONB for
|
||||
* Postgres and VARCHAR(200) for other databases.
|
||||
* </p>
|
||||
*/
|
||||
public String renderType(int deployLength, int deployScale, boolean strict) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(name);
|
||||
|
||||
if (canHaveLength || !strict) {
|
||||
// see if there is a precision/scale to add (or not)
|
||||
int len = deployLength != 0 ? deployLength : defaultLength;
|
||||
if (len > 0) {
|
||||
sb.append("(");
|
||||
sb.append(len);
|
||||
int scale = deployScale != 0 ? deployScale : defaultScale;
|
||||
if (scale > 0) {
|
||||
sb.append(",");
|
||||
sb.append(scale);
|
||||
}
|
||||
sb.append(")");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of the type with a new default length.
|
||||
*/
|
||||
public DbPlatformType withLength(int defaultLength) {
|
||||
return new DbPlatformType(name, defaultLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Helper to reverse lookup a DbType given the name or JDBC int value.
|
||||
*/
|
||||
class DbPlatformTypeLookup {
|
||||
|
||||
/**
|
||||
* A map to lookup the type by name.
|
||||
*/
|
||||
private Map<String, DbType> nameLookup = new HashMap<>();
|
||||
|
||||
/**
|
||||
* A map to lookup the type by JDBC int value.
|
||||
*/
|
||||
private Map<Integer, DbType> idLookup = new HashMap<>();
|
||||
|
||||
DbPlatformTypeLookup() {
|
||||
addAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DbType for the given name.
|
||||
*/
|
||||
DbType byName(String name) {
|
||||
return nameLookup.get(name.trim().toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DbType for the given name.
|
||||
*/
|
||||
DbType byId(int jdbcId) {
|
||||
return idLookup.get(jdbcId);
|
||||
}
|
||||
|
||||
private void addAll() {
|
||||
// Extra mapping for Float and Varchar2
|
||||
add("FLOAT", DbType.REAL);
|
||||
add("VARCHAR2", DbType.VARCHAR);
|
||||
for (DbType type : DbType.values()) {
|
||||
add(type.name(), type);
|
||||
}
|
||||
}
|
||||
|
||||
private void add(String name, DbType dbType) {
|
||||
nameLookup.put(name, dbType);
|
||||
idLookup.put(dbType.id(), dbType);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Used to map bean property types to DB specific types for DDL generation.
|
||||
*/
|
||||
public class DbPlatformTypeMapping {
|
||||
|
||||
private static DbPlatformTypeLookup lookup = new DbPlatformTypeLookup();
|
||||
|
||||
private static final DbPlatformType UUID_NATIVE = new DbPlatformType("uuid", false);
|
||||
private static final DbPlatformType UUID_PLACEHOLDER = new DbPlatformType("uuidPlaceholder");
|
||||
private static final DbPlatformType JSON_CLOB_PLACEHOLDER = new DbPlatformType("jsonClobPlaceholder");
|
||||
private static final DbPlatformType JSON_BLOB_PLACEHOLDER = new DbPlatformType("jsonBlobPlaceholder");
|
||||
private static final DbPlatformType JSON_VARCHAR_PLACEHOLDER = new DbPlatformType("jsonVarcharPlaceholder");
|
||||
|
||||
private static final DbPlatformType POINT = new DbPlatformType("point");
|
||||
private static final DbPlatformType POLYGON = new DbPlatformType("polygon");
|
||||
private static final DbPlatformType LINESTRING = new DbPlatformType("linestring");
|
||||
private static final DbPlatformType MULTIPOINT = new DbPlatformType("multipoint");
|
||||
private static final DbPlatformType MULTILINESTRING = new DbPlatformType("multilinestring");
|
||||
private static final DbPlatformType MULTIPOLYGON = new DbPlatformType("multipolygon");
|
||||
|
||||
private final Map<DbType, DbPlatformType> typeMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Return the DbTypeMap with standard (not platform specific) types.
|
||||
* <p>
|
||||
* This has some extended JSON types (JSON, JSONB, JSONVarchar, JSONClob, JSONBlob).
|
||||
* These types get translated to specific database platform types during DDL generation.
|
||||
*/
|
||||
public static DbPlatformTypeMapping logicalTypes() {
|
||||
return new DbPlatformTypeMapping(true);
|
||||
}
|
||||
|
||||
public DbPlatformTypeMapping() {
|
||||
loadDefaults(false);
|
||||
}
|
||||
|
||||
private DbPlatformTypeMapping(boolean logicalTypes) {
|
||||
loadDefaults(logicalTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the standard types. These can be overridden by DB specific platform.
|
||||
*/
|
||||
private void loadDefaults(boolean logicalTypes) {
|
||||
|
||||
put(DbType.BOOLEAN);
|
||||
put(DbType.BIT);
|
||||
put(DbType.INTEGER);
|
||||
put(DbType.BIGINT);
|
||||
put(DbType.DOUBLE);
|
||||
put(DbType.SMALLINT);
|
||||
put(DbType.TINYINT);
|
||||
put(DbType.BLOB);
|
||||
put(DbType.CLOB);
|
||||
put(DbType.ARRAY);
|
||||
put(DbType.DATE);
|
||||
put(DbType.TIME);
|
||||
put(DbType.TIMESTAMP);
|
||||
put(DbType.LONGVARBINARY);
|
||||
put(DbType.LONGVARCHAR);
|
||||
// most commonly real maps to db float
|
||||
put(DbType.REAL, new DbPlatformType("float"));
|
||||
|
||||
put(DbType.POINT, POINT);
|
||||
put(DbType.POLYGON, POLYGON);
|
||||
put(DbType.LINESTRING, LINESTRING);
|
||||
put(DbType.MULTIPOINT, MULTIPOINT);
|
||||
put(DbType.MULTILINESTRING, MULTILINESTRING);
|
||||
put(DbType.MULTIPOLYGON, MULTIPOLYGON);
|
||||
|
||||
if (logicalTypes) {
|
||||
// keep it logical for 2 layer DDL generation
|
||||
put(DbType.VARCHAR, new DbPlatformType("varchar"));
|
||||
put(DbType.DECIMAL, new DbPlatformType("decimal"));
|
||||
put(DbType.VARBINARY, new DbPlatformType("varbinary"));
|
||||
put(DbType.BINARY, new DbPlatformType("binary"));
|
||||
put(DbType.CHAR, new DbPlatformType("char"));
|
||||
|
||||
put(DbType.HSTORE, new DbPlatformType("hstore", false));
|
||||
put(DbType.JSON, new DbPlatformType("json", false));
|
||||
put(DbType.JSONB, new DbPlatformType("jsonb", false));
|
||||
put(DbType.JSONCLOB, new DbPlatformType("jsonclob"));
|
||||
put(DbType.JSONBLOB, new DbPlatformType("jsonblob"));
|
||||
put(DbType.JSONVARCHAR, new DbPlatformType("jsonvarchar", 1000));
|
||||
put(DbType.UUID, UUID_NATIVE);
|
||||
|
||||
} else {
|
||||
put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
|
||||
put(DbType.DECIMAL, new DbPlatformType("decimal", 38));
|
||||
put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
|
||||
put(DbType.BINARY, new DbPlatformType("binary", 255));
|
||||
put(DbType.CHAR, new DbPlatformType("char", 1));
|
||||
|
||||
put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON
|
||||
put(DbType.JSONB, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSONB
|
||||
put(DbType.JSONCLOB, JSON_CLOB_PLACEHOLDER);
|
||||
put(DbType.JSONBLOB, JSON_BLOB_PLACEHOLDER);
|
||||
put(DbType.JSONVARCHAR, JSON_VARCHAR_PLACEHOLDER);
|
||||
// use reasonable default of varchar(40) - ideally set via DatabasePlatform.configure(DbTypeConfig)
|
||||
put(DbType.UUID, get(DbType.VARCHAR).withLength(40));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the platform specific DbType given the standard sql type name.
|
||||
*/
|
||||
public DbPlatformType lookup(String name, boolean withScale) {
|
||||
|
||||
DbType type = lookup.byName(name);
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Unknown type [" + name + "] - not standard sql type");
|
||||
}
|
||||
// handle JSON types mapped to clob, blob and varchar
|
||||
switch (type) {
|
||||
case JSONBLOB:
|
||||
return get(DbType.BLOB);
|
||||
case JSONCLOB:
|
||||
return get(DbType.CLOB);
|
||||
case JSONVARCHAR:
|
||||
return get(DbType.VARCHAR);
|
||||
case JSON:
|
||||
return getJsonType(DbType.JSON, withScale);
|
||||
case JSONB:
|
||||
return getJsonType(DbType.JSONB, withScale);
|
||||
default:
|
||||
return get(type);
|
||||
}
|
||||
}
|
||||
|
||||
private DbPlatformType getJsonType(DbType type, boolean withScale) {
|
||||
|
||||
DbPlatformType dbType = get(type);
|
||||
if (dbType == JSON_CLOB_PLACEHOLDER) {
|
||||
// if we have scale that implies this maps to varchar
|
||||
return withScale ? get(DbType.VARCHAR) : get(DbType.CLOB);
|
||||
}
|
||||
if (dbType == JSON_BLOB_PLACEHOLDER) {
|
||||
return get(DbType.BLOB);
|
||||
}
|
||||
if (dbType == JSON_VARCHAR_PLACEHOLDER) {
|
||||
return get(DbType.VARCHAR);
|
||||
}
|
||||
// Postgres has specific type
|
||||
return get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the type for a given JDBC type.
|
||||
*/
|
||||
private void put(DbType type) {
|
||||
typeMap.put(type, type.createPlatformType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the type for a given JDBC type.
|
||||
*/
|
||||
public void put(DbType type, DbPlatformType platformType) {
|
||||
typeMap.put(type, platformType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for a given jdbc type.
|
||||
*/
|
||||
public DbPlatformType get(int jdbcType) {
|
||||
return get(lookup.byId(jdbcType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for a given jdbc type.
|
||||
*/
|
||||
public DbPlatformType get(DbType dbType) {
|
||||
return typeMap.get(dbType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the UUID appropriately based on native DB support and ServerConfig.DbUuid.
|
||||
*/
|
||||
public void config(boolean nativeUuidType, ServerConfig.DbUuid dbUuid) {
|
||||
if (nativeUuidType && dbUuid.useNativeType()) {
|
||||
put(DbType.UUID, UUID_NATIVE);
|
||||
} else if (dbUuid.useBinary()) {
|
||||
put(DbType.UUID, get(DbType.BINARY).withLength(16));
|
||||
} else {
|
||||
put(DbType.UUID, get(DbType.VARCHAR).withLength(40));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Parse raw column definitions into DbPlatformType like "decimal(18,6)" and "varchar(20) and "json".
|
||||
*/
|
||||
class DbPlatformTypeParser {
|
||||
|
||||
/**
|
||||
* Parse the column definition and return the DbPlatformType.
|
||||
*/
|
||||
static DbPlatformType parse(String columnDefinition) {
|
||||
|
||||
columnDefinition = columnDefinition.trim();
|
||||
|
||||
int openPos = columnDefinition.indexOf('(');
|
||||
if (openPos == -1) {
|
||||
return new DbPlatformType(columnDefinition, false);
|
||||
}
|
||||
int closePos = columnDefinition.indexOf(')', openPos);
|
||||
if (closePos == -1) {
|
||||
return new DbPlatformType(columnDefinition, false);
|
||||
}
|
||||
try {
|
||||
int commaPos = columnDefinition.indexOf(',', openPos);
|
||||
if (commaPos > -1) {
|
||||
String type = columnDefinition.substring(0, openPos);
|
||||
int scale = Integer.parseInt(columnDefinition.substring(openPos + 1, commaPos));
|
||||
int precision = Integer.parseInt(columnDefinition.substring(commaPos + 1, closePos));
|
||||
return new DbPlatformType(type, scale, precision);
|
||||
|
||||
} else {
|
||||
String type = columnDefinition.substring(0, openPos);
|
||||
int scale = Integer.parseInt(columnDefinition.substring(openPos + 1, closePos));
|
||||
return new DbPlatformType(type, scale);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
return new DbPlatformType(columnDefinition, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,8 @@ package com.avaje.ebean.config.dbplatform;
|
||||
*/
|
||||
public abstract class DbStandardHistorySupport implements DbHistorySupport {
|
||||
|
||||
/**
|
||||
* Return true as with sql2011 the 'as of timestamp' clause included in from or join clause.
|
||||
*/
|
||||
@Override
|
||||
public boolean isBindWithFromClause() {
|
||||
public boolean isStandardsBased() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user