mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
276
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46f3b74b38 | ||
|
|
df51ccd2c4 | ||
|
|
730d43c008 | ||
|
|
81c2c804a6 | ||
|
|
533be356f2 | ||
|
|
589191f3f4 | ||
|
|
0e65efea57 | ||
|
|
be66872249 | ||
|
|
85a0354d42 | ||
|
|
0b8613fd4c | ||
|
|
e734c0010c | ||
|
|
e08333ef26 | ||
|
|
4a3eabbd6b | ||
|
|
ae68d41519 | ||
|
|
722692d934 | ||
|
|
21a3f322e1 | ||
|
|
0d175557b0 | ||
|
|
57ccd19fe6 | ||
|
|
9674711516 | ||
|
|
9155716752 | ||
|
|
d7d8c3e651 | ||
|
|
16f6f2ee7f | ||
|
|
fea6dfd62b | ||
|
|
464ed4322e | ||
|
|
c3f556f0dc | ||
|
|
ba6810891e | ||
|
|
c530883e5e | ||
|
|
06542b031e | ||
|
|
4b5365e708 | ||
|
|
1d471fee92 | ||
|
|
3825dea00a | ||
|
|
3fd130ac4c | ||
|
|
196645e7a2 | ||
|
|
f5459920e9 | ||
|
|
ee6452cfb0 | ||
|
|
ad7e18561b | ||
|
|
c640524bfc | ||
|
|
fea840c859 | ||
|
|
bb7df71391 | ||
|
|
cb6f0335b1 | ||
|
|
762899ef10 | ||
|
|
848d4f031e | ||
|
|
481f828507 | ||
|
|
b3d0c21a80 | ||
|
|
a115cdf095 | ||
|
|
410e9d475b | ||
|
|
462385c7d0 | ||
|
|
3655e2c6f8 | ||
|
|
318f6ae3f5 | ||
|
|
c63acad7e0 | ||
|
|
6dba4a3d28 | ||
|
|
ecf1e53616 | ||
|
|
0ff9a00427 | ||
|
|
725ff8dc58 | ||
|
|
a780dc133e | ||
|
|
b111fcfecc | ||
|
|
114693b7cd | ||
|
|
5a39dcb39c | ||
|
|
b04f887bc3 | ||
|
|
5c38561049 | ||
|
|
f40eb011c3 | ||
|
|
a08cf548e7 | ||
|
|
f12f0d7f7a | ||
|
|
0c53efcbbc | ||
|
|
1aeed8ad12 | ||
|
|
bcb136b692 | ||
|
|
8b670fd615 | ||
|
|
970bc8e973 | ||
|
|
007b06e9db | ||
|
|
4513dbf29d | ||
|
|
53bcc62a0c | ||
|
|
858c55c978 | ||
|
|
cedba089e1 | ||
|
|
cbf7811f7c | ||
|
|
ea13b322ca | ||
|
|
486a8cf1c0 | ||
|
|
bfe46432da | ||
|
|
272eae5f22 | ||
|
|
502104eba8 | ||
|
|
fa45c79bd2 | ||
|
|
ee4d1bf866 | ||
|
|
dcf7b60d37 | ||
|
|
0663a97941 | ||
|
|
f31ab4d6a8 | ||
|
|
f77388738b | ||
|
|
945175c533 | ||
|
|
7d37c6cfd8 | ||
|
|
496672b394 | ||
|
|
1ffe359573 | ||
|
|
23cd9b6a93 | ||
|
|
333ac8edd9 | ||
|
|
081cb20260 | ||
|
|
53f1da32be | ||
|
|
5544a2cc3e | ||
|
|
84c3008db1 | ||
|
|
d949d4d6a2 | ||
|
|
03669dc307 | ||
|
|
2a8fad7364 | ||
|
|
e62db11f01 | ||
|
|
8c8f2b95da | ||
|
|
576eb01187 | ||
|
|
8b18b2a20e | ||
|
|
f5c12a916d | ||
|
|
2f8a99c304 | ||
|
|
cd9a43c3ab | ||
|
|
f251ca5431 | ||
|
|
2c44c80f65 | ||
|
|
d9efeac0a1 | ||
|
|
f4a7d0b6ad | ||
|
|
bc5db1e46a | ||
|
|
8743148238 | ||
|
|
68db6723d0 | ||
|
|
9b1fa43792 | ||
|
|
5f2454831e | ||
|
|
140178bb47 | ||
|
|
f95b4b5c4b | ||
|
|
d3b3a79342 | ||
|
|
52398317bc | ||
|
|
7f2e4f54ff | ||
|
|
9f19ed5376 | ||
|
|
d49a7c415f | ||
|
|
8ffc9ede85 | ||
|
|
eba521563a | ||
|
|
ed71e106df | ||
|
|
050ae49f6b | ||
|
|
d5d9a897ae | ||
|
|
ddf200ffdd | ||
|
|
7fa5e2aa8c | ||
|
|
8bfae9deef | ||
|
|
e6c9f151c1 | ||
|
|
30a0935300 | ||
|
|
b4182d4519 | ||
|
|
93cc0399f1 | ||
|
|
5404dab5a3 | ||
|
|
d70da1d805 | ||
|
|
2225d5b7e8 | ||
|
|
270369bd65 | ||
|
|
a932d61a94 | ||
|
|
24b08663af | ||
|
|
bb6c9c84ba | ||
|
|
a1e185b0f6 | ||
|
|
e2a467ca5a | ||
|
|
4b28933298 | ||
|
|
6077acf134 | ||
|
|
8a4ffd21ab | ||
|
|
d1314124af | ||
|
|
36f018b6aa | ||
|
|
87ccb6e333 | ||
|
|
3432c365f6 | ||
|
|
b7d5aa344f | ||
|
|
7e768623e4 | ||
|
|
73ab2ee1fe | ||
|
|
122fed448c | ||
|
|
6e52bee91f | ||
|
|
cc26afad13 | ||
|
|
bf20449fb5 | ||
|
|
6af5fae8e9 | ||
|
|
e26a38ecaa | ||
|
|
1cdf68f1c0 | ||
|
|
2923dd1d96 | ||
|
|
9067508e1d | ||
|
|
385cc76e34 | ||
|
|
c14cb4b85e | ||
|
|
52644647e4 | ||
|
|
3bf9dd6743 | ||
|
|
aececa2199 | ||
|
|
b4e22a4ca7 | ||
|
|
9b8b4414c4 | ||
|
|
b8fd2c7a02 | ||
|
|
a94f5d74ca | ||
|
|
3829613c37 | ||
|
|
0762eaf0ab | ||
|
|
7fbdab6220 | ||
|
|
cf4d45befb | ||
|
|
dcd81a857d | ||
|
|
0cac723eac | ||
|
|
c6ba4d8155 | ||
|
|
201958f38c | ||
|
|
9326c9c79e | ||
|
|
1042fdb280 | ||
|
|
197056dbc5 | ||
|
|
895b5ee4ff | ||
|
|
c839fe6520 | ||
|
|
2678f85506 | ||
|
|
2b1b4af7a2 | ||
|
|
4218b8a2e8 | ||
|
|
fe7d73a4a4 | ||
|
|
81e86b07e3 | ||
|
|
910c04e373 | ||
|
|
205f1f5e89 | ||
|
|
a1a6d2b725 | ||
|
|
30da589ea0 | ||
|
|
c66e9547e1 | ||
|
|
73990e3fb7 | ||
|
|
f7920de3c2 | ||
|
|
3dd5069f5a | ||
|
|
1d363776ec | ||
|
|
c512eb564d | ||
|
|
7f332e91ff | ||
|
|
8e9d644bc6 | ||
|
|
fa5ce9cbba | ||
|
|
b7905daeb5 | ||
|
|
9da7c9468e | ||
|
|
9eee224e03 | ||
|
|
906d5f04ad | ||
|
|
654c3f7f67 | ||
|
|
c61e6b04a2 | ||
|
|
f893653090 | ||
|
|
579c1efcf6 | ||
|
|
662f9cdeb3 | ||
|
|
b4782425f8 | ||
|
|
2648423930 | ||
|
|
b62cea5073 | ||
|
|
c10ad11b8b | ||
|
|
4aa8a0dc63 | ||
|
|
e4569f9362 | ||
|
|
ed83bababc | ||
|
|
b746c83ed7 | ||
|
|
8e45462c2c | ||
|
|
9fdb375229 | ||
|
|
7e6d059ef1 | ||
|
|
856a3a6fdd | ||
|
|
f94c3e81e5 | ||
|
|
4bf9e2b18e | ||
|
|
112de29964 | ||
|
|
c5d761076a | ||
|
|
4bedefa494 | ||
|
|
a5e3a70921 | ||
|
|
f6f4368048 | ||
|
|
e700f1c83c | ||
|
|
dc5ac02952 | ||
|
|
b89371acd1 | ||
|
|
6c88325dad | ||
|
|
ecec966a85 | ||
|
|
c46ac04c0a | ||
|
|
25e6d05542 | ||
|
|
d3ead5d2f9 | ||
|
|
28a70fa550 | ||
|
|
cf31830cbc | ||
|
|
b4105ab5d0 | ||
|
|
1bb2b1318e | ||
|
|
65fa1c056b | ||
|
|
242945aa18 | ||
|
|
5e77be6e6d | ||
|
|
8c0d6b1a72 | ||
|
|
86436ac3ac | ||
|
|
ae228d6b0e | ||
|
|
410d1a9b37 | ||
|
|
f667a73dc1 | ||
|
|
4509c6b1ed | ||
|
|
d32559baf4 | ||
|
|
2639e799c5 | ||
|
|
46c66b7169 | ||
|
|
30ae435f33 | ||
|
|
4f4743807c | ||
|
|
7b7a492241 | ||
|
|
4af8e53315 | ||
|
|
1c6fa575f2 | ||
|
|
2430404e1f | ||
|
|
d433e0ea46 | ||
|
|
42591a5a87 | ||
|
|
65a62bf683 | ||
|
|
3e3f3c35e7 | ||
|
|
f4db7ca0bb | ||
|
|
b0e487cfbd | ||
|
|
23fd29ddf1 | ||
|
|
f21cac5d4f | ||
|
|
c2e5619f70 | ||
|
|
18e0ff7067 | ||
|
|
4119c02f0d | ||
|
|
8985d37aed | ||
|
|
23e035894f | ||
|
|
32b8fd0e26 | ||
|
|
4971db54c8 | ||
|
|
e417b3cde2 | ||
|
|
d23ca31e42 |
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
custom: https://ebean.io/sponsors
|
||||
@@ -3,6 +3,7 @@ sudo: required
|
||||
language: java
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
- openjdk11
|
||||
|
||||
git:
|
||||
depth: 3
|
||||
|
||||
@@ -1,6 +1,34 @@
|
||||
[](https://travis-ci.org/ebean-orm/ebean)
|
||||
[](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean)
|
||||
|
||||
# Sponsors
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.foconis.de/" target="_blank">
|
||||
<img width="222px" src="https://www.foconis.de/templates/yootheme/cache/foconis_logo_322-709da1de.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.payintech.com/" target="_blank">
|
||||
<img width="222px" src="https://ebean.io/images/sponsor_PayinTech-logo-noir.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.premium-minds.com" target="_blank">
|
||||
<img width="222px" src="https://ebean.io/images/logo-med-principal.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://timerbee.de" target="_blank">
|
||||
<img width="222px" src="https://ebean.io/images/logo-timerbee.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
# Need help?
|
||||
Post questions or issues to the Ebean google group - https://groups.google.com/forum/#!forum/ebean
|
||||
|
||||
|
||||
@@ -9,20 +9,21 @@
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>11.36.3</version>
|
||||
<version>11.44.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
<url>http://ebean-orm.github.io/</url>
|
||||
|
||||
<properties>
|
||||
<jackson-core.version>2.9.5</jackson-core.version>
|
||||
<jackson-core.version>2.9.9</jackson-core.version>
|
||||
<jackson-databind.version>2.9.9.2</jackson-databind.version>
|
||||
<snakeyaml.version>1.21</snakeyaml.version>
|
||||
</properties>
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-11.36.3</tag>
|
||||
<tag>ebean-11.44.1</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
@@ -117,7 +118,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>4.7</version>
|
||||
<version>4.12</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -129,7 +130,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-datasource</artifactId>
|
||||
<version>4.5.1</version>
|
||||
<version>4.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -141,7 +142,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>11.14.1</version>
|
||||
<version>11.20.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -161,7 +162,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson-core.version}</version>
|
||||
<version>${jackson-databind.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -219,17 +220,24 @@
|
||||
|
||||
<!-- Test scope -->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.nuodb.jdbc</groupId>
|
||||
<artifactId>nuodb-jdbc</artifactId>
|
||||
<version>20.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>oracle</groupId>-->
|
||||
<!--<artifactId>oracle-jdbc</artifactId>-->
|
||||
<!--<version>7.0</version>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--<groupId>oracle</groupId>-->
|
||||
<!--<artifactId>oracle-jdbc</artifactId>-->
|
||||
<!--<version>7.0</version>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-docker-run</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<groupId>io.ebean.test</groupId>
|
||||
<artifactId>ebean-test-docker</artifactId>
|
||||
<version>2.10.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -240,20 +248,6 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-agentloader</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-agent</artifactId>
|
||||
<version>11.27.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Provided scope so that the H2HistoryTrigger can live in Ebean core
|
||||
and not require a separate module for it -->
|
||||
<dependency>
|
||||
@@ -280,15 +274,14 @@
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
<version>7.2.0.jre8</version>
|
||||
<version>7.2.2.jre8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<!-- Do not upgrade to 6.0.6: https://bugs.mysql.com/bug.php?id=82896 -->
|
||||
<version>5.1.43</version>
|
||||
<version>8.0.17</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -299,6 +292,13 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.composite</groupId>
|
||||
<artifactId>avaje-composite-testing</artifactId>
|
||||
@@ -330,7 +330,7 @@
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>11.35.1</version>
|
||||
<version>11.44.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
@@ -393,7 +393,7 @@
|
||||
<overview>src/main/java/io/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
<excludePackageNames>io.ebeaninternal.*:io.ebeanservice:io.ebean.common:io.ebean.bean:io.ebean.service:io.ebean.metric:io.ebean.util:io.ebean.config.properties:io.ebean.config.dbplatform*</excludePackageNames>
|
||||
<excludePackageNames>io.ebeaninternal.*:io.ebeanservice:io.ebean.common:io.ebean.bean:io.ebean.service:io.ebean.metric:io.ebean.util:io.ebean.config.properties:io.ebean.config.dbplatform</excludePackageNames>
|
||||
<docletArtifact>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>pygments-doclet</artifactId>
|
||||
|
||||
@@ -69,8 +69,8 @@ public enum CacheMode {
|
||||
*/
|
||||
GET(true, false);
|
||||
|
||||
private boolean get;
|
||||
private boolean put;
|
||||
private final boolean get;
|
||||
private final boolean put;
|
||||
|
||||
CacheMode(boolean get, boolean put) {
|
||||
this.get = get;
|
||||
|
||||
@@ -1237,4 +1237,18 @@ public class DB {
|
||||
return getDefault().json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate the base tables for the given bean types.
|
||||
*/
|
||||
public static void truncate(Class<?>... types) {
|
||||
getDefault().truncate(types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate the given tables.
|
||||
*/
|
||||
public static void truncate(String... tables) {
|
||||
getDefault().truncate(tables);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1580,4 +1580,15 @@ public interface Database {
|
||||
* </p>
|
||||
*/
|
||||
<T> Set<String> validateQuery(Query<T> query);
|
||||
|
||||
/**
|
||||
* Truncate all the given tables.
|
||||
*/
|
||||
void truncate(String... tables);
|
||||
|
||||
/**
|
||||
* Truncate the base tables for the given bean types.
|
||||
*/
|
||||
void truncate(Class<?>... tables);
|
||||
|
||||
}
|
||||
|
||||
@@ -109,6 +109,12 @@ public interface DtoQuery<T> {
|
||||
*/
|
||||
DtoQuery<T> setLabel(String label);
|
||||
|
||||
/**
|
||||
* Set the profile location of this query. This is used to relate query execution metrics
|
||||
* back to a location like a specific line of code.
|
||||
*/
|
||||
DtoQuery<T> setProfileLocation(ProfileLocation profileLocation);
|
||||
|
||||
/**
|
||||
* Set a timeout on this query.
|
||||
* <p>
|
||||
|
||||
@@ -536,4 +536,12 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
<T> Junction<T> junction(Junction.Type type, Query<T> query, ExpressionList<T> parent);
|
||||
|
||||
/**
|
||||
* Add the expressions to the given expression list.
|
||||
*
|
||||
* @param where The expression list to add the expressions to
|
||||
* @param expressions The expressions that are parsed
|
||||
* @param params Bind parameters to match ? or ?1 bind positions.
|
||||
*/
|
||||
<T> void where(ExpressionList<T> where, String expressions, Object[] params);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import io.ebean.search.TextSimple;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -186,6 +187,16 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Query<T> setIncludeSoftDeletes();
|
||||
|
||||
/**
|
||||
* Execute the query using the given transaction.
|
||||
*/
|
||||
Query<T> usingTransaction(Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query using the given connection.
|
||||
*/
|
||||
Query<T> usingConnection(Connection connection);
|
||||
|
||||
/**
|
||||
* Execute as a delete query deleting the 'root level' beans that match the predicates
|
||||
* in the query.
|
||||
@@ -478,7 +489,26 @@ public interface ExpressionList<T> {
|
||||
* Add some filter predicate expressions to the many property.
|
||||
*/
|
||||
@Nonnull
|
||||
ExpressionList<T> filterMany(String prop);
|
||||
ExpressionList<T> filterMany(String manyProperty);
|
||||
|
||||
/**
|
||||
* Add filter expressions to the many property.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* DB.find(Customer.class)
|
||||
* .where()
|
||||
* .eq("name", "Rob")
|
||||
* .filterMany("orders", "status = ?", Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param manyProperty The many property
|
||||
* @param expressions Filter expressions with and, or and ? or ?1 type bind parameters
|
||||
* @param params Bind parameters used in the expressions
|
||||
*/
|
||||
Query<T> filterMany(String manyProperty, String expressions, Object... params);
|
||||
|
||||
/**
|
||||
* Specify specific properties to fetch on the main/root bean (aka partial
|
||||
@@ -652,6 +682,14 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> where();
|
||||
|
||||
/**
|
||||
* Add the expressions to this expression list.
|
||||
*
|
||||
* @param expressions The expressions that are parsed and added to this expression list
|
||||
* @param params Bind parameters to match ? or ?1 bind positions.
|
||||
*/
|
||||
ExpressionList<T> where(String expressions, Object... params);
|
||||
|
||||
/**
|
||||
* Path exists - for the given path in a JSON document.
|
||||
* <pre>{@code
|
||||
@@ -820,9 +858,9 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> inRange(String propertyName, Object value1, Object value2);
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
ExpressionList<T> between(String propertyName, Object value1, Object value2);
|
||||
|
||||
/**
|
||||
@@ -1316,7 +1354,7 @@ public interface ExpressionList<T> {
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Note that we need to cast the Postgres array for UUID types like:
|
||||
* Note that we need to cast the Postgres array for UUID types like:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
@@ -1324,7 +1362,7 @@ public interface ExpressionList<T> {
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param raw The raw expression that is typically a subquery
|
||||
* @param raw The raw expression that is typically a subquery
|
||||
* @param values The values which is typically a list or set of id values.
|
||||
*/
|
||||
ExpressionList<T> rawOrEmpty(String raw, Collection<?> values);
|
||||
|
||||
@@ -148,6 +148,8 @@ public class FetchConfig implements Serializable {
|
||||
|
||||
private boolean queryAll;
|
||||
|
||||
private boolean cache;
|
||||
|
||||
/**
|
||||
* Construct the fetch configuration object.
|
||||
*/
|
||||
@@ -188,6 +190,17 @@ public class FetchConfig implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the beans fetching the beans from the L2 bean cache
|
||||
* and using the DB for beans not in the cache.
|
||||
*/
|
||||
public FetchConfig cache() {
|
||||
this.cache = true;
|
||||
this.queryBatchSize = 0;
|
||||
this.queryAll = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
@@ -247,6 +260,13 @@ public class FetchConfig implements Serializable {
|
||||
return queryAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this uses L2 bean cache.
|
||||
*/
|
||||
public boolean isCache() {
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -255,6 +275,7 @@ public class FetchConfig implements Serializable {
|
||||
FetchConfig that = (FetchConfig) o;
|
||||
if (lazyBatchSize != that.lazyBatchSize) return false;
|
||||
if (queryBatchSize != that.queryBatchSize) return false;
|
||||
if (cache != that.cache) return false;
|
||||
return queryAll == that.queryAll;
|
||||
}
|
||||
|
||||
@@ -263,6 +284,7 @@ public class FetchConfig implements Serializable {
|
||||
int result = lazyBatchSize;
|
||||
result = 92821 * result + queryBatchSize;
|
||||
result = 92821 * result + (queryAll ? 1 : 0);
|
||||
result = 92821 * result + (cache ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.service.SpiFetchGroupQuery;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
@@ -111,4 +113,11 @@ public interface FetchGroup<T> {
|
||||
return XServiceProvider.fetchGroupOf(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a query to be used by query beans for constructing FetchGroup.
|
||||
*/
|
||||
static <T> SpiFetchGroupQuery<T> queryFor(Class<T> beanType) {
|
||||
return XServiceProvider.fetchGroupQueryFor(beanType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -67,12 +67,26 @@ public interface FetchGroupBuilder<T> {
|
||||
@Nonnull
|
||||
FetchGroupBuilder<T> fetchQuery(String path);
|
||||
|
||||
/**
|
||||
* Fetch the path including all its properties using L2 cache.
|
||||
* Cache misses fallback to fetchQuery().
|
||||
*/
|
||||
@Nonnull
|
||||
FetchGroupBuilder<T> fetchCache(String path);
|
||||
|
||||
/**
|
||||
* Fetch the path including specified properties using a query join.
|
||||
*/
|
||||
@Nonnull
|
||||
FetchGroupBuilder<T> fetchQuery(String path, String properties);
|
||||
|
||||
/**
|
||||
* Fetch the path including specified properties using L2 cache.
|
||||
* Cache misses fallback to fetchQuery().
|
||||
*/
|
||||
@Nonnull
|
||||
FetchGroupBuilder<T> fetchCache(String path, String properties);
|
||||
|
||||
/**
|
||||
* Fetch the path including all its properties lazily.
|
||||
*/
|
||||
|
||||
@@ -75,6 +75,25 @@ import io.ebean.bean.EntityBean;
|
||||
*/
|
||||
public abstract class Model {
|
||||
|
||||
/**
|
||||
* The name of the database this entity will use, null for the default database.
|
||||
*/
|
||||
private final String _$dbName;
|
||||
|
||||
/**
|
||||
* Create using the default database.
|
||||
*/
|
||||
public Model() {
|
||||
this._$dbName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with a named database (typically not the default database).
|
||||
*/
|
||||
public Model(String dbName) {
|
||||
this._$dbName = dbName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' Database.
|
||||
* <p>
|
||||
@@ -107,17 +126,8 @@ public abstract class Model {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static Database db() {
|
||||
return DB.getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a named Database that is typically different to the default database.
|
||||
*
|
||||
* @param server The name of the Database. If this is null then the default Database is returned.
|
||||
*/
|
||||
public static Database db(String server) {
|
||||
return DB.byName(server);
|
||||
public Database db() {
|
||||
return DB.byName(_$dbName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -245,27 +255,6 @@ public abstract class Model {
|
||||
return db().deletePermanent(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an update using this entity against the specified server.
|
||||
*/
|
||||
public void update(String server) {
|
||||
db(server).update(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an insert using this entity against the specified server.
|
||||
*/
|
||||
public void insert(String server) {
|
||||
db(server).insert(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a delete using this entity against the specified server.
|
||||
*/
|
||||
public boolean delete(String server) {
|
||||
return db(server).delete(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes this entity from the database.
|
||||
*
|
||||
|
||||
@@ -80,7 +80,6 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Add a property with ascending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> asc(String propertyName, String collation) {
|
||||
|
||||
list.add(new Property(propertyName, true, collation));
|
||||
return query;
|
||||
}
|
||||
@@ -89,7 +88,6 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Add a property with descending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> desc(String propertyName) {
|
||||
|
||||
list.add(new Property(propertyName, false));
|
||||
return query;
|
||||
}
|
||||
@@ -98,7 +96,6 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Add a property with descending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> desc(String propertyName, String collation) {
|
||||
|
||||
list.add(new Property(propertyName, false, collation));
|
||||
return query;
|
||||
}
|
||||
@@ -108,7 +105,6 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Return true if the property is known to be contained in the order by clause.
|
||||
*/
|
||||
public boolean containsProperty(String propertyName) {
|
||||
|
||||
for (Property aList : list) {
|
||||
if (propertyName.equals(aList.getProperty())) {
|
||||
return true;
|
||||
@@ -161,10 +157,9 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Return a copy of the OrderBy.
|
||||
*/
|
||||
public OrderBy<T> copy() {
|
||||
|
||||
OrderBy<T> copy = new OrderBy<>();
|
||||
for (Property aList : list) {
|
||||
copy.add(aList.copy());
|
||||
for (Property property : list) {
|
||||
copy.add(property.copy());
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
@@ -241,6 +236,18 @@ public final class OrderBy<T> implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this order by can be used in select clause.
|
||||
*/
|
||||
public boolean supportsSelect() {
|
||||
for (Property property : list) {
|
||||
if (!property.supportsSelect()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A property and its ascending descending order.
|
||||
*/
|
||||
@@ -401,6 +408,12 @@ public final class OrderBy<T> implements Serializable {
|
||||
this.ascending = ascending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support use in select clause if no collation or nulls ordering.
|
||||
*/
|
||||
boolean supportsSelect() {
|
||||
return nulls == null;
|
||||
}
|
||||
}
|
||||
|
||||
private void parse(String orderByClause) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebean;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -500,6 +501,14 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> fetchQuery(String path, String fetchProperties);
|
||||
|
||||
/**
|
||||
* Fetch the path and properties using L2 bean cache.
|
||||
*
|
||||
* @param path The path of the beans we are fetching from L2 cache.
|
||||
* @param fetchProperties The properties that should be loaded.
|
||||
*/
|
||||
Query<T> fetchCache(String path, String fetchProperties);
|
||||
|
||||
/**
|
||||
* Fetch the path and properties lazily (via batch lazy loading).
|
||||
* <p>
|
||||
@@ -586,6 +595,11 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> fetchQuery(String path);
|
||||
|
||||
/**
|
||||
* Fetch the path eagerly using L2 cache.
|
||||
*/
|
||||
Query<T> fetchCache(String path);
|
||||
|
||||
/**
|
||||
* Fetch the path lazily (via batch lazy loading).
|
||||
* <p>
|
||||
@@ -631,6 +645,16 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> apply(FetchPath fetchPath);
|
||||
|
||||
/**
|
||||
* Execute the query using the given transaction.
|
||||
*/
|
||||
Query<T> usingTransaction(Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query using the given connection.
|
||||
*/
|
||||
Query<T> usingConnection(Connection connection);
|
||||
|
||||
/**
|
||||
* Execute the query returning the list of Id's.
|
||||
* <p>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Thrown at SERIALIZABLE isolation level for non-recoverable concurrent conflict.
|
||||
*/
|
||||
public class SerializableConflictException extends OptimisticLockException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Create with a message and cause.
|
||||
*/
|
||||
public SerializableConflictException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.service.SpiFetchGroupQuery;
|
||||
import io.ebean.service.SpiFetchGroupService;
|
||||
import io.ebean.service.SpiProfileLocationFactory;
|
||||
import io.ebean.service.SpiRawSqlService;
|
||||
@@ -71,4 +72,11 @@ class XServiceProvider {
|
||||
static <T> FetchGroupBuilder<T> fetchGroupOf(Class<T> cls) {
|
||||
return fetchGroupService.of(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the FetchGroup Query for building fetch groups via query beans.
|
||||
*/
|
||||
static <T> SpiFetchGroupQuery<T> fetchGroupQueryFor(Class<T> cls) {
|
||||
return fetchGroupService.queryFor(cls);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* A call origin for query execution profiling to collect graph use (for query tuning).
|
||||
*/
|
||||
public interface CallOrigin {
|
||||
|
||||
/**
|
||||
* Return the top element. Typically the top stack element with class and line.
|
||||
*/
|
||||
String getTopElement();
|
||||
|
||||
/**
|
||||
* Return the full description of the call origin.
|
||||
*/
|
||||
String getFullDescription();
|
||||
|
||||
/**
|
||||
* Compute and return an origin key based on the query hash.
|
||||
*/
|
||||
String getOriginKey(int queryHash);
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package io.ebean.bean;
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static io.ebean.util.EncodeB64.enc;
|
||||
|
||||
/**
|
||||
* Represent the call stack (stack trace elements).
|
||||
* <p>
|
||||
@@ -17,15 +19,15 @@ import java.util.Arrays;
|
||||
* Note the call stack is trimmed to remove the common ebean internal elements.
|
||||
* </p>
|
||||
*/
|
||||
public final class CallStack implements Serializable {
|
||||
public final class CallStack implements Serializable, CallOrigin {
|
||||
|
||||
private static final long serialVersionUID = -8590644046907438579L;
|
||||
|
||||
private static final String NEWLINE = "\n";
|
||||
|
||||
private final String zeroHash;
|
||||
private final String pathHash;
|
||||
|
||||
private final StackTraceElement[] callStack;
|
||||
|
||||
private final int hc;
|
||||
|
||||
public CallStack(StackTraceElement[] callStack, int zeroHash, int pathHash) {
|
||||
@@ -37,12 +39,17 @@ public final class CallStack implements Serializable {
|
||||
|
||||
private int computeHashCode() {
|
||||
int hc = 0;
|
||||
for (StackTraceElement aCallStack : callStack) {
|
||||
hc = 92821 * hc + aCallStack.hashCode();
|
||||
for (StackTraceElement element : callStack) {
|
||||
hc = 92821 * hc + element.hashCode();
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return zeroHash + ":" + pathHash + ":" + callStack[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hc;
|
||||
@@ -63,73 +70,29 @@ public final class CallStack implements Serializable {
|
||||
/**
|
||||
* Return the first element of the call stack.
|
||||
*/
|
||||
public StackTraceElement getFirstStackTraceElement() {
|
||||
return callStack[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the call stack.
|
||||
*/
|
||||
public StackTraceElement[] getCallStack() {
|
||||
return callStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash for the first stack element.
|
||||
*/
|
||||
public String getZeroHash() {
|
||||
return zeroHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash for the stack elements (excluding first stack element).
|
||||
*/
|
||||
public String getPathHash() {
|
||||
return pathHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return zeroHash + ":" + pathHash + ":" + callStack[0];
|
||||
public String getTopElement() {
|
||||
return callStack[0].toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the call stack lines appended with the given newLine string.
|
||||
*/
|
||||
public String description(String newLine) {
|
||||
@Override
|
||||
public String getFullDescription() {
|
||||
StringBuilder sb = new StringBuilder(400);
|
||||
for (StackTraceElement aCallStack : callStack) {
|
||||
sb.append(aCallStack.toString()).append(newLine);
|
||||
for (int i = 0; i < callStack.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(NEWLINE);
|
||||
}
|
||||
sb.append(callStack[i].toString());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOriginKey(int queryHash) {
|
||||
return enc(queryHash) + "." + zeroHash + "." + pathHash;
|
||||
}
|
||||
|
||||
private static final int radix = 1 << 6;
|
||||
private static final int mask = radix - 1;
|
||||
|
||||
/**
|
||||
* Convert the integer to unsigned base 64.
|
||||
*/
|
||||
public static String enc(int i) {
|
||||
char[] buf = new char[32];
|
||||
int charPos = 32;
|
||||
do {
|
||||
buf[--charPos] = intToBase64[i & mask];
|
||||
i >>>= 6;
|
||||
} while (i != 0);
|
||||
|
||||
return new String(buf, charPos, (32 - charPos));
|
||||
}
|
||||
|
||||
private static final char intToBase64[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,12 +16,16 @@ public interface EntityBean extends Serializable {
|
||||
/**
|
||||
* Return all the property names in defined order.
|
||||
*/
|
||||
String[] _ebean_getPropertyNames();
|
||||
default String[] _ebean_getPropertyNames() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property name at the given position.
|
||||
*/
|
||||
String _ebean_getPropertyName(int pos);
|
||||
default String _ebean_getPropertyName(int pos) {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the enhancement marker value.
|
||||
@@ -30,28 +34,38 @@ public interface EntityBean extends Serializable {
|
||||
* entity classes are enhanced (specifically not just a super class).
|
||||
* </p>
|
||||
*/
|
||||
String _ebean_getMarker();
|
||||
default String _ebean_getMarker() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new entity bean instance.
|
||||
*/
|
||||
Object _ebean_newInstance();
|
||||
default Object _ebean_newInstance() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated method that sets the loaded state on all the embedded beans on
|
||||
* this entity bean by using EntityBeanIntercept.setEmbeddedLoaded(Object o);
|
||||
*/
|
||||
void _ebean_setEmbeddedLoaded();
|
||||
default void _ebean_setEmbeddedLoaded() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if any embedded beans are new or dirty.
|
||||
*/
|
||||
boolean _ebean_isEmbeddedNewOrDirty();
|
||||
default boolean _ebean_isEmbeddedNewOrDirty() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the intercept for this object.
|
||||
*/
|
||||
EntityBeanIntercept _ebean_getIntercept();
|
||||
default EntityBeanIntercept _ebean_getIntercept() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to _ebean_getIntercept() except it checks to see if the intercept
|
||||
@@ -66,7 +80,9 @@ public interface EntityBean extends Serializable {
|
||||
* frameworks that can't take into account our ebean fields.
|
||||
* </p>
|
||||
*/
|
||||
EntityBeanIntercept _ebean_intercept();
|
||||
default EntityBeanIntercept _ebean_intercept() {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a field of an entity bean of this type.
|
||||
@@ -75,12 +91,16 @@ public interface EntityBean extends Serializable {
|
||||
* on entity beans. That means lazy loading and oldValues creation.
|
||||
* </p>
|
||||
*/
|
||||
void _ebean_setField(int fieldIndex, Object value);
|
||||
default void _ebean_setField(int fieldIndex, Object value) {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field value with interception.
|
||||
*/
|
||||
void _ebean_setFieldIntercept(int fieldIndex, Object value);
|
||||
default void _ebean_setFieldIntercept(int fieldIndex, Object value) {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of a field from an entity bean of this type.
|
||||
@@ -89,11 +109,15 @@ public interface EntityBean extends Serializable {
|
||||
* on entity beans. That means lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
Object _ebean_getField(int fieldIndex);
|
||||
default Object _ebean_getField(int fieldIndex) {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the field value with interception.
|
||||
*/
|
||||
Object _ebean_getFieldIntercept(int fieldIndex);
|
||||
default Object _ebean_getFieldIntercept(int fieldIndex) {
|
||||
throw new NotEnhancedException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -95,13 +95,10 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
private final byte[] flags;
|
||||
|
||||
private boolean fullyLoadedBean;
|
||||
|
||||
private boolean loadedFromCache;
|
||||
private Object[] origValues;
|
||||
|
||||
private Exception[] loadErrors;
|
||||
|
||||
private int lazyLoadProperty = -1;
|
||||
|
||||
private Object ownerId;
|
||||
private int sortOrder;
|
||||
|
||||
@@ -116,6 +113,14 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
this.flags = new byte[owner._ebean_getPropertyNames().length];
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL - Constructor only for use by serialization frameworks.
|
||||
*/
|
||||
public EntityBeanIntercept() {
|
||||
this.owner = null;
|
||||
this.flags = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the 'owning' entity bean.
|
||||
*/
|
||||
@@ -303,6 +308,22 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set true when the bean has been loaded from L2 bean cache.
|
||||
* The effect of this is that we should skip the cache if there
|
||||
* is subsequent lazy loading (bean cache partially populated).
|
||||
*/
|
||||
public void setLoadedFromCache(boolean loadedFromCache) {
|
||||
this.loadedFromCache = loadedFromCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this bean was loaded from L2 bean cache.
|
||||
*/
|
||||
public boolean isLoadedFromCache() {
|
||||
return loadedFromCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the bean should be treated as readOnly. If a setter method
|
||||
* is called when it is readOnly an Exception is thrown.
|
||||
@@ -772,7 +793,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
|
||||
public boolean[] getLoaded() {
|
||||
boolean[] ret= new boolean[flags.length];
|
||||
boolean[] ret = new boolean[flags.length];
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
ret[i] = (flags[i] & FLAG_LOADED_PROP) != 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* This exception is thrown, when the default implementation of EntityBean is not or not properly overwritten by enhancer.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*
|
||||
*/
|
||||
public class NotEnhancedException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Identifies a unique node of an object graph.
|
||||
@@ -85,8 +86,7 @@ public final class ObjectGraphNode implements Serializable {
|
||||
}
|
||||
|
||||
ObjectGraphNode e = (ObjectGraphNode) obj;
|
||||
//noinspection StringEquality
|
||||
return ((e.path == path) || (e.path != null && e.path.equals(path)))
|
||||
return (Objects.equals(e.path, path))
|
||||
&& e.originQueryPoint.equals(originQueryPoint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public final class ObjectGraphOrigin implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 410937765287968708L;
|
||||
|
||||
private final CallStack callStack;
|
||||
private final CallOrigin callOrigin;
|
||||
|
||||
private final String beanType;
|
||||
|
||||
@@ -24,11 +24,11 @@ public final class ObjectGraphOrigin implements Serializable {
|
||||
|
||||
private final String key;
|
||||
|
||||
public ObjectGraphOrigin(int queryHash, CallStack callStack, String beanType) {
|
||||
this.callStack = callStack;
|
||||
public ObjectGraphOrigin(int queryHash, CallOrigin callOrigin, String beanType) {
|
||||
this.callOrigin = callOrigin;
|
||||
this.beanType = beanType;
|
||||
this.queryHash = queryHash;
|
||||
this.key = callStack.getOriginKey(queryHash);
|
||||
this.key = callOrigin.getOriginKey(queryHash);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,22 +49,22 @@ public final class ObjectGraphOrigin implements Serializable {
|
||||
/**
|
||||
* The call stack involved.
|
||||
*/
|
||||
public CallStack getCallStack() {
|
||||
return callStack;
|
||||
public CallOrigin getCallOrigin() {
|
||||
return callOrigin;
|
||||
}
|
||||
|
||||
public String getFirstStackElement() {
|
||||
return callStack.getFirstStackTraceElement().toString();
|
||||
public String getTopElement() {
|
||||
return callOrigin.getTopElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "key[" + key + "] type[" + beanType + "] " + callStack.getFirstStackTraceElement() + " ";
|
||||
return "key[" + key + "] type[" + beanType + "] " + callOrigin.getTopElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc = 92821 * callStack.hashCode();
|
||||
int hc = 92821 * callOrigin.hashCode();
|
||||
hc = 92821 * hc + beanType.hashCode();
|
||||
hc = 92821 * hc + queryHash;
|
||||
return hc;
|
||||
@@ -82,6 +82,6 @@ public final class ObjectGraphOrigin implements Serializable {
|
||||
ObjectGraphOrigin e = (ObjectGraphOrigin) obj;
|
||||
return e.queryHash == queryHash
|
||||
&& e.beanType.equals(beanType)
|
||||
&& e.callStack.equals(callStack);
|
||||
&& e.callOrigin.equals(callOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -79,4 +81,11 @@ public interface ServerCache {
|
||||
* @param reset if true the statistics are reset.
|
||||
*/
|
||||
ServerCacheStatistics getStatistics(boolean reset);
|
||||
|
||||
/**
|
||||
* Visit the metrics for the cache.
|
||||
*/
|
||||
default void visit(MetricVisitor visitor) {
|
||||
// do nothing by default
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -9,13 +9,15 @@ public class ServerCacheConfig {
|
||||
|
||||
private final ServerCacheType type;
|
||||
private final String cacheKey;
|
||||
private final String shortName;
|
||||
private final ServerCacheOptions cacheOptions;
|
||||
private final CurrentTenantProvider tenantProvider;
|
||||
private final QueryCacheEntryValidate queryCacheEntryValidate;
|
||||
|
||||
public ServerCacheConfig(ServerCacheType type, String cacheKey, ServerCacheOptions cacheOptions, CurrentTenantProvider tenantProvider, QueryCacheEntryValidate queryCacheEntryValidate) {
|
||||
public ServerCacheConfig(ServerCacheType type, String cacheKey, String shortName, ServerCacheOptions cacheOptions, CurrentTenantProvider tenantProvider, QueryCacheEntryValidate queryCacheEntryValidate) {
|
||||
this.type = type;
|
||||
this.cacheKey = cacheKey;
|
||||
this.shortName = shortName;
|
||||
this.cacheOptions = cacheOptions;
|
||||
this.tenantProvider = tenantProvider;
|
||||
this.queryCacheEntryValidate = queryCacheEntryValidate;
|
||||
@@ -35,6 +37,13 @@ public class ServerCacheConfig {
|
||||
return cacheKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the short name for the cache.
|
||||
*/
|
||||
public String getShortName() {
|
||||
return shortName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tuning options.
|
||||
*/
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
|
||||
/**
|
||||
* Defines method for constructing caches for beans and queries.
|
||||
*/
|
||||
public interface ServerCacheFactory {
|
||||
|
||||
/**
|
||||
* Visit the metrics for the cache.
|
||||
*/
|
||||
default void visit(MetricVisitor visitor) {
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the cache for the given type with options.
|
||||
*/
|
||||
|
||||
+36
-2
@@ -1,10 +1,19 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The cache service for server side caching of beans and query results.
|
||||
*/
|
||||
public interface ServerCacheManager {
|
||||
|
||||
/**
|
||||
* Visit the metrics for all the server caches.
|
||||
*/
|
||||
void visitMetrics(MetricVisitor visitor);
|
||||
|
||||
/**
|
||||
* Return true if the L2 caching is local.
|
||||
* <p>
|
||||
@@ -14,6 +23,31 @@ public interface ServerCacheManager {
|
||||
*/
|
||||
boolean isLocalL2Caching();
|
||||
|
||||
/**
|
||||
* Return all the cache regions.
|
||||
*/
|
||||
List<ServerCacheRegion> allRegions();
|
||||
|
||||
/**
|
||||
* Set the regions that are enabled.
|
||||
* <p>
|
||||
* Typically this is set on startup and at runtime (via dynamic configuration).
|
||||
* </p>
|
||||
*
|
||||
* @param regions A region name or comma delimited list of region names.
|
||||
*/
|
||||
void setEnabledRegions(String regions);
|
||||
|
||||
/**
|
||||
* Enable or disable all the cache regions.
|
||||
*/
|
||||
void setAllRegionsEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Return the cache region by name. Typically to enable or disable the region.
|
||||
*/
|
||||
ServerCacheRegion getRegion(String name);
|
||||
|
||||
/**
|
||||
* Return the cache for mapping natural keys to id values.
|
||||
*/
|
||||
@@ -46,7 +80,7 @@ public interface ServerCacheManager {
|
||||
|
||||
/**
|
||||
* Clear all the local caches.
|
||||
*
|
||||
* <p>
|
||||
* This is used when the L2 Cache is based on clustered near-caches (Like Ebean-K8s-L2Cache).
|
||||
* It is not used when the L2 cache is a distributed cache such as HazelCast or Ignite etc.
|
||||
*/
|
||||
@@ -54,7 +88,7 @@ public interface ServerCacheManager {
|
||||
|
||||
/**
|
||||
* Clear the local caches for this bean type.
|
||||
*
|
||||
* <p>
|
||||
* This is used when the L2 Cache is based on clustered near-caches (Like Ebean-K8s-L2Cache).
|
||||
* It is not used when the L2 cache is a distributed cache such as HazelCast or Ignite etc.
|
||||
*/
|
||||
|
||||
@@ -10,22 +10,15 @@ import java.util.Set;
|
||||
*/
|
||||
public class ServerCacheNotification {
|
||||
|
||||
private final long modifyTimestamp;
|
||||
|
||||
private final Set<String> dependentTables;
|
||||
|
||||
public ServerCacheNotification(long modifyTimestamp, Set<String> dependentTables) {
|
||||
this.modifyTimestamp = modifyTimestamp;
|
||||
public ServerCacheNotification(Set<String> dependentTables) {
|
||||
this.dependentTables = dependentTables;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ts:" + modifyTimestamp + " tables:" + dependentTables;
|
||||
}
|
||||
|
||||
public long getModifyTimestamp() {
|
||||
return modifyTimestamp;
|
||||
return "tables:" + dependentTables;
|
||||
}
|
||||
|
||||
public Set<String> getDependentTables() {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
/**
|
||||
* Cache region can be enabled independently.
|
||||
*/
|
||||
public interface ServerCacheRegion {
|
||||
|
||||
/**
|
||||
* Return the region name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return true if the cache region is enabled.
|
||||
*/
|
||||
boolean isEnabled();
|
||||
|
||||
/**
|
||||
* Set to true to enable the cache region.
|
||||
*/
|
||||
void setEnabled(boolean enabled);
|
||||
|
||||
}
|
||||
+12
-96
@@ -21,23 +21,13 @@ public class ServerCacheStatistics {
|
||||
|
||||
protected long missCount;
|
||||
|
||||
protected long insertCount;
|
||||
|
||||
protected long updateCount;
|
||||
protected long putCount;
|
||||
|
||||
protected long removeCount;
|
||||
|
||||
protected long clearCount;
|
||||
|
||||
protected long evictionRunCount;
|
||||
|
||||
protected long evictionRunMicros;
|
||||
|
||||
protected long evictByIdle;
|
||||
|
||||
protected long evictByTTL;
|
||||
|
||||
protected long evictByLRU;
|
||||
protected long evictCount;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -49,15 +39,10 @@ public class ServerCacheStatistics {
|
||||
sb.append(" hitRatio:").append(getHitRatio());
|
||||
sb.append(" hit:").append(hitCount);
|
||||
sb.append(" miss:").append(missCount);
|
||||
sb.append(" insert:").append(insertCount);
|
||||
sb.append(" update:").append(updateCount);
|
||||
sb.append(" put:").append(putCount);
|
||||
sb.append(" remove:").append(removeCount);
|
||||
sb.append(" clear:").append(clearCount);
|
||||
sb.append(" evictByIdle:").append(evictByIdle);
|
||||
sb.append(" evictByTTL:").append(evictByTTL);
|
||||
sb.append(" evictByLRU:").append(evictByLRU);
|
||||
sb.append(" evictionRunCount:").append(evictionRunCount);
|
||||
sb.append(" evictionRunMicros:").append(evictionRunMicros);
|
||||
sb.append(" evict:").append(evictCount);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -153,29 +138,15 @@ public class ServerCacheStatistics {
|
||||
/**
|
||||
* Set the put insert count.
|
||||
*/
|
||||
public void setInsertCount(long insertCount) {
|
||||
this.insertCount = insertCount;
|
||||
public void setPutCount(long putCount) {
|
||||
this.putCount = putCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the put insert count.
|
||||
*/
|
||||
public long getInsertCount() {
|
||||
return insertCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the put update count.
|
||||
*/
|
||||
public void setUpdateCount(long updateCount) {
|
||||
this.updateCount = updateCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the put update count.
|
||||
*/
|
||||
public long getUpdateCount() {
|
||||
return updateCount;
|
||||
public long getPutCount() {
|
||||
return putCount;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,73 +177,18 @@ public class ServerCacheStatistics {
|
||||
return clearCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the eviction run count.
|
||||
*/
|
||||
public void setEvictionRunCount(long evictCount) {
|
||||
this.evictionRunCount = evictCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the eviction run count.
|
||||
*/
|
||||
public long getEvictionRunCount() {
|
||||
return evictionRunCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the eviction run time in micros.
|
||||
*/
|
||||
public void setEvictionRunMicros(long evictionRunMicros) {
|
||||
this.evictionRunMicros = evictionRunMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the eviction run time in micros.
|
||||
*/
|
||||
public long getEvictionRunMicros() {
|
||||
return evictionRunMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count of entries evicted due to idle time.
|
||||
*/
|
||||
public void setEvictByIdle(long evictByIdle) {
|
||||
this.evictByIdle = evictByIdle;
|
||||
public void setEvictCount(long evictCount) {
|
||||
this.evictCount = evictCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of entries evicted due to idle time.
|
||||
*/
|
||||
public long getEvictByIdle() {
|
||||
return evictByIdle;
|
||||
public long getEvictCount() {
|
||||
return evictCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count of entries evicted due to time to live.
|
||||
*/
|
||||
public void setEvictByTTL(long evictByTTL) {
|
||||
this.evictByTTL = evictByTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of entries evicted due to time to live.
|
||||
*/
|
||||
public long getEvictByTTL() {
|
||||
return evictByTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count of entries evicted due to time least recently used.
|
||||
*/
|
||||
public void setEvictByLRU(long evictByLRU) {
|
||||
this.evictByLRU = evictByLRU;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of entries evicted due to time least recently used.
|
||||
*/
|
||||
public long getEvictByLRU() {
|
||||
return evictByLRU;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public enum ServerCacheType {
|
||||
*/
|
||||
QUERY("_Q");
|
||||
|
||||
private String code;
|
||||
private final String code;
|
||||
|
||||
ServerCacheType(String code) {
|
||||
this.code = code;
|
||||
|
||||
@@ -219,7 +219,6 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
/**
|
||||
* Copies all relevant properties for a clone. See {@link #getShallowCopy()}
|
||||
* @param other
|
||||
*/
|
||||
protected void setFromOriginal(AbstractBeanCollection<E> other) {
|
||||
this.disableLazyLoad = other.disableLazyLoad;
|
||||
|
||||
@@ -237,7 +237,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public Set<Entry<K, E>> entrySet() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
|
||||
@@ -5,7 +5,7 @@ package io.ebean.config;
|
||||
*/
|
||||
public class AutoTuneConfig {
|
||||
|
||||
private AutoTuneMode mode = AutoTuneMode.DEFAULT_ON;
|
||||
private AutoTuneMode mode = AutoTuneMode.DEFAULT_OFF;
|
||||
|
||||
private String queryTuningFile = "ebean-autotune.xml";
|
||||
|
||||
|
||||
@@ -5,6 +5,22 @@ package io.ebean.config;
|
||||
*/
|
||||
public abstract class JsonConfig {
|
||||
|
||||
/**
|
||||
* Defined the format used for Date types.
|
||||
*/
|
||||
public enum Date {
|
||||
|
||||
/**
|
||||
* Format as epoch millis.
|
||||
*/
|
||||
MILLIS,
|
||||
|
||||
/**
|
||||
* Format as ISO-8601 date format.
|
||||
*/
|
||||
ISO8601
|
||||
}
|
||||
|
||||
/**
|
||||
* Defined the format used for DateTime types.
|
||||
*/
|
||||
|
||||
@@ -52,6 +52,8 @@ public class PlatformConfig {
|
||||
*/
|
||||
private boolean databaseInetAddressVarchar;
|
||||
|
||||
private boolean caseSensitiveCollation = true;
|
||||
|
||||
/**
|
||||
* Modify the default mapping of standard types such as default precision for DECIMAL etc.
|
||||
*/
|
||||
@@ -74,6 +76,10 @@ public class PlatformConfig {
|
||||
this.idType = platformConfig.idType;
|
||||
this.geometrySRID = platformConfig.geometrySRID;
|
||||
this.dbUuid = platformConfig.dbUuid;
|
||||
this.caseSensitiveCollation = platformConfig.caseSensitiveCollation;
|
||||
this.allQuotedIdentifiers = platformConfig.allQuotedIdentifiers;
|
||||
this.databaseInetAddressVarchar = platformConfig.databaseInetAddressVarchar;
|
||||
this.customDbTypeMappings = platformConfig.customDbTypeMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,6 +96,20 @@ public class PlatformConfig {
|
||||
this.allQuotedIdentifiers = allQuotedIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the collation is case sensitive.
|
||||
*/
|
||||
public boolean isCaseSensitiveCollation() {
|
||||
return caseSensitiveCollation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to false to indicate that the collation is case insensitive.
|
||||
*/
|
||||
public void setCaseSensitiveCollation(boolean caseSensitiveCollation) {
|
||||
this.caseSensitiveCollation = caseSensitiveCollation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a value used to represent TRUE in the database.
|
||||
* <p>
|
||||
@@ -255,6 +275,7 @@ public class PlatformConfig {
|
||||
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
|
||||
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
|
||||
databaseInetAddressVarchar = p.getBoolean("databaseInetAddressVarchar", databaseInetAddressVarchar);
|
||||
caseSensitiveCollation = p.getBoolean("caseSensitiveCollation", caseSensitiveCollation);
|
||||
|
||||
DbUuid dbUuid = p.getEnum(DbUuid.class, "dbuuid", null);
|
||||
if (dbUuid != null) {
|
||||
|
||||
@@ -169,7 +169,12 @@ public class ServerConfig {
|
||||
/**
|
||||
* The JSON format used for DateTime types. Default to millis.
|
||||
*/
|
||||
private JsonConfig.DateTime jsonDateTime = JsonConfig.DateTime.MILLIS;
|
||||
private JsonConfig.DateTime jsonDateTime = JsonConfig.DateTime.ISO8601;
|
||||
|
||||
/**
|
||||
* The JSON format used for Date types. Default to millis.
|
||||
*/
|
||||
private JsonConfig.Date jsonDate = JsonConfig.Date.ISO8601;
|
||||
|
||||
/**
|
||||
* For writing JSON specify if null values or empty collections should be exluded.
|
||||
@@ -479,6 +484,7 @@ public class ServerConfig {
|
||||
*/
|
||||
private boolean disableL2Cache;
|
||||
|
||||
private String enabledL2Regions;
|
||||
|
||||
/**
|
||||
* Should the javax.validation.constraints.NotNull enforce a notNull column in DB.
|
||||
@@ -512,7 +518,7 @@ public class ServerConfig {
|
||||
/**
|
||||
* Controls the default order by id setting of queries. See {@link Query#orderById(boolean)}
|
||||
*/
|
||||
private boolean defaultOrderById = false;
|
||||
private boolean defaultOrderById;
|
||||
|
||||
/**
|
||||
* The mappingLocations for searching xml mapping.
|
||||
@@ -524,6 +530,10 @@ public class ServerConfig {
|
||||
*/
|
||||
private boolean idGeneratorAutomatic = true;
|
||||
|
||||
private boolean dumpMetricsOnShutdown;
|
||||
|
||||
private String dumpMetricsOptions;
|
||||
|
||||
/**
|
||||
* Construct a Database Configuration for programmatically creating an Database.
|
||||
*/
|
||||
@@ -575,8 +585,9 @@ public class ServerConfig {
|
||||
|
||||
|
||||
/**
|
||||
* Sets the default orderById setting for queries.
|
||||
* Deprecated - look to have explicit order by. Sets the default orderById setting for queries.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setDefaultOrderById(boolean defaultOrderById) {
|
||||
this.defaultOrderById = defaultOrderById;
|
||||
}
|
||||
@@ -642,6 +653,7 @@ public class ServerConfig {
|
||||
* @param cls The type of the service object to obtain
|
||||
* @return The service object given the class type
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <P> P getServiceObject(Class<P> cls) {
|
||||
return (P) serviceObject.get(serviceObjectKey(cls));
|
||||
}
|
||||
@@ -678,6 +690,20 @@ public class ServerConfig {
|
||||
this.jsonDateTime = jsonDateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSON format used for Date types.
|
||||
*/
|
||||
public JsonConfig.Date getJsonDate() {
|
||||
return jsonDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JSON format to use for Date types.
|
||||
*/
|
||||
public void setJsonDate(JsonConfig.Date jsonDate) {
|
||||
this.jsonDate = jsonDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSON include mode used when writing JSON.
|
||||
*/
|
||||
@@ -2903,11 +2929,15 @@ public class ServerConfig {
|
||||
}
|
||||
loadDocStoreSettings(p);
|
||||
|
||||
maxCallStack = p.getInt("maxCallStack", maxCallStack);
|
||||
dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown);
|
||||
dumpMetricsOptions = p.get("dumpMetricsOptions", dumpMetricsOptions);
|
||||
queryPlanTTLSeconds = p.getInt("queryPlanTTLSeconds", queryPlanTTLSeconds);
|
||||
slowQueryMillis = p.getLong("slowQueryMillis", slowQueryMillis);
|
||||
collectQueryPlans = p.getBoolean("collectQueryPlans", collectQueryPlans);
|
||||
docStoreOnly = p.getBoolean("docStoreOnly", docStoreOnly);
|
||||
disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache);
|
||||
enabledL2Regions = p.get("enabledL2Regions", enabledL2Regions);
|
||||
notifyL2CacheInForeground = p.getBoolean("notifyL2CacheInForeground", notifyL2CacheInForeground);
|
||||
explicitTransactionBeginMode = p.getBoolean("explicitTransactionBeginMode", explicitTransactionBeginMode);
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
|
||||
@@ -2980,12 +3010,8 @@ public class ServerConfig {
|
||||
queryBatchSize = p.getInt("queryBatchSize", queryBatchSize);
|
||||
|
||||
jsonInclude = p.getEnum(JsonConfig.Include.class, "jsonInclude", jsonInclude);
|
||||
String jsonDateTimeFormat = p.get("jsonDateTime", null);
|
||||
if (jsonDateTimeFormat != null) {
|
||||
jsonDateTime = JsonConfig.DateTime.valueOf(jsonDateTimeFormat);
|
||||
} else {
|
||||
jsonDateTime = JsonConfig.DateTime.MILLIS;
|
||||
}
|
||||
jsonDateTime = p.getEnum(JsonConfig.DateTime.class, "jsonDateTime", jsonDateTime);
|
||||
jsonDate = p.getEnum(JsonConfig.Date.class, "jsonDate", jsonDate);
|
||||
|
||||
ddlGenerate = p.getBoolean("ddl.generate", ddlGenerate);
|
||||
ddlRun = p.getBoolean("ddl.run", ddlRun);
|
||||
@@ -3130,6 +3156,20 @@ public class ServerConfig {
|
||||
this.expressionNativeIlike = expressionNativeIlike;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the enabled L2 cache regions.
|
||||
*/
|
||||
public String getEnabledL2Regions() {
|
||||
return enabledL2Regions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the enabled L2 cache regions (comma delimited).
|
||||
*/
|
||||
public void setEnabledL2Regions(String enabledL2Regions) {
|
||||
this.enabledL2Regions = enabledL2Regions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if L2 cache is disabled.
|
||||
*/
|
||||
@@ -3287,6 +3327,36 @@ public class ServerConfig {
|
||||
this.collectQueryPlans = collectQueryPlans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if metrics should be dumped when the server is shutdown.
|
||||
*/
|
||||
public boolean isDumpMetricsOnShutdown() {
|
||||
return dumpMetricsOnShutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if metrics should be dumped when the server is shutdown.
|
||||
*/
|
||||
public void setDumpMetricsOnShutdown(boolean dumpMetricsOnShutdown) {
|
||||
this.dumpMetricsOnShutdown = dumpMetricsOnShutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the options for dumping metrics.
|
||||
*/
|
||||
public String getDumpMetricsOptions() {
|
||||
return dumpMetricsOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include 'sql' or 'hash' in options such that they are included in the output.
|
||||
*
|
||||
* @param dumpMetricsOptions Example "sql,hash", "sql"
|
||||
*/
|
||||
public void setDumpMetricsOptions(String dumpMetricsOptions) {
|
||||
this.dumpMetricsOptions = dumpMetricsOptions;
|
||||
}
|
||||
|
||||
public enum UuidVersion {
|
||||
VERSION4,
|
||||
VERSION1,
|
||||
|
||||
@@ -35,9 +35,9 @@ public enum TenantMode {
|
||||
* (that holds configuration e.g.)
|
||||
*/
|
||||
DB_WITH_MASTER(true, true);
|
||||
|
||||
boolean dynamicDataSource;
|
||||
boolean ddlEnabled;
|
||||
|
||||
final boolean dynamicDataSource;
|
||||
final boolean ddlEnabled;
|
||||
|
||||
TenantMode(boolean dynamicDataSource, boolean ddlEnabled) {
|
||||
this.dynamicDataSource = dynamicDataSource;
|
||||
@@ -50,12 +50,12 @@ public enum TenantMode {
|
||||
public boolean isDynamicDataSource() {
|
||||
return dynamicDataSource;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true, if DDL is enabled.
|
||||
*/
|
||||
public boolean isDdlEnabled() {
|
||||
return ddlEnabled;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -18,5 +18,10 @@ public enum DataErrorType {
|
||||
/**
|
||||
* Data integrity error like an invalid foreign key.
|
||||
*/
|
||||
DataIntegrity
|
||||
DataIntegrity,
|
||||
|
||||
/**
|
||||
* Non recoverable concurrency conflict.
|
||||
*/
|
||||
SerializableConflict
|
||||
}
|
||||
|
||||
@@ -49,6 +49,10 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected boolean useExtraTransactionOnIterateSecondaryQueries;
|
||||
|
||||
protected boolean supportsDeleteTableAlias;
|
||||
|
||||
protected boolean supportsSavepointId = true;
|
||||
|
||||
/**
|
||||
* The behaviour used when ending a read only transaction at read committed isolation level.
|
||||
*/
|
||||
@@ -69,6 +73,8 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected boolean allQuotedIdentifiers;
|
||||
|
||||
protected boolean caseSensitiveCollation = true;
|
||||
|
||||
/**
|
||||
* For limit/offset, row_number etc limiting of SQL queries.
|
||||
*/
|
||||
@@ -133,6 +139,8 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected Platform platform = Platform.GENERIC;
|
||||
|
||||
protected String truncateTable = "truncate table %s";
|
||||
|
||||
protected String columnAliasPrefix = "c";
|
||||
|
||||
protected String tableAliasPlaceHolder = "${ta}";
|
||||
@@ -176,10 +184,10 @@ public class DatabasePlatform {
|
||||
* findIterate() and findVisit().
|
||||
*/
|
||||
protected boolean forwardOnlyHintOnFindIterate;
|
||||
|
||||
|
||||
/**
|
||||
* If set then use the CONCUR_UPDATABLE hint when creating ResultSets.
|
||||
*
|
||||
*
|
||||
* This is {@code false} for HANA
|
||||
*/
|
||||
protected boolean supportsResultSetConcurrencyModeUpdatable = true;
|
||||
@@ -224,6 +232,7 @@ public class DatabasePlatform {
|
||||
*/
|
||||
public void configure(PlatformConfig config) {
|
||||
this.sequenceBatchSize = config.getDatabaseSequenceBatchSize();
|
||||
this.caseSensitiveCollation = config.isCaseSensitiveCollation();
|
||||
configureIdType(config.getIdType());
|
||||
configure(config, config.isAllQuotedIdentifiers());
|
||||
}
|
||||
@@ -306,6 +315,30 @@ public class DatabasePlatform {
|
||||
return supportsNativeIlike;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the platform supports delete statements with table alias.
|
||||
*/
|
||||
public boolean isSupportsDeleteTableAlias() {
|
||||
return supportsDeleteTableAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the collation is case sensitive.
|
||||
* <p>
|
||||
* This is expected to be used for testing only.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isCaseSensitiveCollation() {
|
||||
return caseSensitiveCollation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the platform supports SavepointId values.
|
||||
*/
|
||||
public boolean isSupportsSavepointId() {
|
||||
return supportsSavepointId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum table name length.
|
||||
* <p>
|
||||
@@ -524,7 +557,7 @@ public class DatabasePlatform {
|
||||
public void setForwardOnlyHintOnFindIterate(boolean forwardOnlyHintOnFindIterate) {
|
||||
this.forwardOnlyHintOnFindIterate = forwardOnlyHintOnFindIterate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the ResultSet CONCUR_UPDATABLE Hint should be used on
|
||||
* createNativeSqlTree() PreparedStatements.
|
||||
@@ -535,7 +568,7 @@ public class DatabasePlatform {
|
||||
public boolean isSupportsResultSetConcurrencyModeUpdatable() {
|
||||
return supportsResultSetConcurrencyModeUpdatable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set to true if the ResultSet CONCUR_UPDATABLE Hint should be used by default on createNativeSqlTree() PreparedStatements.
|
||||
*/
|
||||
@@ -546,7 +579,7 @@ public class DatabasePlatform {
|
||||
/**
|
||||
* Normally not needed - overridden in CockroachPlatform.
|
||||
*/
|
||||
public boolean isDdlCommitOnCreateIndex() {
|
||||
public boolean isDdlAutoCommit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -677,6 +710,13 @@ public class DatabasePlatform {
|
||||
return persistBatchOnCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a statement to truncate a table.
|
||||
*/
|
||||
public String truncateStatement(String table) {
|
||||
return String.format(truncateTable, table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the DB schema if it does not exist.
|
||||
*/
|
||||
|
||||
@@ -27,15 +27,13 @@ public class DbDefaultValue {
|
||||
* The key for the NOW / current timestamp.
|
||||
*/
|
||||
public static final String NOW = "now";
|
||||
|
||||
|
||||
/**
|
||||
* The 'null' literal.
|
||||
*/
|
||||
public static final String NULL = "null";
|
||||
|
||||
|
||||
|
||||
protected Map<String, String> map = new LinkedHashMap<>();
|
||||
protected final Map<String, String> map = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* Set the DB now function.
|
||||
@@ -82,10 +80,9 @@ public class DbDefaultValue {
|
||||
return val != null ? val : dbDefaultLiteral;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method checks & convert the {@link DbDefault#value()} to a valid SQL literal.
|
||||
*
|
||||
*
|
||||
* This is mainly to quote string literals and verify integer/dates for correctness.
|
||||
* <p>
|
||||
* Note: There are some special cases:
|
||||
@@ -98,24 +95,24 @@ public class DbDefaultValue {
|
||||
* If you need really the String "null", you have to specify <code>@DbDefault("'null'")</code>
|
||||
* which gives you the <code>default 'null'</code> statement.</li>
|
||||
* <li>Any statement, that begins and ends with single quote will not be checked or get quoted again.</li>
|
||||
* <li>A statement that begins with "$RAW:", e.g <code>@DbDefault("$RAW:N'SANDNES'")</code> will lead to
|
||||
* <li>A statement that begins with "$RAW:", e.g <code>@DbDefault("$RAW:N'SANDNES'")</code> will lead to
|
||||
* a <code>default N'SANDNES'</code> in DDL. Note that this is platform specific!</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static String toSqlLiteral(String defaultValue, Class<?> propertyType, int sqlType) {
|
||||
if (propertyType == null
|
||||
|| defaultValue == null
|
||||
|| defaultValue == null
|
||||
|| NULL.equals(defaultValue)
|
||||
|| (defaultValue.startsWith("'") && defaultValue.endsWith("'"))
|
||||
|| (defaultValue.startsWith("$RAW:"))) {
|
||||
|| (defaultValue.startsWith("$RAW:"))) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (Boolean.class.isAssignableFrom(propertyType) || Boolean.TYPE.isAssignableFrom(propertyType)) {
|
||||
return toBooleanLiteral(defaultValue);
|
||||
}
|
||||
|
||||
if (Number.class.isAssignableFrom(propertyType)
|
||||
|
||||
if (Number.class.isAssignableFrom(propertyType)
|
||||
|| Byte.TYPE.equals(propertyType)
|
||||
|| Short.TYPE.equals(propertyType)
|
||||
|| Integer.TYPE.equals(propertyType)
|
||||
@@ -126,7 +123,7 @@ public class DbDefaultValue {
|
||||
Double.valueOf(defaultValue); // verify if it is a number
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
// check if it is a date/time - in all other cases return quoted defaultValue
|
||||
switch (sqlType) {
|
||||
// date
|
||||
@@ -155,7 +152,7 @@ public class DbDefaultValue {
|
||||
}
|
||||
throw new IllegalArgumentException("'" + value + "' is not a valid value for boolean");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This adds single qoutes around the <code>value</code> and doubles single quotes.
|
||||
* "User's home" will return "'User''s home'"
|
||||
@@ -175,7 +172,7 @@ public class DbDefaultValue {
|
||||
return sb.toString();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static String toDateLiteral(String value) {
|
||||
if (NOW.equals(value)) {
|
||||
return value; // this will get translated later
|
||||
@@ -191,7 +188,7 @@ public class DbDefaultValue {
|
||||
DatatypeConverter.parseTime(value); // verify
|
||||
return toTextLiteral(value);
|
||||
}
|
||||
|
||||
|
||||
private static String toDateTimeLiteral(String value) {
|
||||
if (NOW.equals(value)) {
|
||||
return value; // this will get translated later
|
||||
|
||||
@@ -11,12 +11,12 @@ class DbPlatformTypeLookup {
|
||||
/**
|
||||
* A map to lookup the type by name.
|
||||
*/
|
||||
private Map<String, DbType> nameLookup = new HashMap<>();
|
||||
private final Map<String, DbType> nameLookup = new HashMap<>();
|
||||
|
||||
/**
|
||||
* A map to lookup the type by JDBC int value.
|
||||
*/
|
||||
private Map<Integer, DbType> idLookup = new HashMap<>();
|
||||
private final Map<Integer, DbType> idLookup = new HashMap<>();
|
||||
|
||||
DbPlatformTypeLookup() {
|
||||
addAll();
|
||||
|
||||
@@ -23,7 +23,7 @@ public class DbPlatformTypeMapping {
|
||||
}
|
||||
}
|
||||
|
||||
private static DbPlatformTypeLookup lookup = new DbPlatformTypeLookup();
|
||||
private static final DbPlatformTypeLookup lookup = new DbPlatformTypeLookup();
|
||||
|
||||
private static final DbPlatformType BOOLEAN_LOGICAL = new BooleanLogicalType();
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebean.config.dbplatform;
|
||||
import io.ebean.AcquireLockException;
|
||||
import io.ebean.DataIntegrityException;
|
||||
import io.ebean.DuplicateKeyException;
|
||||
import io.ebean.SerializableConflictException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.SQLException;
|
||||
@@ -14,12 +15,12 @@ import java.util.Map;
|
||||
*/
|
||||
public class SqlCodeTranslator implements SqlExceptionTranslator {
|
||||
|
||||
private final Map<String,DataErrorType> map;
|
||||
private final Map<String, DataErrorType> map;
|
||||
|
||||
/**
|
||||
* Create given the map of SQLState codes to error types.
|
||||
*/
|
||||
public SqlCodeTranslator(Map<String,DataErrorType> map) {
|
||||
public SqlCodeTranslator(Map<String, DataErrorType> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@@ -46,6 +47,8 @@ public class SqlCodeTranslator implements SqlExceptionTranslator {
|
||||
return new DuplicateKeyException(message, e);
|
||||
case DataIntegrity:
|
||||
return new DataIntegrityException(message, e);
|
||||
case SerializableConflict:
|
||||
return new SerializableConflictException(message, e);
|
||||
}
|
||||
}
|
||||
// return a generic exception
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class SqlErrorCodes {
|
||||
|
||||
private Map<String,DataErrorType> map = new HashMap<>();
|
||||
private final Map<String, DataErrorType> map = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Map the codes to AcquireLockException.
|
||||
@@ -31,6 +31,13 @@ public class SqlErrorCodes {
|
||||
return add(DataErrorType.DuplicateKey, codes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the codes to SerializableConflictException.
|
||||
*/
|
||||
public SqlErrorCodes addSerializableConflict(String... codes) {
|
||||
return add(DataErrorType.SerializableConflict, codes);
|
||||
}
|
||||
|
||||
private SqlErrorCodes add(DataErrorType type, String... codes) {
|
||||
for (String code : codes) {
|
||||
map.put(code, type);
|
||||
|
||||
@@ -21,7 +21,7 @@ public class CockroachPlatform extends PostgresPlatform {
|
||||
* Needs a commit after create index such that alter table add foreign key ... succeeds.
|
||||
*/
|
||||
@Override
|
||||
public boolean isDdlCommitOnCreateIndex() {
|
||||
public boolean isDdlAutoCommit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ public class DB2Platform extends DatabasePlatform {
|
||||
this.platform = Platform.DB2;
|
||||
this.maxTableNameLength = 18;
|
||||
this.maxConstraintNameLength = 18;
|
||||
this.truncateTable = "truncate table %s reuse storage ignore delete triggers immediate";
|
||||
this.sqlLimiter = new Db2SqlLimiter();
|
||||
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
|
||||
@@ -23,9 +23,9 @@ public class H2Platform extends DatabasePlatform {
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
this.historySupport = new H2HistorySupport();
|
||||
this.nativeUuidType = true;
|
||||
this.supportsDeleteTableAlias = true;
|
||||
this.dbDefaultValue.setNow("now()");
|
||||
this.columnAliasPrefix = null;
|
||||
|
||||
this.exceptionTranslator =
|
||||
new SqlErrorCodes()
|
||||
.addAcquireLock("50200","HYT00")
|
||||
|
||||
@@ -18,7 +18,6 @@ public class HanaPlatform extends DatabasePlatform {
|
||||
this.persistBatchOnCascade = PersistBatch.NONE;
|
||||
this.supportsResultSetConcurrencyModeUpdatable = false;
|
||||
this.columnAliasPrefix = null;
|
||||
|
||||
this.historySupport = new HanaHistorySupport();
|
||||
this.basicSqlLimiter = new HanaBasicSqlLimiter();
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ public class HsqldbPlatform extends DatabasePlatform {
|
||||
super();
|
||||
this.platform = Platform.HSQLDB;
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
|
||||
this.truncateTable = "delete from %s";
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
@@ -27,15 +27,15 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
this.platform = Platform.MYSQL;
|
||||
this.useExtraTransactionOnIterateSecondaryQueries = true;
|
||||
this.selectCountWithAlias = true;
|
||||
this.supportsSavepointId = false;
|
||||
this.dbEncrypt = new MySqlDbEncrypt();
|
||||
this.historySupport = new MySqlHistorySupport();
|
||||
this.columnAliasPrefix = null;
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
this.dbIdentity.setSupportsSequence(false);
|
||||
|
||||
|
||||
this.dbDefaultValue.setNow("now(6)"); // must have same precision as TIMESTAMP
|
||||
this.dbDefaultValue.setFalse("0");
|
||||
this.dbDefaultValue.setTrue("1");
|
||||
@@ -51,8 +51,8 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
this.openQuote = "`";
|
||||
this.closeQuote = "`";
|
||||
// use pipe for escaping as it depends if mysql runs in no_backslash_escapes or not.
|
||||
this.likeClauseRaw = "like binary ? escape ''";
|
||||
this.likeClauseEscaped = "like binary ? escape '|'";
|
||||
this.likeClauseRaw = "like ? escape ''";
|
||||
this.likeClauseEscaped = "like ? escape '|'";
|
||||
|
||||
this.forwardOnlyHintOnFindIterate = true;
|
||||
this.booleanDbType = Types.BIT;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package io.ebean.config.dbplatform.nuodb;
|
||||
|
||||
import io.ebean.config.dbplatform.DbViewHistorySupport;
|
||||
|
||||
/**
|
||||
* Runtime support for @History with NuoDB.
|
||||
*/
|
||||
public class NuoDbHistorySupport extends DbViewHistorySupport {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package io.ebean.config.dbplatform.nuodb;
|
||||
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.dbplatform.PlatformIdGenerator;
|
||||
import io.ebean.config.dbplatform.SqlErrorCodes;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* NuoDb specific platform.
|
||||
*/
|
||||
public class NuoDbPlatform extends DatabasePlatform {
|
||||
|
||||
public NuoDbPlatform() {
|
||||
super();
|
||||
this.platform = Platform.NUODB;
|
||||
this.idInExpandedForm = true;
|
||||
this.supportsResultSetConcurrencyModeUpdatable = false;
|
||||
this.supportsDeleteTableAlias = true;
|
||||
this.columnAliasPrefix = null;
|
||||
this.likeClauseRaw = "like ?";
|
||||
this.historySupport = new NuoDbHistorySupport();
|
||||
//this.dbEncrypt = ...
|
||||
dbIdentity.setIdType(IdType.IDENTITY);
|
||||
dbIdentity.setSupportsIdentity(true);
|
||||
dbIdentity.setSupportsSequence(true);
|
||||
dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
|
||||
// No referential integrity exception to map
|
||||
this.exceptionTranslator =
|
||||
new SqlErrorCodes()
|
||||
//.addAcquireLock("")
|
||||
.addDuplicateKey("23000")
|
||||
.addSerializableConflict("40002")
|
||||
.build();
|
||||
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) {
|
||||
return new NuoDbSequence(be, ds, seqName, stepSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
case NOWAIT:
|
||||
return sql + " for update nowait";
|
||||
case SKIPLOCKED:
|
||||
default:
|
||||
return sql + " for update";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package io.ebean.config.dbplatform.nuodb;
|
||||
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.config.dbplatform.SequenceStepIdGenerator;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
public class NuoDbSequence extends SequenceStepIdGenerator {
|
||||
|
||||
private final String nextSql;
|
||||
|
||||
/**
|
||||
* Construct where batchSize is the sequence step size.
|
||||
*/
|
||||
public NuoDbSequence(BackgroundExecutor be, DataSource ds, String seqName, int stepSize) {
|
||||
super(be, ds, seqName, stepSize);
|
||||
this.nextSql = "select next value for " + seqName + " from dual";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSql(int batchSize) {
|
||||
return nextSql;
|
||||
}
|
||||
}
|
||||
@@ -23,13 +23,14 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
public OraclePlatform() {
|
||||
super();
|
||||
this.platform = Platform.ORACLE;
|
||||
this.supportsDeleteTableAlias = true;
|
||||
this.maxTableNameLength = 30;
|
||||
this.maxConstraintNameLength = 30;
|
||||
this.dbEncrypt = new OracleDbEncrypt();
|
||||
this.sqlLimiter = new RownumSqlLimiter();
|
||||
this.basicSqlLimiter = new BasicSqlAnsiLimiter();
|
||||
this.historySupport = new OracleDbHistorySupport();
|
||||
|
||||
this.truncateTable = "truncate table %s cascade";
|
||||
dbIdentity.setIdType(IdType.SEQUENCE);
|
||||
dbIdentity.setSupportsSequence(true);
|
||||
dbIdentity.setSupportsIdentity(true);
|
||||
@@ -47,6 +48,7 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
//.addAcquireLock("")
|
||||
.addDuplicateKey("1")
|
||||
.addDataIntegrity("2291")
|
||||
.addSerializableConflict("72000")
|
||||
.build();
|
||||
|
||||
this.openQuote = "\"";
|
||||
|
||||
@@ -30,12 +30,13 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
super();
|
||||
this.platform = Platform.POSTGRES;
|
||||
this.supportsNativeIlike = true;
|
||||
this.supportsDeleteTableAlias = true;
|
||||
this.selectCountWithAlias = true;
|
||||
this.blobDbType = Types.LONGVARBINARY;
|
||||
this.clobDbType = Types.VARCHAR;
|
||||
this.nativeUuidType = true;
|
||||
this.columnAliasPrefix = null;
|
||||
|
||||
this.truncateTable = "truncate table %s cascade";
|
||||
this.dbEncrypt = new PostgresDbEncrypt();
|
||||
this.historySupport = new PostgresHistorySupport();
|
||||
|
||||
@@ -51,6 +52,7 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
.addAcquireLock("55P03")
|
||||
.addDuplicateKey("23505")
|
||||
.addDataIntegrity("23000","23502","23503","23514")
|
||||
.addSerializableConflict("40001")
|
||||
.build();
|
||||
|
||||
this.openQuote = "\"";
|
||||
|
||||
@@ -17,7 +17,7 @@ public class SQLitePlatform extends DatabasePlatform {
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
this.dbIdentity.setSupportsSequence(false);
|
||||
this.dbIdentity.setSelectLastInsertedIdTemplate("select last_insert_rowid()");
|
||||
|
||||
this.truncateTable = "delete from %s";
|
||||
this.booleanDbType = Types.INTEGER;
|
||||
this.likeClauseRaw = "like ?";
|
||||
this.likeClauseEscaped = "like ?";
|
||||
|
||||
@@ -65,13 +65,9 @@ public class SqlServer2005SqlLimiter implements SqlLimiter {
|
||||
sb.append(NEW_LINE).append(") ");
|
||||
sb.append(rowNumberWindowAlias);
|
||||
sb.append(" where ");
|
||||
if (firstRow > 0) {
|
||||
sb.append(" rn > ").append(firstRow);
|
||||
if (lastRow > 0) {
|
||||
sb.append(" and ");
|
||||
}
|
||||
}
|
||||
sb.append(" rn > ").append(firstRow);
|
||||
if (lastRow > 0) {
|
||||
sb.append(" and ");
|
||||
sb.append(" rn <= ").append(lastRow);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@ abstract class SqlServerBasePlatform extends DatabasePlatform {
|
||||
this.openQuote = "[";
|
||||
this.closeQuote = "]";
|
||||
this.likeSpecialCharacters = new char[]{'%', '_', '['};
|
||||
this.likeClauseRaw = "like ? collate Latin1_General_BIN";
|
||||
this.likeClauseEscaped = "like ? collate Latin1_General_BIN";
|
||||
this.likeClauseRaw = "like ?";
|
||||
this.likeClauseEscaped = "like ?";
|
||||
|
||||
booleanDbType = Types.INTEGER;
|
||||
this.dbDefaultValue.setFalse("0");
|
||||
|
||||
@@ -38,10 +38,8 @@ public class SqlServerSqlLimiter implements SqlLimiter {
|
||||
}
|
||||
|
||||
sb.append(dbSql);
|
||||
if (firstRow > 0) {
|
||||
sb.append(" ").append("offset");
|
||||
sb.append(" ").append(firstRow).append(" rows");
|
||||
}
|
||||
sb.append(" ").append("offset");
|
||||
sb.append(" ").append(firstRow).append(" rows");
|
||||
if (maxRows > 0) {
|
||||
sb.append(" fetch next ").append(maxRows).append(" rows only");
|
||||
}
|
||||
|
||||
@@ -14,189 +14,192 @@ import javax.naming.NamingException;
|
||||
*/
|
||||
final class PropertyEval {
|
||||
|
||||
/**
|
||||
* Prefix for looking up JNDI Environment variable.
|
||||
*/
|
||||
private static final String JAVA_COMP_ENV = "java:comp/env/";
|
||||
/**
|
||||
* Prefix for looking up JNDI Environment variable.
|
||||
*/
|
||||
private static final String JAVA_COMP_ENV = "java:comp/env/";
|
||||
|
||||
/**
|
||||
* Used to detect the start of an expression.
|
||||
*/
|
||||
private static final String START = "${";
|
||||
/**
|
||||
* Used to detect the start of an expression.
|
||||
*/
|
||||
private static final String START = "${";
|
||||
|
||||
/**
|
||||
* Used to detect the end of an expression.
|
||||
*/
|
||||
private static final String END = "}";
|
||||
/**
|
||||
* Used to detect the end of an expression.
|
||||
*/
|
||||
private static final String END = "}";
|
||||
|
||||
/**
|
||||
* Specify the PropertyHolder.
|
||||
*/
|
||||
private PropertyEval() {
|
||||
}
|
||||
/**
|
||||
* Specify the PropertyHolder.
|
||||
*/
|
||||
private PropertyEval() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property value evaluating and replacing any expressions such as
|
||||
* ${CATALINA_HOME}.
|
||||
*/
|
||||
static String eval(String val) {
|
||||
if (val == null) {
|
||||
return null;
|
||||
}
|
||||
int sp = val.indexOf(START);
|
||||
if (sp > -1) {
|
||||
int ep = val.indexOf(END, sp + 1);
|
||||
if (ep > -1) {
|
||||
return eval(val, sp, ep);
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
/**
|
||||
* Return the property value evaluating and replacing any expressions such as
|
||||
* ${CATALINA_HOME}.
|
||||
*/
|
||||
static String eval(String val) {
|
||||
if (val == null) {
|
||||
return null;
|
||||
}
|
||||
int sp = val.indexOf(START);
|
||||
if (sp > -1) {
|
||||
int ep = val.indexOf(END, sp + 1);
|
||||
if (ep > -1) {
|
||||
return eval(val, sp, ep);
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the expression using JNDI, Environment variables, System Properties
|
||||
* or existing an property in SystemProperties itself.
|
||||
*/
|
||||
private static String evaluateExpression(String exp) {
|
||||
/**
|
||||
* Convert the expression using JNDI, Environment variables, System Properties
|
||||
* or existing an property in SystemProperties itself.
|
||||
*/
|
||||
private static String evaluateExpression(String exp) {
|
||||
|
||||
if (isJndiExpression(exp)) {
|
||||
// JNDI property lookup...
|
||||
String val = getJndiProperty(exp);
|
||||
if (val != null) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
String val = System.getProperty(exp);
|
||||
if (val == null) {
|
||||
val = System.getenv(exp);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
if (exp.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (isJndiExpression(exp)) {
|
||||
// JNDI property lookup...
|
||||
String val = getJndiProperty(exp);
|
||||
if (val != null) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
String val = System.getProperty(exp);
|
||||
if (val == null) {
|
||||
val = System.getenv(exp);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
private static String eval(String val, int sp, int ep) {
|
||||
private static String eval(String val, int sp, int ep) {
|
||||
|
||||
return new EvalBuffer(val, sp, ep).process();
|
||||
}
|
||||
return new EvalBuffer(val, sp, ep).process();
|
||||
}
|
||||
|
||||
|
||||
private static boolean isJndiExpression(String exp) {
|
||||
return exp.startsWith("JNDI:") || exp.startsWith("jndi:");
|
||||
}
|
||||
private static boolean isJndiExpression(String exp) {
|
||||
return exp.startsWith("JNDI:") || exp.startsWith("jndi:");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null if JNDI is not setup or if the property is not found.
|
||||
*
|
||||
* @param key the key of the JNDI Environment property including a JNDI: prefix.
|
||||
*/
|
||||
private static String getJndiProperty(String key) {
|
||||
/**
|
||||
* Returns null if JNDI is not setup or if the property is not found.
|
||||
*
|
||||
* @param key the key of the JNDI Environment property including a JNDI: prefix.
|
||||
*/
|
||||
private static String getJndiProperty(String key) {
|
||||
|
||||
try {
|
||||
// remove the JNDI: prefix
|
||||
key = key.substring(5);
|
||||
return (String) getJndiObject(key);
|
||||
} catch (NamingException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
try {
|
||||
// remove the JNDI: prefix
|
||||
key = key.substring(5);
|
||||
return (String) getJndiObject(key);
|
||||
} catch (NamingException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to getProperty but throws NamingException if JNDI is not setup or
|
||||
* if the property is not found.
|
||||
*/
|
||||
private static Object getJndiObject(String key) throws NamingException {
|
||||
/**
|
||||
* Similar to getProperty but throws NamingException if JNDI is not setup or
|
||||
* if the property is not found.
|
||||
*/
|
||||
private static Object getJndiObject(String key) throws NamingException {
|
||||
|
||||
InitialContext ctx = new InitialContext();
|
||||
return ctx.lookup(JAVA_COMP_ENV + key);
|
||||
}
|
||||
InitialContext ctx = new InitialContext();
|
||||
return ctx.lookup(JAVA_COMP_ENV + key);
|
||||
}
|
||||
|
||||
|
||||
private static class EvalBuffer {
|
||||
private static class EvalBuffer {
|
||||
|
||||
private final StringBuilder buf = new StringBuilder();
|
||||
private final String original;
|
||||
private int position;
|
||||
private int start;
|
||||
private int end;
|
||||
private final StringBuilder buf = new StringBuilder();
|
||||
private final String original;
|
||||
private int position;
|
||||
private int start;
|
||||
private int end;
|
||||
|
||||
private String expression;
|
||||
private String defaultValue;
|
||||
private String expression;
|
||||
private String defaultValue;
|
||||
|
||||
EvalBuffer(String val, int start, int ep) {
|
||||
this.original = val;
|
||||
this.start = start;
|
||||
this.end = ep;
|
||||
this.position = 0;
|
||||
moveToStart();
|
||||
}
|
||||
EvalBuffer(String val, int start, int ep) {
|
||||
this.original = val;
|
||||
this.start = start;
|
||||
this.end = ep;
|
||||
this.position = 0;
|
||||
moveToStart();
|
||||
}
|
||||
|
||||
void moveToStart() {
|
||||
if (start > position) {
|
||||
buf.append(original.substring(position, start));
|
||||
position = start;
|
||||
}
|
||||
}
|
||||
void moveToStart() {
|
||||
if (start > position) {
|
||||
buf.append(original.substring(position, start));
|
||||
position = start;
|
||||
}
|
||||
}
|
||||
|
||||
void parseForDefault() {
|
||||
int colonPos = original.lastIndexOf(':', end);
|
||||
if (colonPos > start) {
|
||||
expression = original.substring(start + START.length(), colonPos);
|
||||
defaultValue = original.substring(colonPos + 1, end);
|
||||
} else {
|
||||
expression = original.substring(start + START.length(), end);
|
||||
}
|
||||
}
|
||||
void parseForDefault() {
|
||||
int colonPos = original.lastIndexOf(':', end);
|
||||
if (colonPos > start) {
|
||||
expression = original.substring(start + START.length(), colonPos);
|
||||
defaultValue = original.substring(colonPos + 1, end);
|
||||
} else {
|
||||
expression = original.substring(start + START.length(), end);
|
||||
}
|
||||
}
|
||||
|
||||
void evaluate() {
|
||||
String eval = evaluateExpression(expression);
|
||||
if (eval != null) {
|
||||
buf.append(eval);
|
||||
} else {
|
||||
if (defaultValue != null) {
|
||||
buf.append(defaultValue);
|
||||
} else {
|
||||
buf.append(START).append(expression).append(END);
|
||||
}
|
||||
}
|
||||
}
|
||||
void evaluate() {
|
||||
String eval = evaluateExpression(expression);
|
||||
if (eval != null) {
|
||||
buf.append(eval);
|
||||
} else {
|
||||
if (defaultValue != null) {
|
||||
buf.append(defaultValue);
|
||||
} else {
|
||||
buf.append(START).append(expression).append(END);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String end() {
|
||||
if (end < original.length() - 1) {
|
||||
buf.append(original.substring(end + 1));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
String end() {
|
||||
if (end < original.length() - 1) {
|
||||
buf.append(original.substring(end + 1));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
boolean next() {
|
||||
if (end < original.length()) {
|
||||
int startPos = original.indexOf(START, end + 1);
|
||||
if (startPos > -1) {
|
||||
int endPos = original.indexOf(END, startPos + 1);
|
||||
if (endPos > -1) {
|
||||
if (startPos > end + 1) {
|
||||
buf.append(original.substring(end + 1, startPos));
|
||||
}
|
||||
this.start = startPos;
|
||||
this.end = endPos;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
boolean next() {
|
||||
if (end < original.length()) {
|
||||
int startPos = original.indexOf(START, end + 1);
|
||||
if (startPos > -1) {
|
||||
int endPos = original.indexOf(END, startPos + 1);
|
||||
if (endPos > -1) {
|
||||
if (startPos > end + 1) {
|
||||
buf.append(original.substring(end + 1, startPos));
|
||||
}
|
||||
this.start = startPos;
|
||||
this.end = endPos;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void evalNext() {
|
||||
parseForDefault();
|
||||
evaluate();
|
||||
}
|
||||
private void evalNext() {
|
||||
parseForDefault();
|
||||
evaluate();
|
||||
}
|
||||
|
||||
String process() {
|
||||
evalNext();
|
||||
while (next()) {
|
||||
evalNext();
|
||||
}
|
||||
return end();
|
||||
}
|
||||
String process() {
|
||||
evalNext();
|
||||
while (next()) {
|
||||
evalNext();
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@ public interface BeanQueryRequest<T> {
|
||||
*/
|
||||
Query<T> getQuery();
|
||||
|
||||
/**
|
||||
* Return true if an Id IN expression should have the bind parameters padded.
|
||||
*/
|
||||
boolean isPadInExpression();
|
||||
|
||||
/**
|
||||
* Return true if multi-value binding using Array or Table Values is supported.
|
||||
*/
|
||||
|
||||
@@ -8,11 +8,13 @@ public abstract class AbstractMetricVisitor implements MetricVisitor {
|
||||
private final boolean reset;
|
||||
private final boolean collectTransactionMetrics;
|
||||
private final boolean collectQueryMetrics;
|
||||
private final boolean collectL2Metrics;
|
||||
|
||||
public AbstractMetricVisitor(boolean reset, boolean collectTransactionMetrics, boolean collectQueryMetrics) {
|
||||
public AbstractMetricVisitor(boolean reset, boolean collectTransactionMetrics, boolean collectQueryMetrics, boolean collectL2Metrics) {
|
||||
this.reset = reset;
|
||||
this.collectTransactionMetrics = collectTransactionMetrics;
|
||||
this.collectQueryMetrics = collectQueryMetrics;
|
||||
this.collectL2Metrics = collectL2Metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -30,6 +32,11 @@ public abstract class AbstractMetricVisitor implements MetricVisitor {
|
||||
return collectQueryMetrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollectL2Metrics() {
|
||||
return collectL2Metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitStart() {
|
||||
// do nothing by default
|
||||
|
||||
@@ -6,29 +6,31 @@ import java.util.List;
|
||||
/**
|
||||
* A simple MetricVisitor that can collect the desired metrics into lists.
|
||||
*/
|
||||
public class BasicMetricVisitor extends AbstractMetricVisitor {
|
||||
public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerMetrics {
|
||||
|
||||
private final List<MetaTimedMetric> timed = new ArrayList<>();
|
||||
private final List<MetaQueryMetric> dtoQuery = new ArrayList<>();
|
||||
private final List<MetaOrmQueryMetric> ormQuery = new ArrayList<>();
|
||||
private final List<MetaCountMetric> countMetrics = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Construct to reset and collect everything.
|
||||
*/
|
||||
public BasicMetricVisitor() {
|
||||
super(true, true, true);
|
||||
super(true, true, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct specifying reset and what to collect.
|
||||
*/
|
||||
public BasicMetricVisitor(boolean reset, boolean collectTransactionMetrics, boolean collectQueryMetrics) {
|
||||
super(reset, collectTransactionMetrics, collectQueryMetrics);
|
||||
public BasicMetricVisitor(boolean reset, boolean collectTransactionMetrics, boolean collectQueryMetrics, boolean collectL2Metrics) {
|
||||
super(reset, collectTransactionMetrics, collectQueryMetrics, collectL2Metrics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate.
|
||||
*/
|
||||
@Override
|
||||
public List<MetaTimedMetric> getTimedMetrics() {
|
||||
return timed;
|
||||
}
|
||||
@@ -36,6 +38,7 @@ public class BasicMetricVisitor extends AbstractMetricVisitor {
|
||||
/**
|
||||
* Return the DTO query metrics.
|
||||
*/
|
||||
@Override
|
||||
public List<MetaQueryMetric> getDtoQueryMetrics() {
|
||||
return dtoQuery;
|
||||
}
|
||||
@@ -43,10 +46,16 @@ public class BasicMetricVisitor extends AbstractMetricVisitor {
|
||||
/**
|
||||
* Return the ORM query metrics.
|
||||
*/
|
||||
@Override
|
||||
public List<MetaOrmQueryMetric> getOrmQueryMetrics() {
|
||||
return ormQuery;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaCountMetric> getCountMetrics() {
|
||||
return countMetrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTimed(MetaTimedMetric metric) {
|
||||
timed.add(metric);
|
||||
@@ -61,4 +70,9 @@ public class BasicMetricVisitor extends AbstractMetricVisitor {
|
||||
public void visitOrmQuery(MetaOrmQueryMetric metric) {
|
||||
ormQuery.add(metric);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCount(MetaCountMetric metric) {
|
||||
countMetrics.add(metric);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
/**
|
||||
* Count metrics.
|
||||
*/
|
||||
public interface MetaCountMetric {
|
||||
|
||||
/**
|
||||
* Return the metric type.
|
||||
*/
|
||||
MetricType getMetricType();
|
||||
|
||||
/**
|
||||
* Return the metric name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the total count.
|
||||
*/
|
||||
long getCount();
|
||||
|
||||
}
|
||||
@@ -7,6 +7,15 @@ import java.util.List;
|
||||
*/
|
||||
public interface MetaInfoManager {
|
||||
|
||||
/**
|
||||
* Return the metrics for the database instance.
|
||||
* <p>
|
||||
* This will reset the metrics (reset counters back to zero etc) and
|
||||
* will only return the non-empty metrics.
|
||||
* </p>
|
||||
*/
|
||||
ServerMetrics collectMetrics();
|
||||
|
||||
/**
|
||||
* Collect query plans.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -9,20 +7,15 @@ import java.util.List;
|
||||
*/
|
||||
public interface MetaOrmQueryMetric extends MetaQueryMetric {
|
||||
|
||||
/**
|
||||
* Return the profile location.
|
||||
*/
|
||||
ProfileLocation getProfileLocation();
|
||||
|
||||
/**
|
||||
* Return true if this query plan was tuned by AutoTune.
|
||||
*/
|
||||
boolean isAutoTuned();
|
||||
|
||||
/**
|
||||
* Return a string representation of the query plan hash.
|
||||
* Return the hash of the sql.
|
||||
*/
|
||||
String getQueryPlanHash();
|
||||
String getSqlHash();
|
||||
|
||||
/**
|
||||
* Return the time of the last query executed using this plan.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
|
||||
/**
|
||||
* Query execution metrics.
|
||||
*/
|
||||
@@ -15,6 +17,11 @@ public interface MetaQueryMetric extends MetaTimedMetric {
|
||||
*/
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* Return the profile location.
|
||||
*/
|
||||
ProfileLocation getProfileLocation();
|
||||
|
||||
/**
|
||||
* The actual SQL of the query.
|
||||
*/
|
||||
|
||||
@@ -1,23 +1,51 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
|
||||
public interface MetaQueryPlan {
|
||||
|
||||
/**
|
||||
* Return the bean type for the query.
|
||||
*/
|
||||
Class<?> getBeanType();
|
||||
|
||||
/**
|
||||
* Return a string representation of the query plan hash.
|
||||
* Return the label of the query.
|
||||
*/
|
||||
String getQueryPlanHash();
|
||||
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* Return the profile location for the query.
|
||||
*/
|
||||
ProfileLocation getProfileLocation();
|
||||
|
||||
/**
|
||||
* Return the sql of the query.
|
||||
*/
|
||||
String getSql();
|
||||
|
||||
/**
|
||||
* Return the hash of the sql.
|
||||
*/
|
||||
String getSqlHash();
|
||||
|
||||
/**
|
||||
* Return a description of the bind values.
|
||||
*/
|
||||
String getBind();
|
||||
|
||||
/**
|
||||
* Return the raw plan.
|
||||
*/
|
||||
String getPlan();
|
||||
|
||||
/**
|
||||
* Return the query execution time associated with the bind values capture.
|
||||
*/
|
||||
long getQueryTimeMicros();
|
||||
|
||||
/**
|
||||
* Return the total count of times bind capture has occurred.
|
||||
*/
|
||||
long getCaptureCount();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,11 @@ public interface MetricVisitor {
|
||||
*/
|
||||
boolean isCollectQueryMetrics();
|
||||
|
||||
/**
|
||||
* Return true if we should visit the L2 cache metrics.
|
||||
*/
|
||||
boolean isCollectL2Metrics();
|
||||
|
||||
/**
|
||||
* Visit has started.
|
||||
*/
|
||||
@@ -40,6 +45,11 @@ public interface MetricVisitor {
|
||||
*/
|
||||
void visitOrmQuery(MetaOrmQueryMetric metric);
|
||||
|
||||
/**
|
||||
* Visit a Counter metric.
|
||||
*/
|
||||
void visitCount(MetaCountMetric metric);
|
||||
|
||||
/**
|
||||
* Visit has completed.
|
||||
*/
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.Set;
|
||||
*/
|
||||
public class QueryPlanRequest {
|
||||
|
||||
private List<MetaQueryPlan> plans = new ArrayList<>();
|
||||
private final List<MetaQueryPlan> plans = new ArrayList<>();
|
||||
|
||||
private Connection connection;
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Metrics of the Database instance.
|
||||
*/
|
||||
public interface ServerMetrics {
|
||||
|
||||
/**
|
||||
* Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate.
|
||||
*/
|
||||
List<MetaTimedMetric> getTimedMetrics();
|
||||
|
||||
/**
|
||||
* Return the DTO query metrics.
|
||||
*/
|
||||
List<MetaQueryMetric> getDtoQueryMetrics();
|
||||
|
||||
/**
|
||||
* Return the ORM query metrics.
|
||||
*/
|
||||
List<MetaOrmQueryMetric> getOrmQueryMetrics();
|
||||
|
||||
/**
|
||||
* Return the Counter metrics.
|
||||
*/
|
||||
List<MetaCountMetric> getCountMetrics();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Comparator for timed metrics sorted by name and then count.
|
||||
*/
|
||||
public class SortMetric {
|
||||
|
||||
public static final Comparator<MetaCountMetric> COUNT_NAME = new CountName();
|
||||
|
||||
public static final Comparator<MetaTimedMetric> NAME = new Name();
|
||||
public static final Comparator<MetaTimedMetric> COUNT = new Count();
|
||||
public static final Comparator<MetaTimedMetric> TOTAL = new Total();
|
||||
public static final Comparator<MetaTimedMetric> MEAN = new Mean();
|
||||
public static final Comparator<MetaTimedMetric> MAX = new Max();
|
||||
|
||||
private static int stringCompare(String name, String name2) {
|
||||
if (name == null) {
|
||||
return name2 == null ? 0 : -1;
|
||||
}
|
||||
if (name2 == null) {
|
||||
return 1;
|
||||
}
|
||||
return name.compareTo(name2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort MetaCountMetric's by name.
|
||||
*/
|
||||
public static class CountName implements Comparator<MetaCountMetric> {
|
||||
|
||||
@Override
|
||||
public int compare(MetaCountMetric o1, MetaCountMetric o2) {
|
||||
return stringCompare(o1.getName(), o2.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by name.
|
||||
*/
|
||||
public static class Name implements Comparator<MetaTimedMetric> {
|
||||
|
||||
@Override
|
||||
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
|
||||
int i = stringCompare(o1.getName(), o2.getName());
|
||||
return i != 0 ? i : Long.compare(o1.getCount(), o2.getCount());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by count desc.
|
||||
*/
|
||||
public static class Count implements Comparator<MetaTimedMetric> {
|
||||
|
||||
@Override
|
||||
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
|
||||
return Long.compare(o2.getCount(), o1.getCount());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by total time desc.
|
||||
*/
|
||||
public static class Total implements Comparator<MetaTimedMetric> {
|
||||
|
||||
@Override
|
||||
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
|
||||
return Long.compare(o2.getTotal(), o1.getTotal());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by mean desc.
|
||||
*/
|
||||
public static class Mean implements Comparator<MetaTimedMetric> {
|
||||
|
||||
@Override
|
||||
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
|
||||
return Long.compare(o2.getMean(), o1.getMean());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by max desc.
|
||||
*/
|
||||
public static class Max implements Comparator<MetaTimedMetric> {
|
||||
|
||||
@Override
|
||||
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
|
||||
return Long.compare(o2.getMax(), o1.getMax());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package io.ebean.metric;
|
||||
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
|
||||
/**
|
||||
* Metric for timed events like transaction execution times.
|
||||
*/
|
||||
public interface CountMetric {
|
||||
|
||||
/**
|
||||
* Add to the counter.
|
||||
*/
|
||||
void add(long micros);
|
||||
|
||||
/**
|
||||
* Increment the counter by 1.
|
||||
*/
|
||||
void increment();
|
||||
|
||||
/**
|
||||
* Return the count value.
|
||||
*/
|
||||
long get(boolean reset);
|
||||
|
||||
/**
|
||||
* Return true if there are no metrics collected since the last collection.
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Reset the statistics.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Visit non empty metrics.
|
||||
*/
|
||||
void visit(MetricVisitor visitor);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package io.ebean.metric;
|
||||
|
||||
import io.ebean.meta.MetaCountMetric;
|
||||
|
||||
public interface CountMetricStats extends MetaCountMetric {
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebean.metric;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.meta.MetricType;
|
||||
|
||||
/**
|
||||
@@ -24,9 +25,14 @@ public interface MetricFactory {
|
||||
*/
|
||||
TimedMetric createTimedMetric(MetricType metricType, String name);
|
||||
|
||||
/**
|
||||
* Create a counter metric.
|
||||
*/
|
||||
CountMetric createCountMetric(MetricType metricType, String name);
|
||||
|
||||
/**
|
||||
* Create a Timed metric.
|
||||
*/
|
||||
QueryPlanMetric createQueryPlanMetric(MetricType metricType, Class<?> type, String label, String sql);
|
||||
QueryPlanMetric createQueryPlanMetric(MetricType metricType, Class<?> type, String label, ProfileLocation profileLocation, String sql);
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.ServiceLoader;
|
||||
*/
|
||||
class MetricServiceProvider {
|
||||
|
||||
private static MetricFactory metricFactory = init();
|
||||
private static final MetricFactory metricFactory = init();
|
||||
|
||||
private static MetricFactory init() {
|
||||
|
||||
|
||||
@@ -223,7 +223,6 @@ public interface BeanType<T> {
|
||||
|
||||
/**
|
||||
* Visit all children recursively
|
||||
* @param visitor
|
||||
*/
|
||||
void visitAllInheritanceChildren(Consumer<BeanType<?>> visitor);
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ public interface ExpressionPath {
|
||||
/**
|
||||
* Return the underlying bean property.
|
||||
*/
|
||||
public Property getProperty();
|
||||
Property getProperty();
|
||||
|
||||
/**
|
||||
* The ElPrefix plus name.
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package io.ebean.plugin;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
|
||||
/**
|
||||
* Property of a entity bean that is a ToMany property.
|
||||
*/
|
||||
public interface PropertyAssocMany extends Property {
|
||||
|
||||
/**
|
||||
* Add the loaded current bean to its associated parent.
|
||||
* <p>
|
||||
* Helper method used by Ebean Elastic integration when loading with a persistence context.
|
||||
*/
|
||||
void lazyLoadMany(EntityBean current);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.ebean.service;
|
||||
|
||||
import io.ebean.FetchGroup;
|
||||
import io.ebean.Query;
|
||||
|
||||
/**
|
||||
* Extension of Query to build FetchGroup via query beans.
|
||||
*/
|
||||
public interface SpiFetchGroupQuery<T> extends Query<T> {
|
||||
|
||||
/**
|
||||
* Build the fetch group with select and fetch clauses.
|
||||
*/
|
||||
FetchGroup<T> buildFetchGroup();
|
||||
}
|
||||
@@ -23,4 +23,10 @@ public interface SpiFetchGroupService {
|
||||
* @return The FetchGroupBuilder to add additional select and fetch clauses
|
||||
*/
|
||||
<T> FetchGroupBuilder<T> of(Class<T> beanType);
|
||||
|
||||
/**
|
||||
* Return a new FetchGroupQuery for building FetchGroup via query beans.
|
||||
*/
|
||||
<T> SpiFetchGroupQuery<T> queryFor(Class<T> beanType);
|
||||
|
||||
}
|
||||
|
||||
@@ -49,13 +49,12 @@ class PathPropertiesParser {
|
||||
private String getPath() {
|
||||
do {
|
||||
char c1 = chars[pos++];
|
||||
switch (c1) {
|
||||
case '(':
|
||||
return currentWord();
|
||||
default:
|
||||
if (pos == 1) {
|
||||
return "";
|
||||
}
|
||||
if (c1 == '(') {
|
||||
return currentWord();
|
||||
} else {
|
||||
if (pos == 1) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
} while (pos < eof);
|
||||
throw new RuntimeException("Hit EOF while reading sectionTitle from " + startPos);
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
@@ -107,9 +108,7 @@ public class AnnotationUtil {
|
||||
* Finds all annotations recusively for a class and its superclasses or interfaces.
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> findAnnotationsRecursive(Class<?> clazz, Class<A> annotationType) {
|
||||
if (annotationType == null) {
|
||||
return null;
|
||||
}
|
||||
Objects.requireNonNull(annotationType);
|
||||
Set<A> ret = new LinkedHashSet<>();
|
||||
Set<Annotation> visited = new HashSet<>();
|
||||
Set<Class<?>> visitedInterfaces = new HashSet<>();
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package io.ebean.util;
|
||||
|
||||
/**
|
||||
* Integer to base64 encoder.
|
||||
*/
|
||||
public final class EncodeB64 {
|
||||
|
||||
private static final int radix = 1 << 6;
|
||||
private static final int mask = radix - 1;
|
||||
|
||||
/**
|
||||
* Convert the integer to unsigned base 64.
|
||||
*/
|
||||
public static String enc(int i) {
|
||||
char[] buf = new char[32];
|
||||
int charPos = 32;
|
||||
do {
|
||||
buf[--charPos] = intToBase64[i & mask];
|
||||
i >>>= 6;
|
||||
} while (i != 0);
|
||||
|
||||
return new String(buf, charPos, (32 - charPos));
|
||||
}
|
||||
|
||||
private static final char intToBase64[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
|
||||
};
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import java.util.List;
|
||||
*/
|
||||
public class BeanCacheResult<T> {
|
||||
|
||||
private List<Entry<T>> list = new ArrayList<>();
|
||||
private final List<Entry<T>> list = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Add an entry.
|
||||
|
||||
@@ -115,10 +115,10 @@ public class BindParams implements Serializable {
|
||||
* Return a Natural Key bind param if supported.
|
||||
*/
|
||||
public NaturalKeyBindParam getNaturalKeyBindParam() {
|
||||
if (positionedParameters != null) {
|
||||
if (!positionedParameters.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (namedParameters != null && namedParameters.size() == 1) {
|
||||
if (namedParameters.size() == 1) {
|
||||
Entry<String, Param> e = namedParameters.entrySet().iterator().next();
|
||||
return new NaturalKeyBindParam(e.getKey(), e.getValue().getInValue());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebeaninternal.server.expression.IdInExpression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Used for bean cache lookup with where ids in expression.
|
||||
*/
|
||||
public class CacheIdLookup<T> {
|
||||
|
||||
private final IdInExpression idInExpression;
|
||||
|
||||
private int remaining;
|
||||
|
||||
public CacheIdLookup(IdInExpression idInExpression) {
|
||||
this.idInExpression = idInExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Id values for the in expression.
|
||||
*/
|
||||
public Collection<?> idValues() {
|
||||
return idInExpression.idValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the hits returning the beans fetched from cache and
|
||||
* adjusting the in expression (to not fetch the hits).
|
||||
*/
|
||||
public List<T> removeHits(BeanCacheResult<T> cacheResult) {
|
||||
|
||||
Set<Object> hitIds = new HashSet<>();
|
||||
List<T> beans = new ArrayList<>(hitIds.size());
|
||||
|
||||
for (BeanCacheResult.Entry<T> hit : cacheResult.hits()) {
|
||||
hitIds.add(hit.getKey());
|
||||
beans.add(hit.getBean());
|
||||
}
|
||||
|
||||
this.remaining = idInExpression.removeIds(hitIds);
|
||||
return beans;
|
||||
}
|
||||
|
||||
public boolean allHits() {
|
||||
return remaining == 0;
|
||||
}
|
||||
}
|
||||
@@ -7,22 +7,37 @@ import io.ebean.TxScope;
|
||||
* Helper object to make AOP generated code simpler.
|
||||
*/
|
||||
public class HelpScopeTrans {
|
||||
private static boolean enabled = true;
|
||||
|
||||
/**
|
||||
* Entering an enhanced transactional method.
|
||||
*/
|
||||
public static void enter(TxScope txScope) {
|
||||
server().scopedTransactionEnter(txScope);
|
||||
if (enabled) {
|
||||
server().scopedTransactionEnter(txScope);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exiting an enhanced transactional method.
|
||||
*/
|
||||
public static void exit(Object returnOrThrowable, int opCode) {
|
||||
server().scopedTransactionExit(returnOrThrowable, opCode);
|
||||
if (enabled) {
|
||||
server().scopedTransactionExit(returnOrThrowable, opCode);
|
||||
}
|
||||
}
|
||||
|
||||
private static SpiEbeanServer server() {
|
||||
return (SpiEbeanServer) Ebean.getDefaultServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines if the @Transactional does what is supposed to do or is disabled
|
||||
* (useful only unit testing)
|
||||
*
|
||||
* @param enabled if set to false, @Transactional will not create a transaction
|
||||
*/
|
||||
public static void setEnabled(boolean enabled) {
|
||||
HelpScopeTrans.enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
@@ -17,8 +15,6 @@ import java.util.Set;
|
||||
*/
|
||||
public class LoadBeanRequest extends LoadRequest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LoadBeanRequest.class);
|
||||
|
||||
private final List<EntityBeanIntercept> batch;
|
||||
|
||||
private final LoadBeanBuffer loadBuffer;
|
||||
@@ -27,11 +23,14 @@ public class LoadBeanRequest extends LoadRequest {
|
||||
|
||||
private final boolean loadCache;
|
||||
|
||||
private boolean loadedFromCache;
|
||||
|
||||
/**
|
||||
* Construct for lazy load request.
|
||||
*/
|
||||
public LoadBeanRequest(LoadBeanBuffer LoadBuffer, String lazyLoadProperty, boolean loadCache) {
|
||||
this(LoadBuffer, null, true, lazyLoadProperty, loadCache);
|
||||
public LoadBeanRequest(LoadBeanBuffer LoadBuffer, EntityBeanIntercept ebi, boolean loadCache) {
|
||||
this(LoadBuffer, null, true, ebi.getLazyLoadProperty(), loadCache);
|
||||
this.loadedFromCache = ebi.isLoadedFromCache();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,10 +55,16 @@ public class LoadBeanRequest extends LoadRequest {
|
||||
return loadBuffer.getBeanDescriptor().getBeanType();
|
||||
}
|
||||
|
||||
public boolean isLoadCache() {
|
||||
return loadCache;
|
||||
/**
|
||||
* Return true if the beans invoking lazy loading were previously loaded from cache.
|
||||
*/
|
||||
public boolean isLoadedFromCache() {
|
||||
return loadedFromCache;
|
||||
}
|
||||
|
||||
private boolean isLoadCache() {
|
||||
return loadCache;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return "path:" + loadBuffer.getFullPath() + " batch:" + batch.size();
|
||||
@@ -75,17 +80,10 @@ public class LoadBeanRequest extends LoadRequest {
|
||||
/**
|
||||
* Return the load context.
|
||||
*/
|
||||
public LoadBeanBuffer getLoadContext() {
|
||||
private LoadBeanBuffer getLoadContext() {
|
||||
return loadBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property that invoked the lazy loading.
|
||||
*/
|
||||
public String getLazyLoadProperty() {
|
||||
return lazyLoadProperty;
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return getLoadContext().getBatchSize();
|
||||
}
|
||||
@@ -93,30 +91,14 @@ public class LoadBeanRequest extends LoadRequest {
|
||||
/**
|
||||
* Return the list of Id values for the beans in the lazy load buffer.
|
||||
*/
|
||||
public List<Object> getIdList(int batchSize) {
|
||||
public List<Object> getIdList() {
|
||||
|
||||
List<Object> idList = new ArrayList<>(batchSize);
|
||||
List<Object> idList = new ArrayList<>();
|
||||
|
||||
BeanDescriptor<?> desc = loadBuffer.getBeanDescriptor();
|
||||
for (EntityBeanIntercept ebi : batch) {
|
||||
EntityBean bean = ebi.getOwner();
|
||||
idList.add(desc.getId(bean));
|
||||
idList.add(desc.getId(ebi.getOwner()));
|
||||
}
|
||||
|
||||
|
||||
if (!desc.isMultiValueIdSupported() && !idList.isEmpty()) {
|
||||
int extraIds = batchSize - batch.size();
|
||||
if (extraIds > 0) {
|
||||
// for performance make up the Id's to the batch size
|
||||
// so we get the same query (for Ebean and the db)
|
||||
Object firstId = idList.get(0);
|
||||
for (int i = 0; i < extraIds; i++) {
|
||||
// just add the first Id again
|
||||
idList.add(firstId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return idList;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.api;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.util.StringHelper;
|
||||
import io.ebeaninternal.server.core.BindPadding;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
@@ -65,13 +66,6 @@ public class LoadManyRequest extends LoadRequest {
|
||||
return batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the load context.
|
||||
*/
|
||||
public LoadManyBuffer getLoadContext() {
|
||||
return loadContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if lazy loading should only load the id values.
|
||||
* <p>
|
||||
@@ -80,14 +74,14 @@ public class LoadManyRequest extends LoadRequest {
|
||||
* used.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isOnlyIds() {
|
||||
private boolean isOnlyIds() {
|
||||
return onlyIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we should load the Collection ids into the cache.
|
||||
*/
|
||||
public boolean isLoadCache() {
|
||||
private boolean isLoadCache() {
|
||||
return loadCache;
|
||||
}
|
||||
|
||||
@@ -98,22 +92,16 @@ public class LoadManyRequest extends LoadRequest {
|
||||
return loadContext.getBatchSize();
|
||||
}
|
||||
|
||||
private List<Object> getParentIdList(int batchSize) {
|
||||
private List<Object> getParentIdList() {
|
||||
|
||||
ArrayList<Object> idList = new ArrayList<>(batchSize);
|
||||
List<Object> idList = new ArrayList<>();
|
||||
|
||||
BeanPropertyAssocMany<?> many = getMany();
|
||||
for (BeanCollection<?> bc : batch) {
|
||||
idList.add(many.getParentId(bc.getOwnerBean()));
|
||||
}
|
||||
if (!many.getTargetDescriptor().isMultiValueIdSupported()) {
|
||||
int extraIds = batchSize - batch.size();
|
||||
if (extraIds > 0) {
|
||||
Object firstId = idList.get(0);
|
||||
for (int i = 0; i < extraIds; i++) {
|
||||
idList.add(firstId);
|
||||
}
|
||||
}
|
||||
if (many.getTargetDescriptor().isPadInExpression()) {
|
||||
BindPadding.padIds(idList);
|
||||
}
|
||||
|
||||
return idList;
|
||||
@@ -123,7 +111,7 @@ public class LoadManyRequest extends LoadRequest {
|
||||
return loadContext.getBeanProperty();
|
||||
}
|
||||
|
||||
public SpiQuery<?> createQuery(SpiEbeanServer server, int batchSize) {
|
||||
public SpiQuery<?> createQuery(SpiEbeanServer server) {
|
||||
|
||||
BeanPropertyAssocMany<?> many = getMany();
|
||||
|
||||
@@ -142,10 +130,7 @@ public class LoadManyRequest extends LoadRequest {
|
||||
}
|
||||
|
||||
query.setLazyLoadForParents(many);
|
||||
|
||||
List<Object> idList = getParentIdList(batchSize);
|
||||
many.addWhereParentIdIn(query, idList, loadContext.isUseDocStore());
|
||||
|
||||
many.addWhereParentIdIn(query, getParentIdList(), loadContext.isUseDocStore());
|
||||
query.setPersistenceContext(loadContext.getPersistenceContext());
|
||||
|
||||
String mode = isLazy() ? "+lazy" : "+query";
|
||||
|
||||
@@ -7,7 +7,9 @@ import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
@@ -21,9 +23,7 @@ public class ManyWhereJoins implements Serializable {
|
||||
|
||||
private final TreeMap<String, PropertyJoin> joins = new TreeMap<>();
|
||||
|
||||
private StringBuilder formulaProperties = new StringBuilder();
|
||||
|
||||
private boolean formulaWithJoin;
|
||||
private List<String> formulaJoinProperties;
|
||||
|
||||
private boolean aggregation;
|
||||
|
||||
@@ -125,27 +125,24 @@ public class ManyWhereJoins implements Serializable {
|
||||
* specifically for the findCount query.
|
||||
*/
|
||||
public void addFormulaWithJoin(String propertyName) {
|
||||
if (formulaWithJoin) {
|
||||
formulaProperties.append(",");
|
||||
} else {
|
||||
formulaProperties = new StringBuilder();
|
||||
formulaWithJoin = true;
|
||||
if (formulaJoinProperties == null) {
|
||||
formulaJoinProperties = new ArrayList<>();
|
||||
}
|
||||
formulaProperties.append(propertyName);
|
||||
formulaJoinProperties.add(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the query select includes a formula with join.
|
||||
*/
|
||||
public boolean isFormulaWithJoin() {
|
||||
return formulaWithJoin;
|
||||
return formulaJoinProperties != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the formula properties to build the select clause for a findCount query.
|
||||
*/
|
||||
public String getFormulaProperties() {
|
||||
return formulaProperties.toString();
|
||||
public List<String> getFormulaJoinProperties() {
|
||||
return formulaJoinProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,8 +12,8 @@ import java.util.Map;
|
||||
*/
|
||||
public class NaturalKeyEntry {
|
||||
|
||||
private Map<String,Object> map = new HashMap<>();
|
||||
private Object key;
|
||||
private final Map<String,Object> map = new HashMap<>();
|
||||
private final Object key;
|
||||
private Object inValue;
|
||||
|
||||
/**
|
||||
|
||||
@@ -69,18 +69,18 @@ public class NaturalKeyQueryData<T> {
|
||||
/**
|
||||
* Match for IN expression. We only allow one IN clause.
|
||||
*/
|
||||
public List<Object> matchIn(String propName, List<Object> sourceValues) {
|
||||
public boolean matchIn(String propName, List<Object> inValues) {
|
||||
if (hasIn) {
|
||||
// only 1 IN allowed (to project naturalIds)
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
if (matchProperty(propName)) {
|
||||
this.hasIn = true;
|
||||
this.inProperty = propName;
|
||||
this.inValues = new ArrayList<>(sourceValues);
|
||||
return this.inValues;
|
||||
this.inValues = inValues;
|
||||
return true;
|
||||
}
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,21 +198,19 @@ public class NaturalKeyQueryData<T> {
|
||||
this.hitCount = hits.size();
|
||||
|
||||
List<T> beans = new ArrayList<>(hitCount);
|
||||
|
||||
for (BeanCacheResult.Entry<T> hit : hits) {
|
||||
if (inValues != null) {
|
||||
Object naturalKey = hit.getKey();
|
||||
Object inValue = set.getInValue(naturalKey);
|
||||
inValues.remove(inValue);
|
||||
|
||||
} else if (inPairs != null) {
|
||||
Object naturalKey = hit.getKey();
|
||||
Pairs.Entry inValue = (Pairs.Entry)set.getInValue(naturalKey);
|
||||
inPairs.remove(inValue);
|
||||
}
|
||||
removeKey(set.getInValue(hit.getKey()));
|
||||
beans.add(hit.getBean());
|
||||
}
|
||||
|
||||
return beans;
|
||||
}
|
||||
|
||||
private void removeKey(Object inValue) {
|
||||
if (inValues != null) {
|
||||
inValues.remove(inValue);
|
||||
} else if (inPairs != null) {
|
||||
//noinspection SuspiciousMethodCalls
|
||||
inPairs.remove(inValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public class ScopedTransaction extends SpiTransactionProxy {
|
||||
/**
|
||||
* Stack of 'nested' transactions.
|
||||
*/
|
||||
private ArrayStack<ScopeTrans> stack = new ArrayStack<>();
|
||||
private final ArrayStack<ScopeTrans> stack = new ArrayStack<>();
|
||||
|
||||
private ScopeTrans current;
|
||||
|
||||
@@ -70,7 +70,7 @@ public class ScopedTransaction extends SpiTransactionProxy {
|
||||
|
||||
private void clearScopeOnce() {
|
||||
if (!scopeCleared) {
|
||||
manager.set(null);
|
||||
manager.clear();
|
||||
scopeCleared = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
public interface SpiCacheControl {
|
||||
|
||||
/**
|
||||
* Return true if bean caching or query caching.
|
||||
*/
|
||||
boolean isCaching();
|
||||
|
||||
/**
|
||||
* Return true if bean caching.
|
||||
*/
|
||||
boolean isBeanCaching();
|
||||
|
||||
/**
|
||||
* Return true if natural key caching.
|
||||
*/
|
||||
boolean isNaturalKeyCaching();
|
||||
|
||||
/**
|
||||
* Return true if query caching.
|
||||
*/
|
||||
boolean isQueryCaching();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.cache.ServerCacheRegion;
|
||||
|
||||
/**
|
||||
* Cache region can be enabled independently.
|
||||
*/
|
||||
public interface SpiCacheRegion extends ServerCacheRegion {
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.DtoQuery;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebeaninternal.server.dto.DtoMappingRequest;
|
||||
import io.ebeaninternal.server.dto.DtoQueryPlan;
|
||||
|
||||
@@ -37,9 +38,23 @@ public interface SpiDtoQuery<T> extends DtoQuery<T>, SpiSqlBinding {
|
||||
/**
|
||||
* Return the label for the query.
|
||||
*/
|
||||
@Override
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* Return the label with fallback to profile location label.
|
||||
*/
|
||||
String getPlanLabel();
|
||||
|
||||
/**
|
||||
* Obtain the location if necessary.
|
||||
*/
|
||||
void obtainLocation();
|
||||
|
||||
/**
|
||||
* Return the profile location.
|
||||
*/
|
||||
ProfileLocation getProfileLocation();
|
||||
|
||||
/**
|
||||
* Return the associated DTO bean type.
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user