Compare commits

...
Author SHA1 Message Date
rob bygrave 850db70be3 [maven-release-plugin] prepare release ebean-12.1.13 2020-02-22 08:59:20 +13:00
rob bygrave ee81ee4d7c test only update of ddl review for mysql-create-all.sql 2020-02-22 08:50:32 +13:00
Rob BygraveandGitHub 4cbeb282eb Merge pull request #1954 from boeckers/added_MySqlDbExpression.json
Add JSON expression handing for MySql - MySqlDbExpression.json
2020-02-22 08:40:09 +13:00
Michael Böckers 5278c010ba added MySqlDbExpression.json 2020-02-21 12:58:18 +01:00
rob bygrave ea490a5ac3 Collect the DB schemas in the model via MTable 2020-02-21 17:16:28 +13:00
rob bygrave e4390ed8a2 #1952 - Entity bean with @Id and ONLY @WhenCreated treated as reference bean - not inserted 2020-02-21 00:14:23 +13:00
Rob BygraveandGitHub a23d9f7db8 Merge pull request #1949 from sebastianmrozek/master
Test usingDatabase with a non default db
2020-02-20 22:43:53 +13:00
Sebastian Mrozek b1704ff5dc Test usingDatabase with a non default db
Move the test to separate class with better name.
2020-02-20 22:13:38 +13:00
rob bygrave c0d752b445 #1941 - @History it seems does not work well when it got generated with ebean.allQuotedIdentifiers enabled 2020-02-20 16:51:07 +13:00
Rob BygraveandGitHub ef5ea59559 Merge pull request #1948 from ebean-orm/feature/queryUsingDatabase
ENH: Add query.usingDatabase(database)
2020-02-20 16:42:25 +13:00
rob bygrave de42655bbd Refactor tests using assertSql() helper method
This helper method trims column alias from the sql (for Oracle)
2020-02-20 15:08:43 +13:00
rob bygrave 661230909c ENH: Add query.usingDatabase(database) - add better test 2020-02-19 11:48:47 +13:00
rob bygrave e9325a81f7 ENH: Add query.usingDatabase(database) 2020-02-19 11:41:06 +13:00
Rob BygraveandGitHub 78b9066345 Merge pull request #1946 from ebean-orm/feature/orderByDeprecate
Deprecate orderBy() migrate to order()
2020-02-19 10:00:15 +13:00
rob bygrave 1959e01844 Javadoc update only - change server to database in examples 2020-02-18 23:43:39 +13:00
rob bygrave cf6179c86b Deprecate orderBy() migrate to order() - update javadoc 2020-02-18 23:36:48 +13:00
rob bygrave 168dacffa7 Deprecate orderBy() migrate to order() 2020-02-18 23:27:43 +13:00
rob bygrave 6961bf5787 #1945 - ENH: Add query.orderById(boolean) to ExpressionList ... improve fluid style 2020-02-17 16:47:37 +13:00
rob bygrave a14288b06d Refactor tidy DefaultExpressionList, no functional change 2020-02-17 16:40:03 +13:00
rob bygrave 171d1a19f4 #1937 - When add a new col with @DbComment in Entity,the DbMigration does not generate comment ddl 2020-02-17 14:19:19 +13:00
rob bygrave cbaaad89ab #1942 - Bump datasource to 4.7.3, includes - datasource.offline() closes busy connections ... should let them close on return 2020-02-17 11:51:40 +13:00
Rob BygraveandGitHub 413290a040 Merge pull request #1939 from ebean-orm/feature/1938
#1938 - API consistency add setParameters(varargs) & setParameter() - migrate from setNextParameter() and setParams()
2020-02-17 11:37:34 +13:00
rob bygrave 8feb100ac6 #1938 - API consistency add setParameters(varargs) & setParameter() - migrate from setNextParameter() and setParams() 2020-02-15 02:01:02 +13:00
rob bygrave d236988035 [maven-release-plugin] prepare for next development iteration 2020-02-09 22:23:59 +13:00
rob bygrave df0d84424c [maven-release-plugin] prepare release ebean-12.1.12 2020-02-09 22:23:48 +13:00
rob bygrave fb30a15a5b Update to ebean-maven-plugin 12.1.12 2020-02-09 22:21:14 +13:00
rob bygrave 3707d611b1 No effective change - EBasicVer extend Model 2020-02-07 22:07:38 +13:00
rob bygrave 60aa720777 No effective change - javadoc format SpiTransaction 2020-02-07 20:53:08 +13:00
rob bygrave 427152a894 Add test for IllegalStateException("Transaction is Inactive") 2020-02-07 20:15:59 +13:00
rob bygrave 3e43d544fb #1936 - ENH: Add saveAll(Object... beans) ... using varargs for DB and Database 2020-02-07 16:10:11 +13:00
rob bygrave 62b1da1be2 #1935 - ENH: Add DB.createTransaction() 2020-02-07 15:52:26 +13:00
rob bygrave 8b4eae2f91 #1934 - ENH: Add methods to Model that take explicit transaction - save(transaction), delete(transaction) ... 2020-02-07 13:00:59 +13:00
rob bygrave 4ed3a18b9d #1933 - ENH: Add DtoQuery.usingTransaction(Transaction) ... dto query with supplied transaction 2020-02-07 12:42:10 +13:00
Rob BygraveandGitHub 3c9d7e3127 Merge pull request #1925 from ebean-orm/feature/refatorTxnProfile
#1924 - Refactor for Transaction profiling - base on ProfileLocation / remove profileId
2020-02-04 22:38:44 +13:00
rob bygrave a89744a7bd No functional change - fix error message in DataSourceConfigurationException throw by Ebean 2020-02-03 22:34:10 +13:00
Rob BygraveandGitHub 5962f14874 Merge pull request #1928 from ebean-orm/feature/1755
FIX: Regression of #1775 - set date for other platforms (non MySQL) broken, when ebean.dataTimeZone is set to GMT
2020-02-01 16:03:33 +13:00
Roland Pramlandrob bygrave f161a38334 FIX: Regression of #1775 - set date for other platfroms broken, when ebean.dataTimeZone is set to GMT 2020-02-01 15:59:18 +13:00
Roland Pramlandrob bygrave 13f8da6b2e FIX: Add cause to exception 2020-02-01 14:07:09 +13:00
rob bygrave 9ad14c5306 #1926 - Postgres (Multi value bind) fix related to empty idIn() expression 2020-02-01 14:05:12 +13:00
rob bygrave 61ed4a5a74 Merge branch 'master' of github.com:ebean-orm/ebean 2020-02-01 13:51:48 +13:00
Rob BygraveandGitHub 275f2dbc98 Merge pull request #1927 from ebean-orm/foconis-cache-emptylist
Fix cache emptylist and Fix / improvement for UUIDv1Generator mac address detection
2020-02-01 13:51:25 +13:00
Roland Pramlandrob bygrave 521b6a36ef changed ip.ebeaninternal.api.SpiQuery to io.ebean.Query in Server.exists 2020-02-01 13:46:28 +13:00
Roland Pramlandrob bygrave 0a6c26e5d3 FIX: Virtual Prüfung 2020-02-01 13:38:56 +13:00
Roland Pramlandrob bygrave 33416bffd0 FIX: Detecting MAC address improved 2020-02-01 13:38:44 +13:00
Roland Pramlandrob bygrave 4ce484f3f2 FIX: Cache also empty lists 2020-02-01 13:38:21 +13:00
rob bygrave cacf033647 Merge branch 'foc-imports' 2020-02-01 13:18:55 +13:00
rob bygrave e3dba6bfe1 Failing test for idIn() empty 2020-02-01 13:18:42 +13:00
Roland Pramlandrob bygrave c0b6f291a1 FIX: handle empty collection in "in (...)" queries 2020-02-01 13:06:37 +13:00
rob bygrave 9eab67d82e #1924 - Refactor for Transaction profiling - base on ProfileLocation / remove profileId 2020-02-01 11:31:43 +13:00
rob bygrave 840cb2ee7b [maven-release-plugin] prepare for next development iteration 2020-01-30 18:53:46 +13:00
rob bygrave e0f171b638 [maven-release-plugin] prepare release ebean-12.1.11 2020-01-30 18:53:35 +13:00
rob bygrave 2bb52a9581 #1922 - Performance - Too pessimistic synchronized block for lazy loading on reference bean or l2 cache bean 2020-01-30 18:48:39 +13:00
Rob BygraveandGitHub f1cf94365c Merge pull request #1920 from ebean-orm/feature/createIndexConcurrently
ENH: Add support for Postgres create index concurrently
2020-01-29 20:36:44 +13:00
rob bygrave a894924e96 #1920 Support @Index concurrently and definition 2020-01-29 20:22:32 +13:00
rob bygrave 680a11a532 No effective change - postgres ddl review update 2020-01-29 16:54:23 +13:00
rob bygrave 605150de5c Update ebean-migration to 12.1.3 with support for Postgres create index concurrently 2020-01-29 11:29:29 +13:00
rob bygrave 5ff44703cf [maven-release-plugin] prepare for next development iteration 2020-01-28 14:01:58 +13:00
rob bygrave 99175bf679 [maven-release-plugin] prepare release ebean-12.1.10 2020-01-28 14:01:47 +13:00
rob bygrave acff330b37 #1918 - Ebean 12.1.9 breaks Guice in Stage.PRODUCTION mode for multi tenant apps 2020-01-28 12:07:07 +13:00
rob bygrave df63eeaa8c #1915 - Regression with DiscriminatorValue since #1361 2020-01-28 10:21:29 +13:00
rob bygrave 07aa39c5de #1917 - PostgresPlatform (9+) does not support IdType.IDENTITY? 2020-01-28 09:46:24 +13:00
Rob BygraveandGitHub c51a1b07a4 Merge pull request #1914 from ebean-orm/feature/indexPlatform
ENH: Support @Index platforms attribute - platform specific indexes
2020-01-16 09:23:28 +13:00
rob bygrave bb56725b12 Use unique index rather than constraint when using formula [like lower(column)] 2020-01-15 16:58:55 +13:00
rob bygrave 099adcf6cd Refactor tidy ModelBuildPropertyVisitor - no functional change 2020-01-15 15:52:37 +13:00
rob bygrave 05be24b8b2 ENH: Support @Index platforms attribute - platform specific indexes
This is a potential alternative to using extra-dll.xml. Might be
appropriate to use over extra-dll in small simple cases.

We might look to extend this in the future to allow full raw platform specific ddl - the ability to specify the entire create index statement.
2020-01-15 15:47:14 +13:00
Rob BygraveandGitHub 7d98355d39 Merge pull request #1913 from ebean-orm/feature/MaxMin
Change to use @Aggregation as meta annotation - support newly added @Max, @Min, @Avg annotations
2020-01-14 16:41:44 +13:00
rob bygrave 56562915bf #1912 - Allow @Index(unique=true) to support formula in columns 2020-01-14 16:20:02 +13:00
rob bygrave 07f4ad2500 Change to use @Aggregation as meta annotation - support newly added @Max, @Min, @Avg annotations 2020-01-14 16:14:14 +13:00
rob bygrave 22e43f5fa7 [maven-release-plugin] prepare for next development iteration 2020-01-11 00:01:01 +13:00
rob bygrave 3127bc2154 [maven-release-plugin] prepare release ebean-12.1.9 2020-01-11 00:00:50 +13:00
Rob BygraveandGitHub 8aa1ed6676 Merge pull request #1909 from ebean-orm/feature/mySqlJson
For MySql map @DbJson to mysql JSON db type
2020-01-10 23:59:18 +13:00
rob bygrave 8a0dea1218 #1910 - Change javadoc generation to no longer use pygments doclet (code highlighting) 2020-01-10 23:37:19 +13:00
rob bygrave 1e266a1532 #1895 - Ebean creates invalid sql for particular @ManyToOne 2020-01-10 23:32:58 +13:00
rob bygrave 57cfd25eb5 #1903 - Add ability to set migration path via DbMigration 2020-01-10 16:06:18 +13:00
rob bygrave 2bcce2e648 For MySql map @DbJson to mysql JSON db type 2020-01-10 14:48:26 +13:00
rob bygrave f6e45a6999 For MySql map @DbJson to mysql JSON db type 2020-01-10 14:39:55 +13:00
rob bygrave fa3de7158e No effective change - update mysql ddl review in src/test/ddl-review 2020-01-10 14:15:50 +13:00
rob bygrave 792785dabe Fix for #1902 #1908 - change allowing view based entities to be autoTunable 2020-01-10 14:02:12 +13:00
Rob BygraveandGitHub d0cd74b400 Merge pull request #1908 from FOCONIS/test-setdefaultselectclause
Testcase for #1902
2020-01-10 13:41:24 +13:00
rob bygrave 71d762ab97 #1907 - SQL Server DB Migration for uuid property @NotNull - should drop index before drop constraint 2020-01-10 13:09:11 +13:00
Roland Praml e00713aa29 Testcase for #1902 2020-01-10 01:03:38 +01:00
rob bygrave d70a49e105 No effective change - refactor tidy DefaultOrmQuery 2020-01-10 12:55:05 +13:00
Roland Pramlandrob bygrave 159a9a8e54 #1902 - SingleAttributeQueries with child selection only does not work with autoTune=false (e.g. Views) 2020-01-10 12:49:20 +13:00
rob bygrave db027eb030 #1904 - Bump datasource to 4.7.1 2020-01-09 15:19:17 +13:00
rob bygrave ec55b2f096 Refactor for query plan capture with initial threshold micros - part 3
Use QueryPlanInit
2019-12-24 02:02:11 +13:00
Rob BygraveandGitHub b854943a86 Merge pull request #1899 from ebean-orm/feature/queryPlanCapture
Refactor for query plan capture with initial threshold micros
2019-12-24 00:54:37 +13:00
rob bygrave 8a263d243c Refactor for query plan capture with initial threshold micros - part 2 2019-12-24 00:29:46 +13:00
Rob BygraveandGitHub 0a4f93adc5 #1897 - Indexes names, like index, unique, primary and foreign keys does not honor ebean.allQuotedIdentifiers (#1898) 2019-12-23 18:43:41 +13:00
rob bygrave ffb11019fa #1896 - ebean.allQuotedIdentifiers is ignored for @JoinColumn 2019-12-23 13:30:28 +13:00
rob bygrave 6fcac27dfe Refactor for query plan capture with initial threshold micros 2019-12-23 10:28:08 +13:00
rob bygrave 71295077a5 [maven-release-plugin] prepare for next development iteration 2019-12-17 23:44:36 +13:00
rob bygrave ddbad284ad [maven-release-plugin] prepare release ebean-12.1.8 2019-12-17 23:44:25 +13:00
rob bygrave 1fcec429b0 #1893 - @DbArray with @NotNull ... should persist empty db array rather than fail NOT NULL constraint 2019-12-17 20:33:03 +13:00
rob bygrave c6062fe93e #1893 - @DbArray with @NotNull ... should persist empty db array rather than fail NOT NULL constraint 2019-12-17 20:27:53 +13:00
rob bygrave d8d35b7dd9 #1893 - Failing test for @DbArray with @NotNull 2019-12-17 16:42:09 +13:00
rob bygrave 590cd07d67 #1892 - Refactor change internal use of Ebean to DB 2019-12-13 14:20:51 +13:00
rob bygrave 5cd74bc468 #1892 - Refactor change internal use of Ebean to DB 2019-12-13 14:17:05 +13:00
rob bygrave 502b20be67 #1891 - Deprecate createSqlQuery() ... migrate to sqlQuery() 2019-12-13 13:58:14 +13:00
rob bygrave b3077d44f6 #1890 - Deprecate createSqlUpdate() ... migrate to sqlUpdate() 2019-12-13 13:48:53 +13:00
rob bygrave d4b35cb445 #1889 - NPE at Str.java:16) when using DB.sqlUpdate(...).addBatch() without any bind parameters 2019-12-13 13:35:54 +13:00
rob bygrave 91e7540a39 #1888 - Bump ebean-migration 12.1.2 with updated avaje classpath scanner 2019-12-13 13:06:13 +13:00
rob bygrave 06bd60aaf7 Bump to 12.1.8-SNAPSHOT to align version with query bean generator 2019-12-13 12:42:42 +13:00
rob bygrave 3db2a69312 #1885 - ENH: Add ModuleInfoLoader ... to support automatic registration of entity classes (via generated code using querybean generator) 2019-12-12 01:33:27 +13:00
rob bygrave 5a983b9e0d No effective change - fix spelling in comments 2019-12-11 23:22:30 +13:00
rob bygrave ab7b34779a [maven-release-plugin] prepare for next development iteration 2019-12-06 20:22:43 +13:00
rob bygrave c7aad6078e [maven-release-plugin] prepare release ebean-12.1.6 2019-12-06 20:22:33 +13:00
rob bygrave ccfe9c39cd Bump enhancement plugin 2019-12-06 20:19:17 +13:00
rob bygrave dbdac04883 Add more tests for cascade save on tree structure 2019-12-06 20:18:50 +13:00
rob bygrave 1d369c002d #1880 - Change javadoc references from Cdir to Cidr 2019-12-05 21:20:19 +13:00
rob bygrave 5a1be81603 #1881 - Update Postgres init helper procedures for DB table partitions 2019-12-05 20:10:15 +13:00
rob bygrave dee73da1aa Drop travis Postgres back to 9.6 2019-12-05 17:22:39 +13:00
rob bygrave a7dde87c5f Bump travis to Postgres 11.2 maybe ? 2019-12-05 17:20:23 +13:00
rob bygrave 60fadd448d Bump travis to Postgres 11 2019-12-05 17:12:58 +13:00
rob bygrave 0140d09007 Update tests to use io.avaje:mod-uuid 2019-12-05 10:32:19 +13:00
rob bygrave da5604a38d #1880 - Cidr type stored as INET (instead of CIDR) + named as Cdir (typo) 2019-12-05 08:59:39 +13:00
rob bygrave 937df1395c #1882 - ENH: Add JsonContext.toJsonPretty() ... for pretty JSON output of beans and lists of beans 2019-12-04 22:55:52 +13:00
rob bygrave 89c05007c2 #1881 - Update Postgres init helper procedures for DB table partitions 2019-12-04 22:07:05 +13:00
rob bygrave 4cc9278183 Update review ddl for Postgres 2019-12-04 21:29:58 +13:00
rob bygrave 9841a2c03a #1880 - Cidr type stored as INET (instead of CIDR) + named as Cdir (typo) 2019-12-04 21:28:27 +13:00
rob bygrave 74929472d9 #1879 - For metrics reporting for timed metrics with location by default only report on initial collection 2019-12-03 23:53:13 +13:00
rob bygrave e274a4c512 #1878 - Remove metric type from metric json output 2019-12-03 21:06:13 +13:00
rob bygrave 5d93c44475 #1877 - Adjust metric names add "orm." prefix for orm queries, "dto." for dto queries 2019-12-03 21:01:03 +13:00
rob bygrave 63b802d0b8 [maven-release-plugin] prepare for next development iteration 2019-12-03 10:19:47 +13:00
467 changed files with 7194 additions and 3167 deletions
+17 -60
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>12.1.5</version>
<version>12.1.13</version>
<packaging>jar</packaging>
<name>ebean</name>
@@ -23,37 +23,10 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-12.1.5</tag>
<tag>ebean-12.1.13</tag>
</scm>
<profiles>
<profile>
<!-- Note: to use this profile, you need credentials for the oracle repository in your
settings.xml as described here:
http://docs.oracle.com/middleware/1213/core/MAVEN/config_maven_repo.htm#MAVEN9010 -->
<id>oracle</id>
<dependencies>
<dependency>
<groupId>com.oracle.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>12.2.0.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>maven.oracle.com</id>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<url>https://maven.oracle.com</url>
<layout>default</layout>
</repository>
</repositories>
</profile>
<profile>
<!-- Note: to use this profile, you need to download manually the db2jcc4 driver.
After that, install it into your local maven repository:
@@ -118,25 +91,25 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-annotation</artifactId>
<version>6.1</version>
<version>6.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-types</artifactId>
<version>1.3</version>
<version>2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-datasource</artifactId>
<version>4.6.1</version>
<version>4.7.3</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-migration</artifactId>
<version>12.1.1</version>
<version>12.1.4</version>
</dependency>
<dependency>
@@ -221,17 +194,17 @@
<scope>test</scope>
</dependency>
<!--<dependency>-->
<!--<groupId>oracle</groupId>-->
<!--<artifactId>oracle-jdbc</artifactId>-->
<!--<version>7.0</version>-->
<!--<scope>test</scope>-->
<!--</dependency>-->
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<artifactId>ojdbc10</artifactId>
<version>19.3.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean.test</groupId>
<artifactId>ebean-test-docker</artifactId>
<version>2.10.3</version>
<version>3.1.2</version>
<scope>test</scope>
</dependency>
@@ -308,9 +281,9 @@
</dependency>
<dependency>
<groupId>org.avaje.moduuid</groupId>
<artifactId>avaje-moduuid</artifactId>
<version>2.1</version>
<groupId>io.avaje</groupId>
<artifactId>mod-uuid</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
@@ -323,7 +296,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>12.1.5</version>
<version>12.1.12</version>
<executions>
<execution>
<id>test</id>
@@ -384,23 +357,7 @@
<configuration>
<doctitle>Ebean 12</doctitle>
<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>
<docletArtifact>
<groupId>org.avaje</groupId>
<artifactId>pygments-doclet</artifactId>
<version>1.0.0</version>
</docletArtifact>
<!-- for people using JDK11, our javadoc doclet isn't 11 compatible yet -->
<javadocExecutable>${env.JAVA8_HOME}/bin/javadoc</javadocExecutable>
<additionalparam>
-Xdoclint:none
-include-basedir ${project.basedir}
-attributes "idseparator=-; project_name=${project.name}; \
project_version=${project.version}; \
project_desc=${project.description}"
</additionalparam>
<linksource>true</linksource>
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
</configuration>
+28 -3
View File
@@ -86,14 +86,14 @@ public class DB {
// /**
// * Register the server with this Ebean singleton. Specify if the registered
// * server is the primary/default server.
// * server is the primary/default database.
// */
// public static void register(EbeanServer server, boolean defaultServer) {
// serverMgr.register(server, defaultServer);
// }
//
// /**
// * Backdoor for registering a mock implementation of EbeanServer as the default server.
// * Backdoor for registering a mock implementation of EbeanServer as the default database.
// */
// protected static EbeanServer mock(String name, EbeanServer server, boolean defaultServer) {
// EbeanServer originalPrimaryServer = serverMgr.defaultServer;
@@ -176,6 +176,18 @@ public class DB {
return getDefault().beginTransaction();
}
/**
* Create a new transaction that is not held in TransactionThreadLocal.
* <p>
* You will want to do this if you want multiple Transactions in a single
* thread or generally use transactions outside of the TransactionThreadLocal
* management.
* </p>
*/
public static Transaction createTransaction() {
return getDefault().createTransaction();
}
/**
* Start a transaction additionally specifying the isolation level.
*
@@ -442,6 +454,13 @@ public class DB {
return getDefault().saveAll(beans);
}
/**
* Save all the beans from a Collection.
*/
public static int saveAll(Object... beans) throws OptimisticLockException {
return getDefault().saveAll(beans);
}
/**
* This method checks the uniqueness of a bean. I.e. if the save will work. It will return the
* properties that violates an unique / primary key. This may be done in an UI save action to
@@ -650,7 +669,7 @@ public class DB {
* // find orders and their customers
* List<Order> list = DB.find(Order.class)
* .fetch("customer")
* .orderBy("id")
* .order("id")
* .findList();
*
* // sort by customer name ascending, then by order shipDate
@@ -736,8 +755,11 @@ public class DB {
}
/**
* Deprecated - migrate to sqlQuery().
* <p>
* This is an alias for {@link #sqlQuery(String)}.
*/
@Deprecated
public static SqlQuery createSqlQuery(String sql) {
return sqlQuery(sql);
}
@@ -760,8 +782,11 @@ public class DB {
}
/**
* Deprecated - migrate to sqlUpdate().
* <p>
* This is an alias for {@link #sqlUpdate(String)}.
*/
@Deprecated
public static SqlUpdate createSqlUpdate(String sql) {
return sqlUpdate(sql);
}
+16 -7
View File
@@ -3,7 +3,6 @@ package io.ebean;
import io.ebean.annotation.TxIsolation;
import io.ebean.cache.ServerCacheManager;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.ServerConfig;
import io.ebean.meta.MetaInfoManager;
import io.ebean.plugin.Property;
import io.ebean.plugin.SpiServer;
@@ -123,7 +122,7 @@ public interface Database {
String getName();
/**
* Return the ExpressionFactory for this server.
* Return the ExpressionFactory for this database.
*/
ExpressionFactory getExpressionFactory();
@@ -376,7 +375,7 @@ public interface Database {
* // find orders and their customers
* List<Order> list = database.find(Order.class)
* .fetch("customer")
* .orderBy("id")
* .order("id")
* .findList();
*
* // sort by customer name ascending, then by order shipDate
@@ -465,8 +464,11 @@ public interface Database {
SqlQuery sqlQuery(String sql);
/**
* Deprecated - migrate to sqlQuery().
* <p>
* This is an alias for {@link #sqlQuery(String)}.
*/
@Deprecated
SqlQuery createSqlQuery(String sql);
/**
@@ -485,8 +487,11 @@ public interface Database {
SqlUpdate sqlUpdate(String sql);
/**
* Deprecated - migrate to sqlUpdate().
* <p>
* This is an alias for {@link #sqlUpdate(String)}.
*/
@Deprecated
SqlUpdate createSqlUpdate(String sql);
/**
@@ -856,7 +861,7 @@ public interface Database {
* <pre>{@code
* public class Order { ...
*
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
* List<OrderDetail> details;
* ...
* }
@@ -876,6 +881,11 @@ public interface Database {
*/
int saveAll(Collection<?> beans) throws OptimisticLockException;
/**
* Save all the beans.
*/
int saveAll(Object... beans) throws OptimisticLockException;
/**
* Delete the bean.
* <p>
@@ -1051,7 +1061,6 @@ public interface Database {
* Integer returnValue = (Integer) cs.getObject(3);
*
* }</pre>
*
*/
int execute(CallableSql callableSql);
@@ -1299,7 +1308,7 @@ public interface Database {
* public void run() {
* User u1 = database.find(User.class, 1);
* ...
* }
* }
* });
*
* }</pre>
@@ -1348,7 +1357,7 @@ public interface Database {
* User u1 = database.find(User.class, 1);
* ...
* return u1.getEmail();
* }
* }
* });
*
* }</pre>
+2 -2
View File
@@ -34,14 +34,14 @@ public class DatabaseFactory {
}
/**
* Create using ebean.properties to configure the server.
* Create using ebean.properties to configure the database.
*/
public static synchronized Database create(String name) {
return EbeanServerFactory.create(name);
}
/**
* Create using the ServerConfig object to configure the server.
* Create using the ServerConfig object to configure the database.
*/
public static synchronized Database create(DatabaseConfig config) {
return EbeanServerFactory.create(config);
+8 -8
View File
@@ -61,7 +61,7 @@ public interface DocumentStore {
* <pre>{@code
*
* Customer customer =
* server.find(Customer.class)
* database.find(Customer.class)
* .setUseDocStore(true)
* .setId(42)
* .findOne();
@@ -79,7 +79,7 @@ public interface DocumentStore {
* <pre>{@code
*
* List<Customer> newCustomers =
* server.find(Customer.class)
* database.find(Customer.class)
* .setUseDocStore(true)
* .where().eq("status, Customer.Status.NEW)
* .findList();
@@ -99,7 +99,7 @@ public interface DocumentStore {
* <pre>{@code
*
* PagedList<Customer> newCustomers =
* server.find(Customer.class)
* database.find(Customer.class)
* .setUseDocStore(true)
* .where().eq("status, Customer.Status.NEW)
* .setMaxRows(50)
@@ -120,7 +120,7 @@ public interface DocumentStore {
* </p>
* <pre>{@code
*
* server.find(Order.class)
* database.find(Order.class)
* .setUseDocStore(true)
* .where()... // perhaps add predicates
* .findEach((Order order) -> {
@@ -145,7 +145,7 @@ public interface DocumentStore {
* </p>
* <pre>{@code
*
* server.find(Order.class)
* database.find(Order.class)
* .setUseDocStore(true)
* .where()... // perhaps add predicates
* .findEachWhile(new Predicate<Order>() {
@@ -190,7 +190,7 @@ public interface DocumentStore {
* Drop the index from the document store (similar to DDL drop table).
* <pre>{@code
*
* DocumentStore documentStore = server.docStore();
* DocumentStore documentStore = database.docStore();
*
* documentStore.dropIndex("product_copy");
*
@@ -202,7 +202,7 @@ public interface DocumentStore {
* Create an index given a mapping file as a resource in the classPath (similar to DDL create table).
* <pre>{@code
*
* DocumentStore documentStore = server.docStore();
* DocumentStore documentStore = database.docStore();
*
* // uses product_copy.mapping.json resource
* // ... to define mappings for the index
@@ -289,7 +289,7 @@ public interface DocumentStore {
* <pre>{@code
*
* // predicates to select the source documents to copy
* Query<Product> query = server.find(Product.class)
* Query<Product> query = database.find(Product.class)
* .where()
* .ge("whenModified", new Timestamp(since))
* .ge("name", "A")
+23 -2
View File
@@ -77,12 +77,29 @@ public interface DtoQuery<T> {
Optional<T> findOneOrEmpty();
/**
* The same as bind for named parameters.
* Bind all the parameters using index positions.
* <p>
* Binds each parameter moving the index position each time.
* <p>
* A convenience for multiple calls to {@link #setParameter(Object)}
*/
DtoQuery<T> setParameters(Object... value);
/**
* Bind the next parameter using index position.
* <p>
* Bind the parameter using index position starting at 1 and incrementing.
* <p>
*/
DtoQuery<T> setParameter(Object value);
/**
* Bind the named parameter.
*/
DtoQuery<T> setParameter(String name, Object value);
/**
* The same as bind for positioned parameters.
* Bind the parameter by its index position (1 based like JDBC).
*/
DtoQuery<T> setParameter(int position, Object value);
@@ -136,4 +153,8 @@ public interface DtoQuery<T> {
*/
DtoQuery<T> setBufferFetchSizeHint(int bufferFetchSizeHint);
/**
* Use the explicit transaction to execute the query.
*/
DtoQuery<T> usingTransaction(Transaction transaction);
}
+18 -12
View File
@@ -24,6 +24,8 @@ import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
/**
* Ebean will be Deprecated - please migrate to use DB.
* <p>
* Ebean is a registry of {@link Database} by name. Ebean has now been renamed to {@link DB}.
* <p>
* Ebean is effectively this is an alias for {@link DB} which is the new and improved name for Ebean.
@@ -80,7 +82,7 @@ public final class Ebean {
} catch (DataSourceConfigurationException e) {
String msg = "Configuration error creating DataSource for the default Database." +
" This typically means a missing application-test.yaml or missing ebean-test-config dependency." +
" This typically means a missing application-test.yaml or missing ebean-test dependency." +
" See https://ebean.io/docs/trouble-shooting#datasource";
throw new DataSourceConfigurationException(msg, e);
@@ -185,7 +187,7 @@ public final class Ebean {
}
/**
* Return the ExpressionFactory from the default server.
* Return the ExpressionFactory from the default database.
* <p>
* The ExpressionFactory is used internally by the query and ExpressionList to
* build the WHERE and HAVING clauses. Alternatively you can use the
@@ -207,14 +209,14 @@ public final class Ebean {
/**
* Register the server with this Ebean singleton. Specify if the registered
* server is the primary/default server.
* server is the primary/default database.
*/
public static void register(EbeanServer server, boolean defaultServer) {
serverMgr.register(server, defaultServer);
}
/**
* Backdoor for registering a mock implementation of EbeanServer as the default server.
* Backdoor for registering a mock implementation of EbeanServer as the default database.
*/
protected static EbeanServer mock(String name, EbeanServer server, boolean defaultServer) {
EbeanServer originalPrimaryServer = serverMgr.defaultServer;
@@ -462,7 +464,7 @@ public final class Ebean {
* <pre>{@code
* public class Order { ...
*
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
* List<OrderDetail> details;
* ...
* }
@@ -794,7 +796,7 @@ public final class Ebean {
* // find orders and their customers
* List<Order> list = Ebean.find(Order.class)
* .fetch("customer")
* .orderBy("id")
* .order("id")
* .findList();
*
* // sort by customer name ascending, then by order shipDate
@@ -865,6 +867,8 @@ public final class Ebean {
}
/**
* Deprecated - migrate to DB.sqlQuery().
* <p>
* Create a SqlQuery for executing native sql
* query statements.
* <p>
@@ -872,22 +876,24 @@ public final class Ebean {
* annotation for examples.
* </p>
*/
@Deprecated
public static SqlQuery createSqlQuery(String sql) {
return serverMgr.getDefaultServer().createSqlQuery(sql);
return serverMgr.getDefaultServer().sqlQuery(sql);
}
/**
* Deprecated - migrate to DB.sqlUpdate().
* <p>
* Create a sql update for executing native dml statements.
* <p>
* Use this to execute a Insert Update or Delete statement. The statement will
* be native to the database and contain database table and column names.
* </p>
* <p>
* See {@link SqlUpdate} for example usage.
* </p>
*/
@Deprecated
public static SqlUpdate createSqlUpdate(String sql) {
return serverMgr.getDefaultServer().createSqlUpdate(sql);
return serverMgr.getDefaultServer().sqlUpdate(sql);
}
/**
@@ -1193,7 +1199,7 @@ public final class Ebean {
* public void run() {
* User u1 = Ebean.find(User.class, 1);
* ...
* }
* }
* });
*
* }</pre>
@@ -1245,7 +1251,7 @@ public final class Ebean {
* User u1 = Ebean.find(User.class, 1);
* ...
* return u1.getEmail();
* }
* }
* });
*
* }</pre>
@@ -48,7 +48,7 @@ public class EbeanServerFactory {
}
/**
* Create using ebean.properties to configure the server.
* Create using ebean.properties to configure the database.
*/
public static synchronized EbeanServer create(String name) {
@@ -59,7 +59,7 @@ public class EbeanServerFactory {
}
/**
* Create using the ServerConfig object to configure the server.
* Create using the ServerConfig object to configure the database.
*/
public static synchronized EbeanServer create(ServerConfig config) {
+1 -1
View File
@@ -21,7 +21,7 @@ public class EbeanVersion {
static {
try {
Properties prop = new Properties();
try (InputStream in = Ebean.class.getResourceAsStream("/META-INF/maven/io.ebean/ebean/pom.properties")) {
try (InputStream in = DB.class.getResourceAsStream("/META-INF/maven/io.ebean/ebean/pom.properties")) {
if (in != null) {
prop.load(in);
in.close();
+39 -39
View File
@@ -34,14 +34,14 @@ public class Expr {
* Equal To - property equal to the given value.
*/
public static Expression eq(String propertyName, Object value) {
return Ebean.getExpressionFactory().eq(propertyName, value);
return DB.getExpressionFactory().eq(propertyName, value);
}
/**
* Not Equal To - property not equal to the given value.
*/
public static Expression ne(String propertyName, Object value) {
return Ebean.getExpressionFactory().ne(propertyName, value);
return DB.getExpressionFactory().ne(propertyName, value);
}
/**
@@ -49,7 +49,7 @@ public class Expr {
* using a lower() function to make it case insensitive).
*/
public static Expression ieq(String propertyName, String value) {
return Ebean.getExpressionFactory().ieq(propertyName, value);
return DB.getExpressionFactory().ieq(propertyName, value);
}
/**
@@ -59,28 +59,28 @@ public class Expr {
* </p>
*/
public static Expression inRange(String propertyName, Object value1, Object value2) {
return Ebean.getExpressionFactory().inRange(propertyName, value1, value2);
return DB.getExpressionFactory().inRange(propertyName, value1, value2);
}
/**
* Between - property between the two given values.
*/
public static Expression between(String propertyName, Object value1, Object value2) {
return Ebean.getExpressionFactory().between(propertyName, value1, value2);
return DB.getExpressionFactory().between(propertyName, value1, value2);
}
/**
* Between - value between two given properties.
*/
public static Expression between(String lowProperty, String highProperty, Object value) {
return Ebean.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
return DB.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
}
/**
* Greater Than - property greater than the given value.
*/
public static Expression gt(String propertyName, Object value) {
return Ebean.getExpressionFactory().gt(propertyName, value);
return DB.getExpressionFactory().gt(propertyName, value);
}
/**
@@ -88,42 +88,42 @@ public class Expr {
* value.
*/
public static Expression ge(String propertyName, Object value) {
return Ebean.getExpressionFactory().ge(propertyName, value);
return DB.getExpressionFactory().ge(propertyName, value);
}
/**
* Less Than - property less than the given value.
*/
public static Expression lt(String propertyName, Object value) {
return Ebean.getExpressionFactory().lt(propertyName, value);
return DB.getExpressionFactory().lt(propertyName, value);
}
/**
* Less Than or Equal to - property less than or equal to the given value.
*/
public static Expression le(String propertyName, Object value) {
return Ebean.getExpressionFactory().le(propertyName, value);
return DB.getExpressionFactory().le(propertyName, value);
}
/**
* Is Null - property is null.
*/
public static Expression isNull(String propertyName) {
return Ebean.getExpressionFactory().isNull(propertyName);
return DB.getExpressionFactory().isNull(propertyName);
}
/**
* Is Not Null - property is not null.
*/
public static Expression isNotNull(String propertyName) {
return Ebean.getExpressionFactory().isNotNull(propertyName);
return DB.getExpressionFactory().isNotNull(propertyName);
}
/**
* Case insensitive {@link #exampleLike(Object)}
*/
public static ExampleExpression iexampleLike(Object example) {
return Ebean.getExpressionFactory().iexampleLike(example);
return DB.getExpressionFactory().iexampleLike(example);
}
/**
@@ -131,14 +131,14 @@ public class Expr {
* LikeType.RAW (you need to add you own wildcards % and _).
*/
public static ExampleExpression exampleLike(Object example) {
return Ebean.getExpressionFactory().exampleLike(example);
return DB.getExpressionFactory().exampleLike(example);
}
/**
* Create the query by Example expression specifying more options.
*/
public static ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType) {
return Ebean.getExpressionFactory().exampleLike(example, caseInsensitive, likeType);
return DB.getExpressionFactory().exampleLike(example, caseInsensitive, likeType);
}
/**
@@ -146,7 +146,7 @@ public class Expr {
* characters % (percentage) and _ (underscore).
*/
public static Expression like(String propertyName, String value) {
return Ebean.getExpressionFactory().like(propertyName, value);
return DB.getExpressionFactory().like(propertyName, value);
}
/**
@@ -155,14 +155,14 @@ public class Expr {
* a lower() function to make the expression case insensitive.
*/
public static Expression ilike(String propertyName, String value) {
return Ebean.getExpressionFactory().ilike(propertyName, value);
return DB.getExpressionFactory().ilike(propertyName, value);
}
/**
* Starts With - property like value%.
*/
public static Expression startsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().startsWith(propertyName, value);
return DB.getExpressionFactory().startsWith(propertyName, value);
}
/**
@@ -170,14 +170,14 @@ public class Expr {
* lower() function to make the expression case insensitive.
*/
public static Expression istartsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().istartsWith(propertyName, value);
return DB.getExpressionFactory().istartsWith(propertyName, value);
}
/**
* Ends With - property like %value.
*/
public static Expression endsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().endsWith(propertyName, value);
return DB.getExpressionFactory().endsWith(propertyName, value);
}
/**
@@ -185,14 +185,14 @@ public class Expr {
* function to make the expression case insensitive.
*/
public static Expression iendsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().iendsWith(propertyName, value);
return DB.getExpressionFactory().iendsWith(propertyName, value);
}
/**
* Contains - property like %value%.
*/
public static Expression contains(String propertyName, String value) {
return Ebean.getExpressionFactory().contains(propertyName, value);
return DB.getExpressionFactory().contains(propertyName, value);
}
/**
@@ -200,42 +200,42 @@ public class Expr {
* function to make the expression case insensitive.
*/
public static Expression icontains(String propertyName, String value) {
return Ebean.getExpressionFactory().icontains(propertyName, value);
return DB.getExpressionFactory().icontains(propertyName, value);
}
/**
* For collection properties that are empty (have not existing elements).
*/
public static Expression isEmpty(String propertyName) {
return Ebean.getExpressionFactory().isEmpty(propertyName);
return DB.getExpressionFactory().isEmpty(propertyName);
}
/**
* For collection properties that are not empty (have existing elements).
*/
public static Expression isNotEmpty(String propertyName) {
return Ebean.getExpressionFactory().isNotEmpty(propertyName);
return DB.getExpressionFactory().isNotEmpty(propertyName);
}
/**
* In - property has a value in the array of values.
*/
public static Expression in(String propertyName, Object[] values) {
return Ebean.getExpressionFactory().in(propertyName, values);
return DB.getExpressionFactory().in(propertyName, values);
}
/**
* In - using a subQuery.
*/
public static Expression in(String propertyName, Query<?> subQuery) {
return Ebean.getExpressionFactory().in(propertyName, subQuery);
return DB.getExpressionFactory().in(propertyName, subQuery);
}
/**
* In - property has a value in the collection of values.
*/
public static Expression in(String propertyName, Collection<?> values) {
return Ebean.getExpressionFactory().in(propertyName, values);
return DB.getExpressionFactory().in(propertyName, values);
}
/**
@@ -272,14 +272,14 @@ public class Expr {
* }</pre>
*/
public static Expression inOrEmpty(String propertyName, Collection<?> values) {
return Ebean.getExpressionFactory().inOrEmpty(propertyName, values);
return DB.getExpressionFactory().inOrEmpty(propertyName, values);
}
/**
* Id Equal to - ID property is equal to the value.
*/
public static Expression idEq(Object value) {
return Ebean.getExpressionFactory().idEq(value);
return DB.getExpressionFactory().idEq(value);
}
/**
@@ -292,7 +292,7 @@ public class Expr {
* @param propertyMap a map keyed by property names.
*/
public static Expression allEq(Map<String, Object> propertyMap) {
return Ebean.getExpressionFactory().allEq(propertyMap);
return DB.getExpressionFactory().allEq(propertyMap);
}
/**
@@ -303,7 +303,7 @@ public class Expr {
* </p>
*/
public static Expression raw(String raw, Object value) {
return Ebean.getExpressionFactory().raw(raw, value);
return DB.getExpressionFactory().raw(raw, value);
}
/**
@@ -314,14 +314,14 @@ public class Expr {
* </p>
*/
public static Expression raw(String raw, Object[] values) {
return Ebean.getExpressionFactory().raw(raw, values);
return DB.getExpressionFactory().raw(raw, values);
}
/**
* Add raw expression with no parameters.
*/
public static Expression raw(String raw) {
return Ebean.getExpressionFactory().raw(raw);
return DB.getExpressionFactory().raw(raw);
}
/**
@@ -329,7 +329,7 @@ public class Expr {
*/
public static Expression and(Expression expOne, Expression expTwo) {
return Ebean.getExpressionFactory().and(expOne, expTwo);
return DB.getExpressionFactory().and(expOne, expTwo);
}
/**
@@ -337,7 +337,7 @@ public class Expr {
*/
public static Expression or(Expression expOne, Expression expTwo) {
return Ebean.getExpressionFactory().or(expOne, expTwo);
return DB.getExpressionFactory().or(expOne, expTwo);
}
/**
@@ -345,7 +345,7 @@ public class Expr {
*/
public static Expression not(Expression exp) {
return Ebean.getExpressionFactory().not(exp);
return DB.getExpressionFactory().not(exp);
}
/**
@@ -353,7 +353,7 @@ public class Expr {
*/
public static <T> Junction<T> conjunction(Query<T> query) {
return Ebean.getExpressionFactory().conjunction(query);
return DB.getExpressionFactory().conjunction(query);
}
/**
@@ -361,6 +361,6 @@ public class Expr {
*/
public static <T> Junction<T> disjunction(Query<T> query) {
return Ebean.getExpressionFactory().disjunction(query);
return DB.getExpressionFactory().disjunction(query);
}
}
+21 -23
View File
@@ -30,7 +30,7 @@ import java.util.function.Predicate;
* </p>
* <p>
* The ExpressionList also duplicates methods that are found on the Query such
* as findList() and orderBy(). The purpose of these methods is provide a fluid
* as findList() and order(). The purpose of these methods is provide a fluid
* API. The upside of this approach is that you can build and execute a query
* via chained methods. The down side is that this ExpressionList object has
* more methods than you would initially expect (the ones duplicated from
@@ -52,6 +52,14 @@ public interface ExpressionList<T> {
*/
Query<T> query();
/**
* Controls, if paginated queries should always append an 'order by id' statement at the end to
* guarantee a deterministic sort result. This may affect performance.
* If this is not enabled, and an orderBy is set on the query, it's up to the programmer that
* this query provides a deterministic result.
*/
Query<T> orderById(boolean orderById);
/**
* Set the order by clause replacing the existing order by clause if there is
* one.
@@ -59,10 +67,6 @@ public interface ExpressionList<T> {
* This follows SQL syntax using commas between each property with the
* optional asc and desc keywords representing ascending and descending order
* respectively.
* </p>
* <p>
* This is EXACTLY the same as {@link #orderBy(String)}.
* </p>
*/
Query<T> order(String orderByClause);
@@ -77,27 +81,21 @@ public interface ExpressionList<T> {
OrderBy<T> order();
/**
* Return the OrderBy so that you can append an ascending or descending
* property to the order by clause.
* <p>
* This will never return a null. If no order by clause exists then an 'empty'
* OrderBy object is returned.
* </p>
* Deprecated migrate to order().
*/
@Deprecated
OrderBy<T> orderBy();
/**
* Add an orderBy clause to the query.
*
* @see Query#orderBy(String)
* Deprecated migrate to {@link #order(String)}
*/
@Deprecated
Query<T> orderBy(String orderBy);
/**
* Add an orderBy clause to the query.
*
* @see Query#orderBy(String)
* Deprecated migrate to {@link #order(String)}
*/
@Deprecated
Query<T> setOrderBy(String orderBy);
/**
@@ -334,7 +332,7 @@ public interface ExpressionList<T> {
* List<String> names =
* DB.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .order().asc("name")
* .findSingleAttributeList();
*
* }</pre>
@@ -347,7 +345,7 @@ public interface ExpressionList<T> {
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
* .orderBy().asc("name")
* .order().asc("name")
* .setMaxRows(100)
* .findSingleAttributeList();
*
@@ -1451,7 +1449,7 @@ public interface ExpressionList<T> {
* .eq("status", Customer.Status.ACTIVE)
* .gt("id", 0)
* .endAnd()
* .orderBy().asc("name")
* .order().asc("name")
* .findList();
* }</pre>
*/
@@ -1472,7 +1470,7 @@ public interface ExpressionList<T> {
* .or()
* .eq("status", Customer.Status.ACTIVE)
* .isNull("anniversary")
* .orderBy().asc("name")
* .order().asc("name")
* .findList();
*
* }</pre>
@@ -1492,7 +1490,7 @@ public interface ExpressionList<T> {
* .eq("status", Customer.Status.ACTIVE)
* .gt("id", 0)
* .endAnd()
* .orderBy().asc("name")
* .order().asc("name")
* .findList();
*
* }</pre>
@@ -1526,7 +1524,7 @@ public interface ExpressionList<T> {
* .gt("id", 1)
* .eq("anniversary", onAfter)
* .endNot()
* .orderBy()
* .order()
* .asc("name")
* .findList();
*
+3 -6
View File
@@ -1,8 +1,5 @@
package io.ebean;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiTransaction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.NonUniqueResultException;
@@ -70,7 +67,7 @@ public interface ExtendedServer {
*
* @return True if the query finds a matching row in the database
*/
<T> boolean exists(SpiQuery<?> ormQuery, SpiTransaction transaction);
<T> boolean exists(Query<?> ormQuery, Transaction transaction);
/**
* Return the number of 'top level' or 'root' entities this query should return.
@@ -360,7 +357,7 @@ public interface ExtendedServer {
* List<String> names =
* DB.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .order().asc("name")
* .findSingleAttributeList();
*
* }</pre>
@@ -372,7 +369,7 @@ public interface ExtendedServer {
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
* .orderBy().asc("name")
* .order().asc("name")
* .setMaxRows(100)
* .findSingleAttributeList();
*
+1 -1
View File
@@ -86,7 +86,7 @@ public interface Filter<T> {
* expressions.
* </p>
* <p>
* Refer to {@link Ebean#sort(List, String)} for more detail.
* Refer to {@link DB#sort(List, String)} for more detail.
* </p>
*/
Filter<T> sort(String sortByClause);
+1 -1
View File
@@ -32,7 +32,7 @@ import java.util.List;
* public List<Customer> findNew() {
* return query().where()
* .eq("status", Customer.Status.NEW)
* .orderBy("name")
* .order("name")
* .findList()
* }
* }
+35
View File
@@ -192,6 +192,13 @@ public abstract class Model {
db().save(this);
}
/**
* Save this entity with an explicit transaction.
*/
public void save(Transaction transaction) {
db().save(this, transaction);
}
/**
* Flush any batched changes to the database.
* <p>
@@ -212,6 +219,13 @@ public abstract class Model {
db().update(this);
}
/**
* Update this entity with an explicit transaction.
*/
public void update(Transaction transaction) {
db().update(this, transaction);
}
/**
* Insert this entity.
*
@@ -221,6 +235,13 @@ public abstract class Model {
db().insert(this);
}
/**
* Insert with an explicit transaction.
*/
public void insert(Transaction transaction) {
db().insert(this, transaction);
}
/**
* Delete this bean.
* <p>
@@ -242,6 +263,13 @@ public abstract class Model {
return db().delete(this);
}
/**
* Delete this entity with an explicit transaction.
*/
public boolean delete(Transaction transaction) {
return db().delete(this, transaction);
}
/**
* Delete a bean permanently without soft delete.
* <p>
@@ -255,6 +283,13 @@ public abstract class Model {
return db().deletePermanent(this);
}
/**
* Delete a bean permanently without soft delete using an explicit transaction.
*/
public boolean deletePermanent(Transaction transaction) {
return db().deletePermanent(this, transaction);
}
/**
* Refreshes this entity from the database.
*
+1 -1
View File
@@ -30,7 +30,7 @@ import java.util.List;
* .where()
* .eq("store", "def")
* .inPairs(pairs) // IN clause with 'pairs' of values
* .orderBy("sku desc")
* .order("sku desc")
*
* // query expressions cover the natural key properties
* // so we can choose to hit the L2 bean cache if we want
+5 -5
View File
@@ -5,9 +5,9 @@ import io.ebean.config.properties.PropertiesLoader;
import java.util.Properties;
/**
* Provides singleton state for the default server.
* Provides singleton state for the default database.
* <p/>
* Intended for internal use as part of bootup, construction, registration of the default server.
* Intended for internal use as part of bootup, construction, registration of the default database.
*/
class PrimaryServer {
@@ -18,21 +18,21 @@ class PrimaryServer {
private static boolean skip;
/**
* Set whether to skip automatically creating the primary server.
* Set whether to skip automatically creating the primary database.
*/
static synchronized void setSkip(boolean skip) {
PrimaryServer.skip = skip;
}
/**
* Return true to skip automatically creating the primary server.
* Return true to skip automatically creating the primary database.
*/
static synchronized boolean isSkip() {
return skip;
}
/**
* Return the default server name.
* Return the default database name.
*/
static synchronized String getDefaultServerName() {
getProperties();
+17 -2
View File
@@ -31,9 +31,9 @@ public interface ProfileLocation {
}
/**
* Obtain the location description.
* Obtain the description returning true if this is the initial call.
*/
String obtain();
boolean obtain();
/**
* Return a short version of the location description.
@@ -45,8 +45,23 @@ public interface ProfileLocation {
*/
String label();
/**
* Return the full location.
*/
String fullLocation();
/**
* Add execution time.
*/
void add(long executionTime);
/**
* Return true if this request should be traced.
*/
boolean trace();
/**
* Set the number of times to trace the transactions for this profile location.
*/
void setTraceCount(int traceCount);
}
+38 -48
View File
@@ -25,7 +25,7 @@ import java.util.stream.Stream;
* .where()
* .like("customer.name","rob%")
* .gt("orderDate",lastWeek)
* .orderBy("customer.id, id desc")
* .order("customer.id, id desc")
* .setMaxRows(50)
* .findList();
*
@@ -656,6 +656,11 @@ public interface Query<T> {
*/
Query<T> usingConnection(Connection connection);
/**
* Execute the query using the given database.
*/
Query<T> usingDatabase(Database database);
/**
* Execute the query returning the list of Id's.
* <p>
@@ -885,7 +890,7 @@ public interface Query<T> {
* List<String> names =
* DB.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .order().asc("name")
* .findSingleAttributeList();
*
* }</pre>
@@ -898,7 +903,7 @@ public interface Query<T> {
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
* .orderBy().asc("name")
* .order().asc("name")
* .setMaxRows(100)
* .findSingleAttributeList();
*
@@ -1183,6 +1188,30 @@ public interface Query<T> {
*/
Query<T> setParameter(int position, Object value);
/**
* Bind the next positioned parameter.
*
* <pre>{@code
*
* // a query with a positioned parameters
* String oql = "where status = ? and name = ?";
*
* List<Order> list = DB.createQuery(Order.class, oql)
* .setParameter(OrderStatus.NEW)
* .setParameter("Rob")
* .findList();
*
* }</pre>
*/
Query<T> setParameter(Object value);
/**
* Bind all the positioned parameters.
* <p>
* A convenience for multiple calls to {@link #setParameter(Object)}
*/
Query<T> setParameters(Object... values);
/**
* Set the Id value to query. This is used with findOne().
* <p>
@@ -1323,17 +1352,9 @@ public interface Query<T> {
Query<T> having(Expression addExpressionToHaving);
/**
* Set the order by clause replacing the existing order by clause if there is
* one.
* <p>
* This follows SQL syntax using commas between each property with the
* optional asc and desc keywords representing ascending and descending order
* respectively.
* </p>
* <p>
* This is EXACTLY the same as {@link #order(String)}.
* </p>
* Deprecated migrate to {@link #order(String)}
*/
@Deprecated
Query<T> orderBy(String orderByClause);
/**
@@ -1343,10 +1364,6 @@ public interface Query<T> {
* This follows SQL syntax using commas between each property with the
* optional asc and desc keywords representing ascending and descending order
* respectively.
* </p>
* <p>
* This is EXACTLY the same as {@link #orderBy(String)}.
* </p>
*/
Query<T> order(String orderByClause);
@@ -1356,40 +1373,24 @@ public interface Query<T> {
* <p>
* This will never return a null. If no order by clause exists then an 'empty'
* OrderBy object is returned.
* </p>
* <p>
* This is EXACTLY the same as {@link #orderBy()}.
* </p>
*/
OrderBy<T> order();
/**
* Return the OrderBy so that you can append an ascending or descending
* property to the order by clause.
* <p>
* This will never return a null. If no order by clause exists then an 'empty'
* OrderBy object is returned.
* </p>
* <p>
* This is EXACTLY the same as {@link #order()}.
* </p>
* Deprecated migrate to order().
*/
@Deprecated
OrderBy<T> orderBy();
/**
* Set an OrderBy object to replace any existing OrderBy clause.
* <p>
* This is EXACTLY the same as {@link #setOrderBy(OrderBy)}.
* </p>
*/
Query<T> setOrder(OrderBy<T> orderBy);
/**
* Set an OrderBy object to replace any existing OrderBy clause.
* <p>
* This is EXACTLY the same as {@link #setOrder(OrderBy)}.
* </p>
* Deprecated migrate to {@link #setOrder(OrderBy)}
*/
@Deprecated
Query<T> setOrderBy(OrderBy<T> orderBy);
/**
@@ -1524,17 +1525,6 @@ public interface Query<T> {
return setUseQueryCache(enabled ? CacheMode.ON : CacheMode.OFF);
}
/**
* Set an id to identify this query for profiling purposes.
* <p>
* The profileId is expected to be unique for a given bean type.
* </p>
* <p>
* Note that the profileId is treated as a short internally and has a MAX value of 32,767.
* </p>
*/
Query<T> setProfileId(int profileId);
/**
* 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.
+2 -2
View File
@@ -23,9 +23,9 @@ import java.util.Iterator;
* <h3>Try finally style</h3>
* <pre>{@code
*
* Query<Customer> query = server.find(Customer.class)
* Query<Customer> query = database.find(Customer.class)
* .where().gt("id", 0)
* .orderBy("id")
* .order("id")
* .setMaxRows(2);
*
* QueryIterator<Customer> it = query.findIterate();
+9
View File
@@ -50,4 +50,13 @@ public interface ScriptRunner {
*/
void run(URL resource, Map<String, String> placeholderMap);
/**
* Run the raw provided DDL or SQL script.
*
* @param name The name of the script for logging purposes
* @param content The SQL content
* @param useAutoCommit Set to true to use auto commit true and continue when any errors occur
*/
void runScript(String name, String content, boolean useAutoCommit);
}
+49 -16
View File
@@ -131,7 +131,7 @@ public interface SqlQuery extends Serializable {
* String sql = "select max(unit_price) from o_order_detail where order_qty > ?";
*
* BigDecimal maxPrice = DB.sqlQuery(sql)
* .setParameter(1, 2)
* .setParameter(42)
* .findSingleAttribute(BigDecimal.class);
*
* }</pre>
@@ -171,31 +171,24 @@ public interface SqlQuery extends Serializable {
* " where unit_price > ? " +
* " order by (unit_price * order_qty) desc";
*
* //
* List<BigDecimal> lineAmounts =
* DB.sqlQuery(sql)
* .setParameter(1, 3)
* .setParameter(42)
* .findSingleAttributeList(BigDecimal.class);
*
* }</pre>
*
* <p>
* The attributeType can be any scalar type that Ebean supports (includes javax time types, Joda types etc).
* </p>
*
* @param attributeType The type of the returned value
*/
<T> List<T> findSingleAttributeList(Class<T> attributeType);
/**
* The same as bind for named parameters.
*/
SqlQuery setParameter(String name, Object value);
/**
* Set one of more positioned parameters.
* <p>
* This is a convenient alternative to multiple calls setParameter().
* This is a convenient alternative to multiple calls to {@link #setParameter(Object)}.
*
* <pre>{@code
*
@@ -203,27 +196,67 @@ public interface SqlQuery extends Serializable {
*
* List<SqlRow> list =
* DB.sqlQuery(sql)
* .setParams("Rob", Status.NEW)
* .setParameters("Rob", Status.NEW)
* .findList();
*
*
* // is the same as ...
* // effectively the same as ...
*
* .setParameter("Rob")
* .setParameter("Status.NEW)
*
* // and ...
*
* List<SqlRow> list =
* DB.sqlQuery(sql)
* .setParameter(1, "Rob")
* .setParameter(2, "Status.NEW)
* .findList();
*
* }</pre>
*/
SqlQuery setParameters(Object... values);
/**
* Deprecated migrate to setParameters(Object... values)
*/
@Deprecated
SqlQuery setParams(Object... values);
/**
* The same as bind for positioned parameters.
* Set the next bind parameter by position.
* <pre>{@code
*
* String sql = "select id, name from customer where name like ? and status = ?";
*
* List<SqlRow> list =
* DB.sqlQuery(sql)
* .setParameter("Rob")
* .setParameter("Status.NEW)
* .findList();
*
* // the same as ...
*
* .setParameters("Rob", Status.NEW)
*
* // and ...
*
* .setParameter(1, "Rob")
* .setParameter(2, "Status.NEW)
*
* }</pre>
*
* @param value The value to bind
*/
SqlQuery setParameter(Object value);
/**
* Bind the parameter by its index position (1 based like JDBC).
*/
SqlQuery setParameter(int position, Object value);
/**
* Bind the named parameter value.
*/
SqlQuery setParameter(String name, Object value);
/**
* Set the index of the first row of the results to return.
*/
+22 -5
View File
@@ -126,8 +126,6 @@ public interface SqlUpdate {
* {@link Transaction#setBatchMode(boolean)} and
* {@link Transaction#setBatchSize(int)}.
* </p>
*
* @see Ebean#execute(SqlUpdate)
*/
int execute();
@@ -241,28 +239,47 @@ public interface SqlUpdate {
* String sql = "insert into audit_log (id, name, version) values (?,?,?)";
*
* DB.sqlUpdate(sql)
* .setParams(UUID.randomUUID(), "Hello", 1)
* .setParameters(UUID.randomUUID(), "Hello", 1)
* .executeNow();
*
*
* // is the same as ...
*
* DB.sqlUpdate(sql)
* .setParameter(UUID.randomUUID())
* .setParameter("Hello")
* .setParameter(1)
* .executeNow();
*
* // which is the same as ...
*
* DB.sqlUpdate(sql)
* .setParameter(1, UUID.randomUUID())
* .setParameter(2, "Hello")
* .setParameter(3, 1)
* .executeNow();
*
* }</pre>
*
*/
SqlUpdate setParameters(Object... values);
/**
* Deprecated migrate to setParameters(Object... values).
*/
@Deprecated
SqlUpdate setParams(Object... values);
/**
* Set the next positioned parameter.
* Set the next bind parameter by position.
*
* @param value The value to bind
*/
SqlUpdate setParameter(Object value);
/**
* Deprecated migrate to setParameter(value).
*/
@Deprecated
SqlUpdate setNextParameter(Object value);
/**
+3 -3
View File
@@ -27,7 +27,7 @@ public interface Transaction extends AutoCloseable {
* @see Database#currentTransaction()
*/
static Transaction current() {
return Ebean.currentTransaction();
return DB.currentTransaction();
}
/**
@@ -295,7 +295,7 @@ public interface Transaction extends AutoCloseable {
*
* <pre>{@code
*
* try (Transaction transaction = server.beginTransaction()) {
* try (Transaction transaction = database.beginTransaction()) {
*
* // turn on JDBC batch
* transaction.setBatchMode(true);
@@ -318,7 +318,7 @@ public interface Transaction extends AutoCloseable {
* </p>
* <pre>{@code
*
* try (Transaction transaction = server.beginTransaction()) {
* try (Transaction transaction = database.beginTransaction()) {
*
* transaction.setBatchMode(true);
* transaction.setBatchSize(100);
+4 -4
View File
@@ -12,16 +12,16 @@ import java.util.concurrent.Callable;
* <p>
* This information matches the features of the Transactional annotation. You
* can use it directly with Runnable or Callable via
* {@link Ebean#execute(TxScope, Runnable)} or
* {@link Ebean#executeCall(TxScope, Callable)}.
* {@link DB#execute(TxScope, Runnable)} or
* {@link DB#executeCall(TxScope, Callable)}.
* </p>
* <p>
* This object is used internally with the enhancement of a method with
* Transactional annotation.
* </p>
*
* @see Ebean#execute(TxScope, Runnable)
* @see Ebean#executeCall(TxScope, Callable)
* @see DB#execute(TxScope, Runnable)
* @see DB#executeCall(TxScope, Callable)
*/
public final class TxScope {
@@ -1,6 +1,7 @@
package io.ebean.bean;
import io.ebean.Ebean;
import io.ebean.DB;
import io.ebean.Database;
import io.ebean.ValuePair;
import javax.persistence.EntityNotFoundException;
@@ -104,9 +105,6 @@ public final class EntityBeanIntercept implements Serializable {
/**
* Create a intercept with a given entity.
* <p>
* Refer to agent ProxyConstructor.
* </p>
*/
public EntityBeanIntercept(Object ownerBean) {
this.owner = (EntityBean) ownerBean;
@@ -821,14 +819,14 @@ public final class EntityBeanIntercept implements Serializable {
synchronized (this) {
if (beanLoader == null) {
BeanLoader serverLoader = (BeanLoader) Ebean.getServer(ebeanServerName);
if (serverLoader == null) {
throw new PersistenceException("Server [" + ebeanServerName + "] was not found?");
final Database database = DB.byName(ebeanServerName);
if (database == null) {
throw new PersistenceException("Database [" + ebeanServerName + "] was not found?");
}
// For stand alone reference bean or after deserialisation lazy load
// using the ebeanServer. Synchronise only on the bean.
loadBeanInternal(loadProperty, serverLoader);
loadBeanInternal(loadProperty, database.getPluginApi());
return;
}
}
@@ -0,0 +1,48 @@
package io.ebean.bean;
import io.ebean.Database;
/**
* BeanLoader used when single beans are loaded (which is usually not ideal / N+1).
*/
public abstract class SingleBeanLoader implements BeanLoader {
protected final Database database;
SingleBeanLoader(Database database) {
this.database = database;
}
@Override
public String getName() {
return database.getName();
}
/**
* Single bean lazy loaded when bean from L2 cache.
*/
public static class L2 extends SingleBeanLoader {
public L2(Database database) {
super(database);
}
@Override
public void loadBean(EntityBeanIntercept ebi) {
database.getPluginApi().loadBeanL2(ebi);
}
}
/**
* Single bean lazy loaded when a reference bean.
*/
public static class Ref extends SingleBeanLoader {
public Ref(Database database) {
super(database);
}
@Override
public void loadBean(EntityBeanIntercept ebi) {
database.getPluginApi().loadBeanRef(ebi);
}
}
}
@@ -1,6 +1,6 @@
package io.ebean.common;
import io.ebean.Ebean;
import io.ebean.DB;
import io.ebean.ExpressionList;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanCollectionLoader;
@@ -93,7 +93,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
void lazyLoadCollection(boolean onlyIds) {
if (loader == null) {
loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
loader = (BeanCollectionLoader) DB.byName(ebeanServerName);
}
loader.loadMany(this, onlyIds);
checkEmptyLazyLoad();
@@ -88,7 +88,6 @@ public class DbConstraintNaming {
* Return the primary key constraint name.
*/
public String primaryKeyName(String tableName) {
return pkPrefix + normaliseTable(tableName) + pkSuffix;
}
@@ -103,7 +102,6 @@ public class DbConstraintNaming {
* Return the index name associated with a foreign key constraint given multiple columns.
*/
public String foreignKeyIndexName(String tableName, String[] columns) {
String colPart = joinColumnNames(columns);
return fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix;
}
@@ -112,7 +110,6 @@ public class DbConstraintNaming {
* Return the index name associated with a foreign key constraint given a single column foreign key.
*/
public String foreignKeyIndexName(String tableName, String column) {
String colPart = normaliseTable(column);
return fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix;
}
@@ -121,7 +118,6 @@ public class DbConstraintNaming {
* Return the index name for a general index (not associated with a foreign key).
*/
public String indexName(String tableName, String column) {
String colPart = normaliseTable(column);
return indexPrefix + normaliseTable(tableName) + indexMiddle + colPart + indexSuffix;
}
@@ -130,7 +126,6 @@ public class DbConstraintNaming {
* Return the index name for a general index (not associated with a foreign key).
*/
public String indexName(String tableName, String[] columns) {
String colPart = joinColumnNames(columns);
return indexPrefix + normaliseTable(tableName) + indexMiddle + colPart + indexSuffix;
}
@@ -139,7 +134,6 @@ public class DbConstraintNaming {
* Join the column names together with underscores.
*/
protected String joinColumnNames(String[] columns) {
if (columns.length == 1) {
return normaliseColumn(columns[0]);
}
@@ -157,7 +151,6 @@ public class DbConstraintNaming {
* Return the unique constraint name.
*/
public String uniqueConstraintName(String tableName, String columnName) {
return uqPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + uqSuffix;
}
@@ -165,7 +158,6 @@ public class DbConstraintNaming {
* Return the unique constraint name.
*/
public String uniqueConstraintName(String tableName, String[] columns) {
String colPart = joinColumnNames(columns);
return uqPrefix + normaliseTable(tableName) + "_" + colPart + uqSuffix;
}
@@ -174,7 +166,6 @@ public class DbConstraintNaming {
* Return the check constraint name.
*/
public String checkConstraintName(String tableName, String columnName) {
return ckPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + ckSuffix;
}
@@ -41,17 +41,20 @@ public class DbConstraintNormalise {
}
/**
* Normalise the column name by removing any quoted identifier characters.
* Normalise the column name by removing any quoted identifier characters and formula brackets.
*/
public String normaliseColumn(String columnName) {
columnName = trimQuotes(columnName);
columnName = trimBrackets(trimQuotes(columnName));
if (lowerCaseColumns) {
columnName = columnName.toLowerCase();
}
return columnName;
}
private String trimBrackets(String value) {
return value.replace("(","").replace(")","");
}
/**
* Lower case the table name checking for quoted identifiers.
*/
@@ -29,7 +29,7 @@ public class DocStoreConfig {
protected boolean create;
/**
* The URL of the Document store server. For example: http://localhost:9200.
* The URL of the Document store. For example: http://localhost:9200.
*/
protected String url;
@@ -131,7 +131,7 @@ public class DocStoreConfig {
}
/**
* Set the URL to the Document store server.
* Set the URL to the Document store.
* <p>
* For a local ElasticSearch server this would be: http://localhost:9200
*/
@@ -0,0 +1,21 @@
package io.ebean.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used by generated code to hold entity classes to register with Ebean.
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ModuleInfo {
/**
* Returns the entity classes with db name prefix.
* <p>
* The db name prefix is added to entity classes for non default databases.
*/
String[] entities() default {};
}
@@ -0,0 +1,19 @@
package io.ebean.config;
import java.util.List;
/**
* Loads and returns entity classes to register with Ebean databases.
*/
public interface ModuleInfoLoader {
/**
* Return the entity classes to register with the default DB.
*/
List<Class<?>> entityClasses();
/**
* Return entity classes to register for a named DB (not default DB).
*/
List<Class<?>> entityClassesFor(String dbName);
}
@@ -17,6 +17,13 @@ public class PlatformConfig {
private boolean allQuotedIdentifiers;
private DbConstraintNaming constraintNaming;
/**
* Flag set when a supplied constraintNaming is used.
*/
private boolean customConstraintNaming;
/**
* The database boolean true value (typically either 1, T, or Y).
*/
@@ -63,7 +70,7 @@ public class PlatformConfig {
* Construct with defaults.
*/
public PlatformConfig() {
this.constraintNaming = new DbConstraintNaming();
}
/**
@@ -80,6 +87,19 @@ public class PlatformConfig {
this.allQuotedIdentifiers = platformConfig.allQuotedIdentifiers;
this.databaseInetAddressVarchar = platformConfig.databaseInetAddressVarchar;
this.customDbTypeMappings = platformConfig.customDbTypeMappings;
this.constraintNaming = new DbConstraintNaming(!allQuotedIdentifiers);
}
public DbConstraintNaming getConstraintNaming() {
return constraintNaming;
}
/**
* Set a custom database constraint naming convention.
*/
public void setConstraintNaming(DbConstraintNaming constraintNaming) {
this.customConstraintNaming = true;
this.constraintNaming = constraintNaming;
}
/**
@@ -94,6 +114,9 @@ public class PlatformConfig {
*/
public void setAllQuotedIdentifiers(boolean allQuotedIdentifiers) {
this.allQuotedIdentifiers = allQuotedIdentifiers;
if (!customConstraintNaming) {
this.constraintNaming = new DbConstraintNaming(!allQuotedIdentifiers);
}
}
/**
+59 -20
View File
@@ -132,6 +132,15 @@ public class ServerConfig {
private TenantCatalogProvider tenantCatalogProvider;
/**
* When true will load entity classes via ModuleInfoLoader.
* <p>
* NB: ModuleInfoLoader implementations are generated by querybean generator.
* Having this on and registering entity classes means we don't need to manually
* write that code or use classpath scanning to find entity classes.
*/
private boolean loadModuleInfo;
/**
* List of interesting classes such as entities, embedded, ScalarTypes,
* Listeners, Finders, Controllers etc.
@@ -344,11 +353,6 @@ public class ServerConfig {
*/
private NamingConvention namingConvention = new UnderscoreNamingConvention();
/**
* Naming convention used in DDL generation for primary keys, foreign keys etc.
*/
private DbConstraintNaming constraintNaming = new DbConstraintNaming();
/**
* Behaviour of updates in JDBC batch to by default include all properties.
*/
@@ -488,6 +492,11 @@ public class ServerConfig {
*/
private boolean collectQueryPlans;
/**
* The default threshold in micros for collecting query plans.
*/
private long collectQueryPlanThresholdMicros = Long.MAX_VALUE;
/**
* The time in millis used to determine when a query is alerted for being slow.
*/
@@ -1600,14 +1609,14 @@ public class ServerConfig {
* Return the constraint naming convention used in DDL generation.
*/
public DbConstraintNaming getConstraintNaming() {
return constraintNaming;
return platformConfig.getConstraintNaming();
}
/**
* Set the constraint naming convention used in DDL generation.
*/
public void setConstraintNaming(DbConstraintNaming constraintNaming) {
this.constraintNaming = constraintNaming;
platformConfig.setConstraintNaming(constraintNaming);
}
/**
@@ -1877,7 +1886,7 @@ public class ServerConfig {
}
/**
* Return the database platform to use for this server.
* Return the database platform to use for this database.
*/
public DatabasePlatform getDatabasePlatform() {
return databasePlatform;
@@ -2273,15 +2282,21 @@ public class ServerConfig {
* </p>
*
* @param cls the entity type (or other type) that should be registered by this
* server.
* database.
*/
public void addClass(Class<?> cls) {
if (classes == null) {
classes = new ArrayList<>();
}
classes.add(cls);
}
/**
* Register all the classes (typically entity classes).
*/
public void addAll(List<Class<?>> classList) {
if (classList != null && !classList.isEmpty()) {
classes.addAll(classList);
}
}
/**
* Add a package to search for entities via class path search.
* <p>
@@ -2289,9 +2304,6 @@ public class ServerConfig {
* </p>
*/
public void addPackage(String packageName) {
if (packages == null) {
packages = new ArrayList<>();
}
packages.add(packageName);
}
@@ -2317,7 +2329,7 @@ public class ServerConfig {
/**
* Set the list of classes (entities, listeners, scalarTypes etc) that should
* be used for this server.
* be used for this database.
* <p>
* If no classes are specified then the classes are found automatically via
* searching the class path.
@@ -2331,7 +2343,7 @@ public class ServerConfig {
}
/**
* Return the classes registered for this server. Typically this includes
* Return the classes registered for this database. Typically this includes
* entities and perhaps listeners.
*/
public List<Class<?>> getClasses() {
@@ -2838,12 +2850,14 @@ public class ServerConfig {
}
loadDocStoreSettings(p);
loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo);
maxCallStack = p.getInt("maxCallStack", maxCallStack);
dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown);
dumpMetricsOptions = p.get("dumpMetricsOptions", dumpMetricsOptions);
queryPlanTTLSeconds = p.getInt("queryPlanTTLSeconds", queryPlanTTLSeconds);
slowQueryMillis = p.getLong("slowQueryMillis", slowQueryMillis);
collectQueryPlans = p.getBoolean("collectQueryPlans", collectQueryPlans);
collectQueryPlanThresholdMicros = p.getLong("collectQueryPlanThresholdMicros", collectQueryPlanThresholdMicros);
docStoreOnly = p.getBoolean("docStoreOnly", docStoreOnly);
disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache);
enabledL2Regions = p.get("enabledL2Regions", enabledL2Regions);
@@ -2962,20 +2976,20 @@ public class ServerConfig {
return classes;
}
List<Class<?>> classes = new ArrayList<>();
List<Class<?>> classList = new ArrayList<>();
String[] split = StringHelper.splitNames(classNames);
for (String cn : split) {
if (!"class".equalsIgnoreCase(cn)) {
try {
classes.add(Class.forName(cn));
classList.add(Class.forName(cn));
} catch (ClassNotFoundException e) {
String msg = "Error registering class [" + cn + "] from [" + classNames + "]";
throw new RuntimeException(msg, e);
}
}
}
return classes;
return classList;
}
private List<String> getSearchList(String searchNames, List<String> defaultValue) {
@@ -3229,6 +3243,20 @@ public class ServerConfig {
this.collectQueryPlans = collectQueryPlans;
}
/**
* Return the query plan collection threshold in microseconds.
*/
public long getCollectQueryPlanThresholdMicros() {
return collectQueryPlanThresholdMicros;
}
/**
* Set the query plan collection threshold in microseconds.
*/
public void setCollectQueryPlanThresholdMicros(long collectQueryPlanThresholdMicros) {
this.collectQueryPlanThresholdMicros = collectQueryPlanThresholdMicros;
}
/**
* Return true if metrics should be dumped when the server is shutdown.
*/
@@ -3259,6 +3287,17 @@ public class ServerConfig {
this.dumpMetricsOptions = dumpMetricsOptions;
}
/**
* Return true if entity classes should be loaded and registered via ModuleInfoLoader.
* <p>
* When false we either register entity classes via application code or use classpath
* scanning to find and register entity classes.
* </p>
*/
public boolean isAutoLoadModuleInfo() {
return loadModuleInfo && classes.isEmpty();
}
public enum UuidVersion {
VERSION4,
VERSION1,
@@ -29,6 +29,8 @@ public class DbPlatformTypeMapping {
private static final DbPlatformType INET_NATIVE = new DbPlatformType("inet", false);
private static final DbPlatformType INET_VARCHAR = new DbPlatformType("varchar", 50);
private static final DbPlatformType CIDR_NATIVE = new DbPlatformType("cidr", false);
private static final DbPlatformType CIDR_VARCHAR = new DbPlatformType("varchar", 50);
private static final DbPlatformType UUID_NATIVE = new DbPlatformType("uuid", false);
@SuppressWarnings("unused")
@@ -110,6 +112,7 @@ public class DbPlatformTypeMapping {
put(DbType.JSONVARCHAR, new DbPlatformType("jsonvarchar", 1000));
put(DbType.UUID, UUID_NATIVE);
put(DbType.INET, INET_NATIVE);
put(DbType.CIDR, CIDR_NATIVE);
} else {
put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
@@ -126,6 +129,7 @@ public class DbPlatformTypeMapping {
// default to native UUID and override on platform configure()
put(DbType.UUID, UUID_NATIVE);
put(DbType.INET, INET_VARCHAR);
put(DbType.CIDR, CIDR_VARCHAR);
}
}
@@ -36,7 +36,7 @@ public enum DbType {
UUID(ExtraDbTypes.UUID),
INET(ExtraDbTypes.INET),
CDIR(ExtraDbTypes.CDIR),
CIDR(ExtraDbTypes.CIDR),
POINT(ExtraDbTypes.POINT),
POLYGON(ExtraDbTypes.POLYGON),
@@ -41,7 +41,7 @@ public interface ExtraDbTypes {
int JSONBlob = 5005;
int INET = 5020;
int CDIR = 5021;
int CIDR = 5021;
/**
* Geo Point
@@ -47,7 +47,7 @@ public class ClickHousePlatform extends DatabasePlatform {
dbTypeMap.put(DbType.UUID, new DbPlatformType("UUID", false));
dbTypeMap.put(DbType.INET, new DbPlatformType("String", false));
dbTypeMap.put(DbType.CDIR, new DbPlatformType("String", false));
dbTypeMap.put(DbType.CIDR, new DbPlatformType("String", false));
}
@Override
@@ -65,6 +65,8 @@ public class MySqlPlatform extends DatabasePlatform {
dbTypeMap.put(DbType.BLOB, new MySqlBlob());
dbTypeMap.put(DbType.BINARY, new DbPlatformType("binary", 255));
dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false));
dbTypeMap.put(DbType.JSONB, new DbPlatformType("json", false));
}
@Override
@@ -14,8 +14,6 @@ public class Postgres8Platform extends PostgresPlatform {
super();
this.dbIdentity.setSupportsGetGeneratedKeys(false);
this.dbIdentity.setIdType(IdType.SEQUENCE);
this.dbIdentity.setSupportsSequence(true);
this.dbIdentity.setSupportsIdentity(true);
this.columnAliasPrefix = "as c";
}
@@ -44,6 +44,7 @@ public class PostgresPlatform extends DatabasePlatform {
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsSequence(true);
this.dbIdentity.setSupportsIdentity(true);
this.dbDefaultValue.setNow("current_timestamp");
@@ -51,7 +52,7 @@ public class PostgresPlatform extends DatabasePlatform {
new SqlErrorCodes()
.addAcquireLock("55P03")
.addDuplicateKey("23505")
.addDataIntegrity("23000","23502","23503","23514")
.addDataIntegrity("23000", "23502", "23503", "23514")
.addSerializableConflict("40001")
.build();
@@ -63,6 +64,7 @@ public class PostgresPlatform extends DatabasePlatform {
dbTypeMap.put(DbType.UUID, new DbPlatformType("uuid", false));
dbTypeMap.put(DbType.INET, new DbPlatformType("inet", false));
dbTypeMap.put(DbType.CIDR, new DbPlatformType("cidr", false));
dbTypeMap.put(DbType.HSTORE, new DbPlatformType("hstore", false));
dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false));
dbTypeMap.put(DbType.JSONB, new DbPlatformType("jsonb", false));
@@ -127,7 +129,6 @@ public class PostgresPlatform extends DatabasePlatform {
@Override
public boolean tablePartitionsExist(Connection connection, String table) throws SQLException {
try (PreparedStatement statement = connection.prepareStatement("select count(*) from pg_inherits i WHERE i.inhparent = ?::regclass")) {
statement.setString(1, table);
try (ResultSet resultSet = statement.executeQuery()) {
@@ -138,18 +139,15 @@ public class PostgresPlatform extends DatabasePlatform {
/**
* Return SQL using built in partition helper functions to create some initial partitions.
*
* <p>
* Only use this if extra-ddl doesn't have some initial partitions defined (which it should).
*/
@Override
public String tablePartitionInit(String tableName, PartitionMode mode, String property, String pkey) {
if (property == null) {
property = "";
}
if (pkey == null) {
pkey = "";
}
return "select partition('" + mode.name().toLowerCase() + "','" + tableName + "','" + pkey + "','" + property + "',1);";
// default partition required pg11 but this is only used for testing but bumped test docker container to pg11 by default
return
"create table " + tableName + "_default" + " partition of " + tableName + " default;\n" +
"select partition('" + mode.name().toLowerCase() + "','" + tableName + "',1);";
}
}
@@ -1,6 +1,6 @@
package io.ebean.dbmigration;
import io.ebean.EbeanServer;
import io.ebean.Database;
import io.ebean.annotation.Platform;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
@@ -62,11 +62,28 @@ public interface DbMigration {
*/
void setPathToResources(String pathToResources);
/**
* Set the path where migrations are generated to (which defaults to "dbmigration").
* <p>
* Normally we only use this when we use Ebean to generate the database migrations
* and then use some other tool like FlywayDB to run the migrations.
* <p>
* Example: with <code>setMigrationPath("db/migration")</code> ... the migrations
* are generated into <code>src/resources/db/migration</code>.
* <p>
* Note that if Ebean migration runner is used we should not use this method but
* instead set the migrationPath via a property such that both the migration generator
* and migration runner both use the same path.
*
* @param migrationPath The path that migrations are generated into.
*/
void setMigrationPath(String migrationPath);
/**
* Set the server to use to determine the current model.
* Typically this is not called explicitly.
*/
void setServer(EbeanServer ebeanServer);
void setServer(Database database);
/**
* Set the serverConfig to use. Typically this is not called explicitly.
@@ -76,7 +93,7 @@ public interface DbMigration {
/**
* Set the specific platform to generate DDL for.
* <p>
* If not set this defaults to the platform of the default server.
* If not set this defaults to the platform of the default database.
* </p>
*/
void setPlatform(Platform platform);
@@ -84,7 +101,7 @@ public interface DbMigration {
/**
* Set the specific platform to generate DDL for.
* <p>
* If not set this defaults to the platform of the default server.
* If not set this defaults to the platform of the default database.
* </p>
*/
void setPlatform(DatabasePlatform databasePlatform);
@@ -15,8 +15,8 @@ package io.ebean.event;
*
* Object extaBeanToSave = ...;
* Transaction t = request.getTransaction();
* EbeanServer server = request.getEbeanServer();
* server.save(extraBeanToSave, t);
* Database server = request.getEbeanServer();
* database.save(extraBeanToSave, t);
*
* }</pre>
* <p>
@@ -1,6 +1,6 @@
package io.ebean.event;
import io.ebean.Ebean;
import io.ebean.DB;
import java.util.Set;
@@ -8,7 +8,7 @@ import java.util.Set;
* Listen for bulk table events that occur.
* <p>
* These events can be triggered via
* {@link Ebean#externalModification(String, boolean, boolean, boolean)} or
* {@link DB#externalModification(String, boolean, boolean, boolean)} or
* automatically determined from Ebean bulk update statements.
*/
public interface BulkTableEventListener {
@@ -33,11 +33,6 @@ public interface MetaInfoManager {
*/
List<MetricData> collectMetricsAsData();
/**
* Collect query plans.
*/
List<MetaQueryPlan> collectQueryPlans(QueryPlanRequest request);
/**
* Visit the metrics resetting and collecting/reporting as desired.
*/
@@ -54,4 +49,21 @@ public interface MetaInfoManager {
*/
void resetAllMetrics();
/**
* Initiate query plan collection by turning on "bind capture" on matching query plans.
* <p>
* Also refer to ServerConfig collectQueryPlans that needs to be set to true
* and collectQueryPlanThresholdMicros which is a global defaults that can also
* initiate query plan capture.
*
* @return The query plans that have had bind capture turned on by this request.
*/
List<MetaQueryPlan> queryPlanInit(QueryPlanInit initRequest);
/**
* Collect query plans in the foreground.
*/
List<MetaQueryPlan> queryPlanCollectNow(QueryPlanRequest request);
}
@@ -25,12 +25,4 @@ public interface MetaQueryMetric extends MetaTimedMetric {
*/
String getHash();
/**
* Return true if this is the first metrics collection for this query.
* <p>
* This can be used to suppress including the SQL and location from metrics
* content.
* </p>
*/
boolean initialCollection();
}
@@ -30,4 +30,13 @@ public interface MetaTimedMetric extends MetaMetric {
* Return the mean execution time in micros.
*/
long getMean();
/**
* Return true if this is the first metrics collection for this query.
* <p>
* This can be used to suppress including the SQL and location from metrics
* content.
* </p>
*/
boolean initialCollection();
}
@@ -0,0 +1,67 @@
package io.ebean.meta;
import java.util.HashSet;
import java.util.Set;
/**
* Initiate query plan collection for plans by their hash or all query plans.
*/
public class QueryPlanInit {
private boolean all;
private Set<String> hashes = new HashSet<>();
private long thresholdMicros;
/**
* Return true if this initiates bind collection on all query plans.
*/
public boolean isAll() {
return all;
}
/**
* Set to true to initiate bind collection on all query plans.
*/
public void setAll(boolean all) {
this.all = all;
}
/**
* Return the query execution time threshold which must be exceeded to initiate
* query plan collection.
*/
public long getThresholdMicros() {
return thresholdMicros;
}
/**
* Set the query execution time threshold which must be exceeded to initiate
* query plan collection.
*/
public void setThresholdMicros(long thresholdMicros) {
this.thresholdMicros = thresholdMicros;
}
/**
* Return true if the query plan should be initiated based on it's hash.
*/
public boolean includeHash(String hash) {
return all || hashes.contains(hash);
}
/**
* Return the specific hashes that we want to collect query plans on.
*/
public Set<String> getHashes() {
return hashes;
}
/**
* Set the specific hashes that we want to collect query plans on.
*/
public void setHashes(Set<String> hashes) {
this.hashes = hashes;
}
}
@@ -1,97 +1,66 @@
package io.ebean.meta;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Request used to capture query plans.
*/
public class QueryPlanRequest {
private final List<MetaQueryPlan> plans = new ArrayList<>();
private Connection connection;
private boolean store;
private long since;
private Set<Class<?>> includedBeanTypes;
private int maxCount;
private Set<String> includedLabels;
public List<MetaQueryPlan> getPlans() {
return plans;
}
private long maxTimeMillis;
/**
* Return the connection to use to capture the query plans.
*/
public Connection getConnection() {
return connection;
}
/**
* Set the connection to use to capture the query plans.
*/
public void setConnection(Connection connection) {
this.connection = connection;
}
/**
* Return true if the captured query plan is stored.
*/
public boolean isStore() {
return store;
}
/**
* Set to true to store the captured query plan.
*/
public void setStore(boolean store) {
this.store = store;
}
/**
* Return the epoch time after which the query plan was capture (to be included).
* Return the epoch time in millis for minimum bind capture time.
* <p>
* When set this ensures that the bind values used to get the query plan
* have been around for a while (e.g. 5 mins) and so reasonably represent
* bind values that match the slowest execution for this query plan.
*/
public long getSince() {
return since;
}
/**
* Set the epoch time after which the query plan was captured.
* <p>
* This is used to only capture plans that have changed since a given time (like the time of last capture).
* </p>
* Set the epoch time (e.g. 5 mins ago) such that the query bind values
* reasonably represent bind values that match the slowest execution for this query plan.
*
* @param since The time after which the query plan was captured to be included
* @param since The minimum age of the bind values capture.
*/
public void setSince(long since) {
this.since = since;
}
/**
* Process consume the query plan.
* Return the maximum number of plans to capture.
*/
public void process(MetaQueryPlan plan) {
plans.add(plan);
public int getMaxCount() {
return maxCount;
}
/**
* Return true if the bean type should be included in the query plan capture.
* Set the maximum number of plans to capture.
*/
public boolean includeType(Class<?> beanType) {
return includedBeanTypes == null || includedBeanTypes.isEmpty() || includedBeanTypes.contains(beanType);
public void setMaxCount(int maxCount) {
this.maxCount = maxCount;
}
/**
* Return true if the label should be included in the query plan capture.
* Return the maximum amount of time we want to use to capture plans.
* <p>
* Query plan collection will stop once this time is exceeded.
*/
public boolean includeLabel(String label) {
return includedLabels == null || includedLabels.isEmpty() || includedLabels.contains(label);
public long getMaxTimeMillis() {
return maxTimeMillis;
}
/**
* Set the maximum amount of time we want to use to capture plans.
* <p>
* Query plan collection will stop once this time is exceeded.
*/
public void setMaxTimeMillis(long maxTimeMillis) {
this.maxTimeMillis = maxTimeMillis;
}
}
@@ -8,14 +8,9 @@ import java.util.Comparator;
public interface ServerMetricsAsJson {
/**
* Set to false to exclude profile location.
* Set to false to exclude profile location and sql.
*/
ServerMetricsAsJson withLocation(boolean withLocation);
/**
* Set to false to exclude SQL for query metrics.
*/
ServerMetricsAsJson withSql(boolean withSql);
ServerMetricsAsJson withExtraAttributes(boolean withLocation);
/**
* Set to false to exclude SQL hash.
@@ -25,11 +25,6 @@ public interface BeanType<T> {
@Nonnull
String getName();
/**
* Return the profileId of the bean type.
*/
short getProfileId();
/**
* Return the full name of the bean type.
*/
+19 -2
View File
@@ -1,6 +1,8 @@
package io.ebean.plugin;
import io.ebean.EbeanServer;
import io.ebean.bean.BeanLoader;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
@@ -10,7 +12,7 @@ import java.util.List;
/**
* Extensions to Database API made available to plugins.
*/
public interface SpiServer extends EbeanServer {
public interface SpiServer extends EbeanServer, BeanLoader {
/**
* Return the serverConfig.
@@ -18,7 +20,7 @@ public interface SpiServer extends EbeanServer {
ServerConfig getServerConfig();
/**
* Return the DatabasePlatform for this server.
* Return the DatabasePlatform for this database.
*/
DatabasePlatform getDatabasePlatform();
@@ -52,4 +54,19 @@ public interface SpiServer extends EbeanServer {
*/
DataSource getReadOnlyDataSource();
/**
* Invoke lazy loading on this single bean (reference bean).
*/
void loadBeanRef(EntityBeanIntercept ebi);
/**
* Invoke lazy loading on this single bean (L2 cache bean).
*/
void loadBeanL2(EntityBeanIntercept ebi);
/**
* Invoke lazy loading on this single bean when no BeanLoader is set.
* Typically due to serialisation or multiple stateless updates.
*/
void loadBean(EntityBeanIntercept ebi);
}
@@ -13,7 +13,7 @@ package io.ebean.search;
* .lowFreqOperatorAnd(true)
* .highFreqOperatorAnd(true);
*
* List<Customer> customers = server.find(Customer.class)
* List<Customer> customers = database.find(Customer.class)
* .text()
* .textCommonTerms("the brown", options)
* .findList();
@@ -13,7 +13,7 @@ package io.ebean.search;
* .lenient(true)
* .opAnd();
*
* List<Customer> customers = server.find(Customer.class)
* List<Customer> customers = database.find(Customer.class)
* .text()
* .textSimple("quick brown", options)
* .findList();
@@ -24,7 +24,7 @@ package io.ebean.search;
* // just use default options
* TextQueryString options = new TextQueryString();
*
* List<Customer> customers = server.find(Customer.class)
* List<Customer> customers = database.find(Customer.class)
* .text()
* .textSimple("quick brown", options)
* .findList();
@@ -13,7 +13,7 @@ package io.ebean.search;
* .lenient(true)
* .opAnd();
*
* List<Customer> customers = server.find(Customer.class)
* List<Customer> customers = database.find(Customer.class)
* .text()
* .textSimple("quick brown", options)
* .findList();
@@ -12,7 +12,7 @@ public interface SpiContainer {
/**
* Create the EbeanServer for a given configuration.
*
* @param configuration The configuration information for this server.
* @param configuration The configuration information for this database.
*/
EbeanServer createServer(ServerConfig configuration);
@@ -149,6 +149,13 @@ public interface JsonContext {
*/
String toJson(Object value) throws JsonIOException;
/**
* Return the bean or collection as JSON string in pretty format.
*
* @throws JsonIOException When IOException occurs
*/
String toJsonPretty(Object value) throws JsonIOException;
/**
* Write the bean or collection in JSON format to the writer.
*
@@ -38,6 +38,11 @@ public class BindParams implements Serializable {
*/
private String bindHash;
/**
* Helper to add positioned parameters in order.
*/
private int addPos;
public BindParams() {
}
@@ -156,6 +161,19 @@ public class BindParams implements Serializable {
p.setOutType(outType);
}
public void setNextParameters(Object... values) {
for (Object value : values) {
setNextParameter(value);
}
}
/**
* Bind the next positioned parameter.
*/
public void setNextParameter(Object value) {
setParameter(++addPos, value);
}
/**
* Using position set the In value of a parameter. Note that for nulls you
* must use setNullParameter.
@@ -0,0 +1,80 @@
package io.ebeaninternal.api;
import io.ebean.meta.MetricType;
import io.ebean.meta.MetricVisitor;
import io.ebean.metric.CountMetric;
import io.ebean.metric.MetricFactory;
import io.ebean.metric.TimedMetric;
/**
* Extra metrics collected to measure internal behaviour.
*/
public class ExtraMetrics {
private final TimedMetric bindCapture;
private final TimedMetric planCollect;
private final CountMetric loadOneL2;
private final CountMetric loadOneRef;
private final CountMetric loadOneNoLoader;
/**
* Create the extra metrics.
*/
public ExtraMetrics() {
final MetricFactory factory = MetricFactory.get();
this.bindCapture = factory.createTimedMetric(MetricType.ORM, "ebean.queryplan.bindcapture");
this.planCollect = factory.createTimedMetric(MetricType.ORM, "ebean.queryplan.collect");
this.loadOneL2 = factory.createCountMetric(MetricType.ORM, "loadone.l2");
this.loadOneRef = factory.createCountMetric(MetricType.ORM, "loadone.ref");
this.loadOneNoLoader = factory.createCountMetric(MetricType.ORM, "loadone.noloader");
}
/**
* Timed metric for bind capture used with query plan collection.
*/
public TimedMetric getBindCapture() {
return bindCapture;
}
/**
* Timed metric for query plan collection.
*/
public TimedMetric getPlanCollect() {
return planCollect;
}
/**
* Increment counter for lazy loading one bean from L2 cache.
* All good when lazy loading also hits L2 cache.
*/
public void incrementLoadOneL2() {
loadOneL2.increment();
}
/**
* Increment counter for lazy loading on reference bean.
* We ought to be able to avoid this by changing to a tuned query.
*/
public void incrementLoadOneRef() {
loadOneRef.increment();
}
/**
* Increment counter for lazy loading one bean due to no loader.
* Likely due to multiple stateless updates or serialisation.
*/
public void incrementLoadOneNoLoader() {
loadOneNoLoader.increment();
}
/**
* Collect the metrics.
*/
public void visitMetrics(MetricVisitor visitor) {
bindCapture.visit(visitor);
planCollect.visit(visitor);
loadOneL2.visit(visitor);
loadOneRef.visit(visitor);
loadOneNoLoader.visit(visitor);
}
}
@@ -1,6 +1,6 @@
package io.ebeaninternal.api;
import io.ebean.Ebean;
import io.ebean.DB;
import io.ebean.TxScope;
/**
@@ -28,7 +28,7 @@ public class HelpScopeTrans {
}
private static SpiEbeanServer server() {
return (SpiEbeanServer) Ebean.getDefaultServer();
return (SpiEbeanServer) DB.getDefault();
}
/**
@@ -118,7 +118,7 @@ public class LoadManyRequest extends LoadRequest {
SpiQuery<?> query = many.newQuery(server);
String orderBy = many.getLazyFetchOrderBy();
if (orderBy != null) {
query.orderBy(orderBy);
query.order(orderBy);
}
String extraWhere = many.getExtraWhere();
@@ -0,0 +1,21 @@
package io.ebeaninternal.api;
import io.ebeaninternal.server.type.bindcapture.BindCapture;
class NoopQueryBindCapture implements SpiQueryBindCapture {
@Override
public boolean collectFor(long timeMicros) {
return false;
}
@Override
public void setBind(BindCapture bindCapture, long timeMicros, long startNanos) {
// do nothing
}
@Override
public void queryPlanInit(long thresholdMicros) {
// do nothing
}
}
@@ -0,0 +1,20 @@
package io.ebeaninternal.api;
import io.ebean.meta.MetaQueryPlan;
import io.ebean.meta.QueryPlanRequest;
import java.util.Collections;
import java.util.List;
class NoopQueryPlanManager implements QueryPlanManager {
@Override
public SpiQueryBindCapture createBindCapture(SpiQueryPlan queryPlan) {
return SpiQueryBindCapture.NOOP;
}
@Override
public List<MetaQueryPlan> collect(QueryPlanRequest request) {
return Collections.emptyList();
}
}
@@ -0,0 +1,24 @@
package io.ebeaninternal.api;
import io.ebean.meta.MetaQueryPlan;
import io.ebean.meta.QueryPlanRequest;
import java.util.List;
/**
* Manage query plan capture.
*/
public interface QueryPlanManager {
QueryPlanManager NOOP = new NoopQueryPlanManager();
/**
* Create the bind capture for the given query plan.
*/
SpiQueryBindCapture createBindCapture(SpiQueryPlan queryPlan);
/**
* Collect the database query plans.
*/
List<MetaQueryPlan> collect(QueryPlanRequest request);
}
@@ -0,0 +1,15 @@
package io.ebeaninternal.api;
import io.ebean.meta.MetaQueryPlan;
/**
* Internal database query plan being capture.
*/
public interface SpiDbQueryPlan extends MetaQueryPlan {
/**
* Extend with queryTimeMicros and captureCount.
*/
SpiDbQueryPlan with(long queryTimeMicros, long captureCount);
}
@@ -2,6 +2,7 @@ package io.ebeaninternal.api;
import io.ebean.DtoQuery;
import io.ebean.ProfileLocation;
import io.ebean.Transaction;
import io.ebeaninternal.server.dto.DtoMappingRequest;
import io.ebeaninternal.server.dto.DtoQueryPlan;
@@ -65,4 +66,9 @@ public interface SpiDtoQuery<T> extends DtoQuery<T>, SpiSqlBinding {
*/
SpiQuery<?> getOrmQuery();
/**
* Return the explicit transaction used to execute the query.
*/
Transaction getTransaction();
}
@@ -12,7 +12,6 @@ import io.ebean.TxScope;
import io.ebean.bean.BeanCollectionLoader;
import io.ebean.bean.BeanLoader;
import io.ebean.bean.CallOrigin;
import io.ebean.bean.ObjectGraphNode;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.event.readaudit.ReadAuditLogger;
@@ -32,7 +31,7 @@ import java.util.function.Predicate;
/**
* Service Provider extension to EbeanServer.
*/
public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanLoader, BeanCollectionLoader {
public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanCollectionLoader {
/**
* Return the log manager.
@@ -311,4 +310,9 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanLoader,
* Execute the sql update regardless of transaction batch mode.
*/
int executeNow(SpiSqlUpdate sqlUpdate);
/**
* Create a query bind capture for the given query plan.
*/
SpiQueryBindCapture createQueryBindCapture(SpiQueryPlan queryPlan);
}
@@ -13,6 +13,9 @@ import java.io.IOException;
*/
public interface SpiExpression extends Expression {
static final String SQL_TRUE = "1=1";
static final String SQL_FALSE = "1=0";
/**
* Simplify nested expressions if possible.
*/
@@ -1,5 +1,6 @@
package io.ebeaninternal.api;
import io.ebean.ProfileLocation;
import io.ebeaninternal.server.transaction.ProfileStream;
import io.ebeaninternal.server.transaction.TransactionProfile;
@@ -24,7 +25,7 @@ public interface SpiProfileHandler {
* Create a profiling stream if we are profiling this transaction.
* Return null if we are not profiling this transaction.
*
* @param profileId The transaction profileId
* @param location The profile location
*/
ProfileStream createProfileStream(int profileId);
ProfileStream createProfileStream(ProfileLocation location);
}
@@ -191,7 +191,7 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
/**
* Return the id used to identify a particular query for the given bean type.
*/
short getProfileId();
String getProfileId();
/**
* Return the profile location for this query.
@@ -0,0 +1,35 @@
package io.ebeaninternal.api;
import io.ebean.meta.QueryPlanRequest;
import io.ebeaninternal.server.type.bindcapture.BindCapture;
/**
* Capture query bind values and with those actual database query plans.
*/
public interface SpiQueryBindCapture {
/**
* NOOP implementation.
*/
SpiQueryBindCapture NOOP = new NoopQueryBindCapture();
/**
* Return true if the query just executed should be bind captured to collect
* the query plan from (as the query time is large / interesting).
*/
boolean collectFor(long timeMicros);
/**
* Set the captured bind values that we can use later to collect a query plan.
*
* @param bindCapture The bind values of the query
* @param queryTimeMicros The query execution time
* @param startNanos The nanos start of this bind capture
*/
void setBind(BindCapture bindCapture, long queryTimeMicros, long startNanos);
/**
* Update the threshold micros triggering the bind capture.
*/
void queryPlanInit(long thresholdMicros);
}
@@ -0,0 +1,48 @@
package io.ebeaninternal.api;
import io.ebean.ProfileLocation;
/**
* The internal ORM "query plan".
*/
public interface SpiQueryPlan {
/**
* The related entity bean type
*/
Class<?> getBeanType();
/**
* The plan name.
*/
String getName();
/**
* The hash for the query plan.
*/
String getHash();
/**
* The SQL for the query plan.
*/
String getSql();
/**
* The related profile location.
*/
ProfileLocation getProfileLocation();
/**
* Initiate bind capture with the give threshold.
*/
void queryPlanInit(long thresholdMicros);
/**
* Return as Database query plan.
*
* @param bind Description of the bind values used
* @param planString The raw database query plan
*/
SpiDbQueryPlan createMeta(String bind, String planString);
}
@@ -20,7 +20,6 @@ import java.sql.SQLException;
* Extends Transaction with additional API required on server.
* <p>
* Provides support for batching and TransactionContext.
* </p>
*/
public interface SpiTransaction extends Transaction {
@@ -65,7 +64,6 @@ public interface SpiTransaction extends Transaction {
* Add a deleting bean to the registered list.
* <p>
* This is to handle bi-directional relationships where both sides Cascade.
* </p>
*/
void registerDeleteBean(Integer hash);
@@ -86,7 +84,6 @@ public interface SpiTransaction extends Transaction {
* the bean when cascade persist is on both sides of a relationship).
* <p>
* This will register the bean if it is not already.
* </p>
*/
boolean isRegisteredBean(Object bean);
@@ -111,7 +108,6 @@ public interface SpiTransaction extends Transaction {
* Return the batchSize specifically set for this transaction or 0.
* <p>
* Returning 0 implies to use the system wide default batch size.
* </p>
*/
DocStoreMode getDocStoreMode();
@@ -125,7 +121,6 @@ public interface SpiTransaction extends Transaction {
* Return the batchSize specifically set for this transaction or 0.
* <p>
* Returning 0 implies to use the system wide default batch size.
* </p>
*/
@Override
int getBatchSize();
@@ -141,11 +136,9 @@ public interface SpiTransaction extends Transaction {
* As we cascade save or delete we traverse the object graph tree. Going up
* to Assoc Ones the depth decreases and going down to Assoc Manys the depth
* increases.
* </p>
* <p>
* The depth is used for ordering batching statements. The lowest depth get
* executed first during save.
* </p>
*/
void depth(int diff);
@@ -166,7 +159,6 @@ public interface SpiTransaction extends Transaction {
* This information is used maintain the table state, cache and text
* indexes. On commit the Table modifications this generates is broadcast
* around the cluster (if you have a cluster).
* </p>
*/
TransactionEvent getEvent();
@@ -198,7 +190,6 @@ public interface SpiTransaction extends Transaction {
* You may wish to hold onto this and set it against another transaction
* later. This is along the lines of 'extended persistence context'
* behaviour.
* </p>
*/
PersistenceContext getPersistenceContext();
@@ -211,7 +202,6 @@ public interface SpiTransaction extends Transaction {
* is one PersistenceContext per Transaction. The getPersistenceContext()
* and setPersistenceContext() enable a developer to reuse a single
* PersistenceContext with multiple transactions.
* </p>
*/
void setPersistenceContext(PersistenceContext context);
@@ -221,7 +211,6 @@ public interface SpiTransaction extends Transaction {
* If the connection is made from Transaction and the user code calls
* that method we can no longer trust the query only status of a
* Transaction.
* </p>
*/
Connection getInternalConnection();
@@ -4,6 +4,8 @@ import io.ebean.TxScope;
import io.ebeaninternal.server.transaction.TransactionScopeManager;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* Service provider interface for the transaction manager.
@@ -55,4 +57,9 @@ public interface SpiTransactionManager {
*/
void notifyOfQueryOnly(SpiTransaction transaction);
/**
* Return a connection used for query plan collection.
*/
Connection getQueryPlanConnection() throws SQLException;
}
@@ -3,6 +3,7 @@ package io.ebeaninternal.dbmigration;
import io.ebean.config.DbMigrationConfig;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.migration.ddl.DdlAutoCommit;
import io.ebean.migration.ddl.DdlRunner;
import io.ebean.migration.runner.ScriptTransform;
import io.ebean.util.JdbcClose;
@@ -47,6 +48,7 @@ public class DdlGenerator {
private final boolean ddlAutoCommit;
private final String dbSchema;
private final ScriptTransform scriptTransform;
private final String platformName;
private CurrentModel currentModel;
private String dropAllContent;
@@ -60,13 +62,15 @@ public class DdlGenerator {
this.extraDdl = serverConfig.isDdlExtra();
this.createOnly = serverConfig.isDdlCreateOnly();
this.dbSchema = serverConfig.getDbSchema();
final DatabasePlatform databasePlatform = server.getDatabasePlatform();
this.platformName = databasePlatform.getPlatform().base().name();
if (!serverConfig.getTenantMode().isDdlEnabled() && serverConfig.isDdlRun()) {
log.warn("DDL can't be run on startup with TenantMode " + serverConfig.getTenantMode());
this.runDdl = false;
this.ddlAutoCommit = false;
} else {
this.runDdl = serverConfig.isDdlRun();
this.ddlAutoCommit = server.getDatabasePlatform().isDdlAutoCommit();
this.ddlAutoCommit = databasePlatform.isDdlAutoCommit();
}
this.scriptTransform = createScriptTransform(serverConfig.getMigrationConfig());
this.baseDir = initBaseDir();
@@ -156,19 +160,19 @@ public class DdlGenerator {
/**
* Execute all the DDL statements in the script.
*/
public int runScript(Connection connection, boolean expectErrors, String content, String scriptName) {
public void runScript(Connection connection, boolean expectErrors, String content, String scriptName) {
DdlRunner runner = new DdlRunner(expectErrors, scriptName);
DdlRunner runner = createDdlRunner(expectErrors, scriptName);
try {
if (expectErrors || ddlAutoCommit) {
connection.setAutoCommit(true);
}
int count = runner.runAll(scriptTransform.transform(content), connection);
runner.runAll(scriptTransform.transform(content), connection);
if (expectErrors || ddlAutoCommit) {
connection.setAutoCommit(false);
}
connection.commit();
return count;
runner.runNonTransactional(connection);
} catch (SQLException e) {
throw new PersistenceException("Failed to run script", e);
@@ -177,6 +181,10 @@ public class DdlGenerator {
}
}
private DdlRunner createDdlRunner(boolean expectErrors, String scriptName) {
return new DdlRunner(expectErrors, scriptName, platformName);
}
protected void runDropSql(Connection connection) throws IOException {
if (!createOnly) {
if (extraDdl && jaxbPresent) {
@@ -1,6 +1,7 @@
package io.ebeaninternal.dbmigration;
import io.ebean.Ebean;
import io.ebean.DB;
import io.ebean.Database;
import io.ebean.EbeanServer;
import io.ebean.annotation.Platform;
import io.ebean.config.DbConstraintNaming;
@@ -90,6 +91,8 @@ public class DefaultDbMigration implements DbMigration {
protected String pathToResources = "src/main/resources";
protected String migrationPath;
protected DatabasePlatform databasePlatform;
private boolean vanillaPlatform;
@@ -137,13 +140,18 @@ public class DefaultDbMigration implements DbMigration {
this.pathToResources = pathToResources;
}
@Override
public void setMigrationPath(String migrationPath) {
this.migrationPath = migrationPath;
}
/**
* Set the server to use to determine the current model.
* Typically this is not called explicitly.
*/
@Override
public void setServer(EbeanServer ebeanServer) {
this.server = (SpiEbeanServer) ebeanServer;
public void setServer(Database database) {
this.server = (SpiEbeanServer) database;
setServerConfig(server.getServerConfig());
}
@@ -671,7 +679,7 @@ public class DefaultDbMigration implements DbMigration {
*/
private void setDefaults() {
if (server == null) {
setServer(Ebean.getDefaultServer());
setServer(DB.getDefault());
}
if (vanillaPlatform || databasePlatform == null) {
// not explicitly set so use the platform of the server
@@ -684,6 +692,9 @@ public class DefaultDbMigration implements DbMigration {
if (applyPrefix != null) {
migrationConfig.setApplyPrefix(applyPrefix);
}
if (migrationPath != null) {
migrationConfig.setMigrationPath(migrationPath);
}
if (header != null) {
migrationConfig.setDdlHeader(header);
}
@@ -112,8 +112,8 @@ public class BaseTableDdl implements TableDdl {
handleStrictError(tableName, columnName);
}
before = getScriptsForPlatform(column.getBefore(), platformDdl.getPlatform().getName());
after = getScriptsForPlatform(column.getAfter(), platformDdl.getPlatform().getName());
before = getScriptsForPlatform(column.getBefore());
after = getScriptsForPlatform(column.getAfter());
this.withHistory = withHistory;
}
@@ -136,9 +136,9 @@ public class BaseTableDdl implements TableDdl {
}
before = Collections.singletonList(platformDdl.getUpdateNullWithDefault());
} else {
before = getScriptsForPlatform(alter.getBefore(), platformDdl.getPlatform().getName());
before = getScriptsForPlatform(alter.getBefore());
}
after = getScriptsForPlatform(alter.getAfter(), platformDdl.getPlatform().getName());
after = getScriptsForPlatform(alter.getAfter());
}
void writeBefore(DdlBuffer buffer) throws IOException {
@@ -167,7 +167,8 @@ public class BaseTableDdl implements TableDdl {
}
}
private List<String> getScriptsForPlatform(List<DdlScript> scripts, String searchPlatform) {
private List<String> getScriptsForPlatform(List<DdlScript> scripts) {
String searchPlatform = platformDdl.getPlatform().getName();
List<String> ret = Collections.emptyList();
for (DdlScript script : scripts) {
if (script.getPlatforms() == null || script.getPlatforms().isEmpty()) {
@@ -358,7 +359,6 @@ public class BaseTableDdl implements TableDdl {
* For all other DB platforms these unique constraints are done inline as per normal.
*/
protected void writeUniqueOneToOneConstraints(DdlWrite write, CreateTable createTable) throws IOException {
String tableName = createTable.getName();
for (Column col : externalUnique) {
String uqName = col.getUniqueOneToOne();
@@ -381,7 +381,6 @@ public class BaseTableDdl implements TableDdl {
}
protected void writeSequence(DdlWrite writer, CreateTable createTable, String pk) throws IOException {
// explicit sequence use or platform decides
String explicitSequenceName = createTable.getSequenceName();
int initial = toInt(createTable.getSequenceInitial());
@@ -400,13 +399,11 @@ public class BaseTableDdl implements TableDdl {
}
protected void createWithHistory(DdlWrite writer, String name) throws IOException {
MTable table = writer.getTable(name);
platformDdl.createWithHistory(writer, table);
}
protected void writeInlineForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
for (Column column : createTable.getColumn()) {
String references = column.getReferences();
if (hasValue(references)) {
@@ -417,13 +414,11 @@ public class BaseTableDdl implements TableDdl {
}
protected void writeInlineForeignKey(DdlWrite write, Column column) throws IOException {
String fkConstraint = platformDdl.tableInlineForeignKey(new WriteForeignKey(null, column));
write.apply().append(",").newLine().append(" ").append(fkConstraint);
}
protected void writeInlineCompoundForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
for (ForeignKey key : createTable.getForeignKey()) {
String fkConstraint = platformDdl.tableInlineForeignKey(new WriteForeignKey(null, key));
write.apply().append(",").newLine().append(" ").append(fkConstraint);
@@ -431,7 +426,6 @@ public class BaseTableDdl implements TableDdl {
}
protected void writeAddForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
for (Column column : createTable.getColumn()) {
String references = column.getReferences();
if (hasValue(references)) {
@@ -443,7 +437,6 @@ public class BaseTableDdl implements TableDdl {
}
protected void writeAddCompoundForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
for (ForeignKey key : createTable.getForeignKey()) {
writeForeignKey(write, new WriteForeignKey(createTable.getName(), key));
}
@@ -454,12 +447,11 @@ public class BaseTableDdl implements TableDdl {
}
protected void writeForeignKey(DdlWrite write, WriteForeignKey request) throws IOException {
DdlBuffer fkeyBuffer = write.applyForeignKeys();
String tableName = lowerTableName(request.table());
if (request.indexName() != null) {
// no matching unique constraint so add the index
fkeyBuffer.appendStatement(platformDdl.createIndex(request.indexName(), tableName, request.cols()));
fkeyBuffer.appendStatement(platformDdl.createIndex(new WriteCreateIndex(request.indexName(), tableName, request.cols(), false)));
}
alterTableAddForeignKey(write.getOptions(), fkeyBuffer, request);
@@ -474,7 +466,6 @@ public class BaseTableDdl implements TableDdl {
}
protected void alterTableAddForeignKey(DdlOptions options, DdlBuffer buffer, WriteForeignKey request) throws IOException {
buffer.appendStatement(platformDdl.alterTableAddForeignKey(options, request));
}
@@ -493,7 +484,6 @@ public class BaseTableDdl implements TableDdl {
* Add 'drop table' statement to the buffer.
*/
protected void dropTable(DdlBuffer buffer, String tableName) throws IOException {
buffer.appendStatement(platformDdl.dropTable(tableName));
}
@@ -501,26 +491,38 @@ public class BaseTableDdl implements TableDdl {
* Add 'drop sequence' statement to the buffer.
*/
protected void dropSequence(DdlBuffer buffer, String sequenceName) throws IOException {
buffer.appendStatement(platformDdl.dropSequence(sequenceName));
}
protected void writeCompoundUniqueConstraints(DdlBuffer apply, CreateTable createTable) throws IOException {
boolean inlineUniqueWhenNull = platformDdl.isInlineUniqueWhenNullable();
for (UniqueConstraint uniqueConstraint : createTable.getUniqueConstraint()) {
if (inlineUniqueWhenNull) {
String uqName = uniqueConstraint.getName();
String[] columns = split(uniqueConstraint.getColumnNames());
apply.append(",").newLine();
apply.append(" constraint ").append(uqName).append(" unique");
appendColumns(columns, apply);
} else {
externalCompoundUnique.add(uniqueConstraint);
if (platformInclude(uniqueConstraint.getPlatforms())) {
if (inlineUniqueWhenNull) {
String uqName = uniqueConstraint.getName();
apply.append(",").newLine();
apply.append(" constraint ").append(uqName).append(" unique");
appendColumns(split(uniqueConstraint.getColumnNames()), apply);
} else {
externalCompoundUnique.add(uniqueConstraint);
}
}
}
}
private boolean platformInclude(String platforms) {
if (platforms == null || platforms.isEmpty()) {
return true;
}
String currentPlatform = platformDdl.getPlatform().getPlatform().name();
for (String name : StringHelper.splitNames(platforms)) {
if (currentPlatform.equalsIgnoreCase(name)) {
return true;
}
}
return false;
}
/**
* Write the unique constraints inline with the create table statement.
*/
@@ -607,26 +609,31 @@ public class BaseTableDdl implements TableDdl {
}
@Override
public void generate(DdlWrite writer, CreateIndex createIndex) throws IOException {
writer.apply().appendStatement(platformDdl.createIndex(createIndex.getIndexName(), createIndex.getTableName(), split(createIndex.getColumns())));
writer.dropAll().appendStatement(platformDdl.dropIndex(createIndex.getIndexName(), createIndex.getTableName()));
public void generate(DdlWrite writer, CreateIndex index) throws IOException {
if (platformInclude(index.getPlatforms())) {
writer.apply().appendStatement(platformDdl.createIndex(new WriteCreateIndex(index)));
writer.dropAll().appendStatement(platformDdl.dropIndex(index.getIndexName(), index.getTableName(), Boolean.TRUE.equals(index.isConcurrent())));
}
}
@Override
public void generate(DdlWrite writer, DropIndex dropIndex) throws IOException {
writer.apply().appendStatement(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName()));
if (platformInclude(dropIndex.getPlatforms())) {
writer.apply().appendStatement(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName(), Boolean.TRUE.equals(dropIndex.isConcurrent())));
}
}
@Override
public void generate(DdlWrite writer, AddUniqueConstraint constraint) throws IOException {
if (platformInclude(constraint.getPlatforms())) {
if (DdlHelp.isDropConstraint(constraint.getColumnNames())) {
writer.apply().appendStatement(platformDdl.alterTableDropUniqueConstraint(constraint.getTableName(), constraint.getConstraintName()));
if (DdlHelp.isDropConstraint(constraint.getColumnNames())) {
writer.apply().appendStatement(platformDdl.alterTableDropUniqueConstraint(constraint.getTableName(), constraint.getConstraintName()));
} else {
String[] cols = split(constraint.getColumnNames());
String[] nullableColumns = split(constraint.getNullableColumns());
writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(constraint.getTableName(), constraint.getConstraintName(), cols, nullableColumns));
} else {
String[] cols = split(constraint.getColumnNames());
String[] nullableColumns = split(constraint.getNullableColumns());
writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(constraint.getTableName(), constraint.getConstraintName(), cols, nullableColumns));
}
}
}
@@ -944,6 +951,10 @@ public class BaseTableDdl implements TableDdl {
}
platformDdl.alterTableAddColumn(buffer, tableName, column, onHistoryTable, help.getDefaultValue());
final String comment = column.getComment();
if (comment != null && !comment.isEmpty()) {
platformDdl.addColumnComment(buffer, tableName, column.getName(), comment);
}
if (!onHistoryTable) {
help.writeAfter(buffer);
@@ -56,12 +56,12 @@ public class ClickHouseDdl extends PlatformDdl {
}
@Override
public String dropIndex(String indexName, String tableName) {
public String dropIndex(String indexName, String tableName, boolean concurrent) {
return null;
}
@Override
public String createIndex(String indexName, String tableName, String[] columns) {
public String createIndex(WriteCreateIndex create) {
return null;
}
@@ -13,25 +13,24 @@ public class HanaColumnStoreDdl extends AbstractHanaDdl {
}
@Override
public String createIndex(String indexName, String tableName, String[] columns) {
public String createIndex(WriteCreateIndex create) {
final String[] columns = create.getColumns();
if (columns == null || columns.length == 0) {
return "-- cannot create index: no columns given";
}
if (columns.length == 1) {
return "-- explicit index \"" + indexName + "\" for single column \"" + columns[0] + "\" of table \"" + tableName
return "-- explicit index \"" + create.getIndexName() + "\" for single column \"" + columns[0] + "\" of table \"" + create.getTableName()
+ "\" is not necessary";
}
StringBuilder buffer = new StringBuilder();
buffer.append("create inverted hash index ").append(maxConstraintName(indexName)).append(" on ").append(tableName);
buffer.append("create inverted hash index ").append(maxConstraintName(create.getIndexName())).append(" on ").append(create.getTableName());
appendColumns(columns, buffer);
return buffer.toString();
}
@Override
public String dropIndex(String indexName, String tableName) {
public String dropIndex(String indexName, String tableName, boolean concurrent) {
DdlBuffer buffer = new BaseDdlBuffer(null);
try {
buffer.append("delimiter $$").newLine();
@@ -30,7 +30,7 @@ public class MySqlDdl extends PlatformDdl {
* Return the drop index statement.
*/
@Override
public String dropIndex(String indexName, String tableName) {
public String dropIndex(String indexName, String tableName, boolean concurrent) {
return "drop index " + maxConstraintName(indexName) + " on " + tableName;
}
@@ -109,6 +109,9 @@ public class PlatformDdl {
protected String addForeignKeySkipCheck = "";
protected String uniqueIndex = "unique";
protected String indexConcurrent = "";
/**
* Set false for MsSqlServer to allow multiple nulls for OneToOne mapping.
*/
@@ -380,21 +383,34 @@ public class PlatformDdl {
}
/**
* Return the drop index statement.
* Return the drop index statement for known non concurrent index.
*/
public String dropIndex(String indexName, String tableName) {
return dropIndexIfExists + maxConstraintName(indexName);
return dropIndex(indexName, tableName, false);
}
/**
* Return the create index statement.
* Return the drop index statement.
*/
public String createIndex(String indexName, String tableName, String[] columns) {
public String dropIndex(String indexName, String tableName, boolean concurrent) {
return dropIndexIfExists + maxConstraintName(indexName);
}
public String createIndex(WriteCreateIndex create) {
if (create.useDefinition()) {
return create.getDefinition();
}
StringBuilder buffer = new StringBuilder();
buffer.append("create index ").append(maxConstraintName(indexName)).append(" on ").append(tableName);
appendColumns(columns, buffer);
buffer.append("create ");
if (create.isUnique()) {
buffer.append(uniqueIndex).append(" ");
}
buffer.append("index ");
if (create.isConcurrent()) {
buffer.append(indexConcurrent);
}
buffer.append(maxConstraintName(create.getIndexName())).append(" on ").append(create.getTableName());
appendColumns(create.getColumns(), buffer);
return buffer.toString();
}
@@ -10,6 +10,8 @@ import java.io.IOException;
*/
public class PostgresDdl extends PlatformDdl {
private static final String dropIndexConcurrentlyIfExists = "drop index concurrently if exists ";
public PostgresDdl(DatabasePlatform platform) {
super(platform);
this.historyDdl = new PostgresHistoryDdl();
@@ -18,6 +20,7 @@ public class PostgresDdl extends PlatformDdl {
this.alterTableIfExists = "if exists ";
this.columnSetNull = "drop not null";
this.addForeignKeySkipCheck = " not valid";
this.indexConcurrent = "concurrently ";
}
public String setLockTimeout(int lockTimeoutSeconds) {
@@ -39,7 +42,6 @@ public class PostgresDdl extends PlatformDdl {
*/
@Override
public String asIdentityColumn(String columnDefn) {
if ("bigint".equalsIgnoreCase(columnDefn)) {
return "bigserial";
}
@@ -56,4 +58,9 @@ public class PostgresDdl extends PlatformDdl {
public void addTablePartition(DdlBuffer apply, String partitionMode, String partitionColumn) throws IOException {
apply.append(" partition by range (").append(partitionColumn).append(")");
}
@Override
public String dropIndex(String indexName, String tableName, boolean concurrent) {
return (concurrent ? dropIndexConcurrentlyIfExists : dropIndexIfExists) + maxConstraintName(indexName);
}
}
@@ -12,4 +12,13 @@ public class SplitColumns {
return columns.split(",");
}
/**
* Split returning null when columns is null or empty.
*/
public static String[] splitWithNull(String columns) {
if (columns == null || columns.isEmpty()) {
return null;
}
return columns.split(",");
}
}
@@ -58,7 +58,7 @@ public class SqlServerDdl extends PlatformDdl {
}
@Override
public String dropIndex(String indexName, String tableName) {
public String dropIndex(String indexName, String tableName, boolean concurrent) {
return "IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('" + tableName + "','U') AND name = '"
+ maxConstraintName(indexName) + "') drop index " + maxConstraintName(indexName) + " ON " + tableName;
}
@@ -105,9 +105,9 @@ public class SqlServerDdl extends PlatformDdl {
@Override
public String alterTableDropUniqueConstraint(String tableName, String uniqueConstraintName) {
StringBuilder sb = new StringBuilder();
sb.append(dropIndex(uniqueConstraintName, tableName)).append(";\n");
sb.append("IF (OBJECT_ID('").append(maxConstraintName(uniqueConstraintName)).append("', 'UQ') IS NOT NULL) ");
sb.append(super.alterTableDropUniqueConstraint(tableName, uniqueConstraintName)).append(";\n");
sb.append(dropIndex(uniqueConstraintName, tableName));
sb.append(super.alterTableDropUniqueConstraint(tableName, uniqueConstraintName));
return sb.toString();
}
/**
@@ -31,11 +31,14 @@ public class SqlServerHistoryDdl implements PlatformHistoryDdl {
enableSystemVersioning(writer, baseTable);
}
private String getHistoryTable(String baseTable) {
String historyTable = baseTable + "_history"; // history must contain schema, otherwise you'll get
// Setting SYSTEM_VERSIONING to ON failed because history table 'xxx_history' is not specified in two-part name format.
String getHistoryTable(String baseTable) {
String historyTable = baseTable + "_history";
if (baseTable.startsWith("[")) {
historyTable = historyTable.replace("]", "") + "]";
}
if (historyTable.indexOf('.') == -1) {
historyTable = "dbo." +historyTable; // so add the default schema, if none was specified.
// history must contain schema, add the default schema if none was specified
historyTable = "dbo." + historyTable;
}
return historyTable;
}
@@ -86,10 +89,10 @@ public class SqlServerHistoryDdl implements PlatformHistoryDdl {
DdlBuffer apply = writer.applyHistoryView();
String baseTableName = baseTable.getBaseTable();
apply.append("-- alter table ").append(baseTableName).append(" set (system_versioning = off (history_table=")
.append(getHistoryTable(baseTableName)).append("))").endOfStatement();
.append(getHistoryTable(baseTableName)).append("))").endOfStatement();
apply.append("-- history migration goes here").newLine();
apply.append("-- alter table ").append(baseTableName).append(" set (system_versioning = on (history_table=")
.append(getHistoryTable(baseTableName)).append("))").endOfStatement();
.append(getHistoryTable(baseTableName)).append("))").endOfStatement();
}
}
@@ -0,0 +1,61 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebeaninternal.dbmigration.migration.CreateIndex;
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split;
class WriteCreateIndex {
private final String indexName;
private final String tableName;
private final String[] columns;
private final boolean unique;
private final boolean concurrent;
private final String definition;
WriteCreateIndex(String indexName, String tableName, String[] columns, boolean unique) {
this.indexName = indexName;
this.tableName = tableName;
this.columns = columns;
this.unique = unique;
this.concurrent = false;
this.definition = null;
}
public WriteCreateIndex(CreateIndex index) {
this.indexName = index.getIndexName();
this.tableName = index.getTableName();
this.columns = split(index.getColumns());
this.unique = Boolean.TRUE.equals(index.isUnique());
this.concurrent = Boolean.TRUE.equals(index.isConcurrent());
this.definition = index.getDefinition();
}
public String getIndexName() {
return indexName;
}
public String getTableName() {
return tableName;
}
public String[] getColumns() {
return columns;
}
public boolean isUnique() {
return unique;
}
public boolean isConcurrent() {
return concurrent;
}
public String getDefinition() {
return definition;
}
public boolean useDefinition() {
return definition != null && !definition.isEmpty();
}
}
@@ -21,6 +21,7 @@ import javax.xml.bind.annotation.XmlType;
* &lt;attribute name="columnNames" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="oneToOne" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;attribute name="nullableColumns" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="platforms" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
@@ -41,6 +42,8 @@ public class AddUniqueConstraint {
protected Boolean oneToOne;
@XmlAttribute(name = "nullableColumns")
protected String nullableColumns;
@XmlAttribute(name = "platforms")
protected String platforms;
/**
* Gets the value of the constraintName property.
@@ -142,4 +145,24 @@ public class AddUniqueConstraint {
this.nullableColumns = value;
}
/**
* Gets the value of the platforms property.
*
* @return possible object is
* {@link String }
*/
public String getPlatforms() {
return platforms;
}
/**
* Sets the value of the platforms property.
*
* @param value allowed object is
* {@link String }
*/
public void setPlatforms(String value) {
this.platforms = value;
}
}
@@ -19,6 +19,10 @@ import javax.xml.bind.annotation.XmlType;
* &lt;attribute name="indexName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="tableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="columns" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="unique" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;attribute name="concurrent" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;attribute name="definition" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="platforms" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
@@ -35,6 +39,14 @@ public class CreateIndex {
protected String tableName;
@XmlAttribute(name = "columns", required = true)
protected String columns;
@XmlAttribute(name = "unique")
protected Boolean unique;
@XmlAttribute(name = "concurrent")
protected Boolean concurrent;
@XmlAttribute(name = "definition")
protected String definition;
@XmlAttribute(name = "platforms")
protected String platforms;
/**
* Gets the value of the indexName property.
@@ -96,4 +108,84 @@ public class CreateIndex {
this.columns = value;
}
/**
* Gets the value of the unique property.
*
* @return possible object is
* {@link Boolean }
*/
public Boolean isUnique() {
return unique;
}
/**
* Sets the value of the unique property.
*
* @param value allowed object is
* {@link Boolean }
*/
public void setUnique(Boolean value) {
this.unique = value;
}
/**
* Gets the value of the concurrent property.
*
* @return possible object is
* {@link Boolean }
*/
public Boolean isConcurrent() {
return concurrent;
}
/**
* Sets the value of the concurrent property.
*
* @param value allowed object is
* {@link Boolean }
*/
public void setConcurrent(Boolean value) {
this.concurrent = value;
}
/**
* Gets the value of the definition property.
*
* @return possible object is
* {@link String }
*/
public String getDefinition() {
return definition;
}
/**
* Sets the value of the definition property.
*
* @param value allowed object is
* {@link String }
*/
public void setDefinition(String value) {
this.definition = value;
}
/**
* Gets the value of the platforms property.
*
* @return possible object is
* {@link String }
*/
public String getPlatforms() {
return platforms;
}
/**
* Sets the value of the platforms property.
*
* @param value allowed object is
* {@link String }
*/
public void setPlatforms(String value) {
this.platforms = value;
}
}
@@ -37,6 +37,7 @@ import java.util.List;
* &lt;attribute name="sequenceInitial" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
* &lt;attribute name="sequenceAllocate" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
* &lt;attribute name="pkName" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="storageEngine" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
@@ -18,6 +18,8 @@ import javax.xml.bind.annotation.XmlType;
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="indexName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="tableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="concurrent" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;attribute name="platforms" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
@@ -32,6 +34,10 @@ public class DropIndex {
protected String indexName;
@XmlAttribute(name = "tableName", required = true)
protected String tableName;
@XmlAttribute(name = "concurrent")
protected Boolean concurrent;
@XmlAttribute(name = "platforms")
protected String platforms;
/**
* Gets the value of the indexName property.
@@ -73,4 +79,44 @@ public class DropIndex {
this.tableName = value;
}
/**
* Gets the value of the concurrent property.
*
* @return possible object is
* {@link Boolean }
*/
public Boolean isConcurrent() {
return concurrent;
}
/**
* Sets the value of the concurrent property.
*
* @param value allowed object is
* {@link Boolean }
*/
public void setConcurrent(Boolean value) {
this.concurrent = value;
}
/**
* Gets the value of the platforms property.
*
* @return possible object is
* {@link String }
*/
public String getPlatforms() {
return platforms;
}
/**
* Sets the value of the platforms property.
*
* @param value allowed object is
* {@link String }
*/
public void setPlatforms(String value) {
this.platforms = value;
}
}
@@ -20,6 +20,7 @@ import javax.xml.bind.annotation.XmlType;
* &lt;attribute name="columnNames" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="oneToOne" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;attribute name="nullableColumns" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="platforms" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
@@ -38,6 +39,8 @@ public class UniqueConstraint {
protected Boolean oneToOne;
@XmlAttribute(name = "nullableColumns")
protected String nullableColumns;
@XmlAttribute(name = "platforms")
protected String platforms;
/**
* Gets the value of the name property.
@@ -119,4 +122,24 @@ public class UniqueConstraint {
this.nullableColumns = value;
}
/**
* Gets the value of the platforms property.
*
* @return possible object is
* {@link String }
*/
public String getPlatforms() {
return platforms;
}
/**
* Sets the value of the platforms property.
*
* @param value allowed object is
* {@link String }
*/
public void setPlatforms(String value) {
this.platforms = value;
}
}
@@ -1,11 +1,11 @@
package io.ebeaninternal.dbmigration.model;
import io.ebean.config.DbConstraintNaming;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DefaultConstraintMaxLength;
import io.ebeaninternal.dbmigration.migration.ChangeSet;
import io.ebeaninternal.dbmigration.model.build.ModelBuildBeanVisitor;
import io.ebeaninternal.dbmigration.model.build.ModelBuildContext;
@@ -24,9 +24,9 @@ public class CurrentModel {
private final SpiEbeanServer server;
private final DbConstraintNaming constraintNaming;
private final DatabasePlatform databasePlatform;
private final DbConstraintNaming.MaxLength maxLength;
private final DbConstraintNaming constraintNaming;
private final boolean platformTypes;
@@ -60,8 +60,8 @@ public class CurrentModel {
private CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, boolean platformTypes) {
this.server = server;
this.databasePlatform = server.getDatabasePlatform();
this.constraintNaming = constraintNaming;
this.maxLength = maxLength(server, constraintNaming);
this.platformTypes = platformTypes;
this.jaxbPresent = server.getServerConfig().getClassLoadConfig().isJavaxJAXBPresent();
}
@@ -84,16 +84,6 @@ public class CurrentModel {
return read().getPartitionedTables();
}
private static DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
if (naming.getMaxLength() != null) {
return naming.getMaxLength();
}
int maxConstraintNameLength = server.getDatabasePlatform().getMaxConstraintNameLength();
return new DefaultConstraintMaxLength(maxConstraintNameLength);
}
/**
* Return the current model by reading all the bean descriptors and properties.
*/
@@ -101,7 +91,7 @@ public class CurrentModel {
if (model == null) {
model = new ModelContainer();
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength, platformTypes);
ModelBuildContext context = new ModelBuildContext(model, databasePlatform, constraintNaming, platformTypes);
ModelBuildBeanVisitor visitor = new ModelBuildBeanVisitor(context);
VisitAllUsing visit = new VisitAllUsing(visitor, server);
visit.visitAllBeans();
@@ -7,6 +7,9 @@ import io.ebeaninternal.dbmigration.migration.UniqueConstraint;
import java.util.Arrays;
import java.util.Objects;
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split;
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.splitWithNull;
/**
* A unique constraint for multiple columns.
* <p>
@@ -28,12 +31,41 @@ public class MCompoundUniqueConstraint {
*/
private final String[] columns;
private final String platforms;
private String[] nullableColumns;
public MCompoundUniqueConstraint(String[] columns, Boolean oneToOne, String name) {
/**
* Create for OneToOne.
*/
public MCompoundUniqueConstraint(String[] columns, String name) {
this.name = name;
this.columns = columns;
this.oneToOne = Boolean.TRUE.equals(oneToOne);
this.oneToOne = true;
this.platforms = null;
}
public MCompoundUniqueConstraint(String[] columns, boolean oneToOne, String name, String platforms) {
this.name = name;
this.columns = columns;
this.oneToOne = oneToOne;
this.platforms = platforms;
}
public MCompoundUniqueConstraint(AddUniqueConstraint change) {
this.name = change.getConstraintName();
this.columns = split(change.getColumnNames());
this.oneToOne = change.isOneToOne();
this.platforms = change.getPlatforms();
this.nullableColumns = splitWithNull(change.getNullableColumns());
}
public MCompoundUniqueConstraint(UniqueConstraint uq) {
this.name = uq.getName();
this.columns = split(uq.getColumnNames());
this.oneToOne = uq.isOneToOne();
this.platforms = uq.getPlatforms();
this.nullableColumns = splitWithNull(uq.getNullableColumns());
}
/**
@@ -44,7 +76,7 @@ public class MCompoundUniqueConstraint {
}
/**
* Return true if this unqiue constraint is specifically for OneToOne mapping.
* Return true if this unique constraint is specifically for OneToOne mapping.
*/
public boolean isOneToOne() {
return oneToOne;
@@ -57,12 +89,17 @@ public class MCompoundUniqueConstraint {
return name;
}
public String getPlatforms() {
return platforms;
}
public UniqueConstraint getUniqueConstraint() {
UniqueConstraint uq = new UniqueConstraint();
uq.setName(getName());
uq.setColumnNames(join(columns));
uq.setNullableColumns(join(nullableColumns));
uq.setOneToOne(isOneToOne());
uq.setPlatforms(platforms);
return uq;
}
@@ -76,6 +113,7 @@ public class MCompoundUniqueConstraint {
create.setColumnNames(join(columns));
create.setNullableColumns(join(nullableColumns));
create.setOneToOne(isOneToOne());
create.setPlatforms(platforms);
return create;
}
@@ -83,12 +121,13 @@ public class MCompoundUniqueConstraint {
* Create a AddUniqueConstraint migration with 'DROP CONSTRAINT' set for this index.
*/
public AddUniqueConstraint dropUniqueConstraint(String tableName) {
AddUniqueConstraint dropUniqueConstraint = new AddUniqueConstraint();
dropUniqueConstraint.setConstraintName(name);
dropUniqueConstraint.setTableName(tableName);
dropUniqueConstraint.setColumnNames(DdlHelp.DROP_CONSTRAINT);
dropUniqueConstraint.setNullableColumns(join(nullableColumns));
return dropUniqueConstraint;
AddUniqueConstraint drop = new AddUniqueConstraint();
drop.setConstraintName(name);
drop.setTableName(tableName);
drop.setColumnNames(DdlHelp.DROP_CONSTRAINT);
drop.setNullableColumns(join(nullableColumns));
drop.setPlatforms(platforms);
return drop;
}
public void setNullableColumns(String[] nullableColumns) {
@@ -127,9 +166,10 @@ public class MCompoundUniqueConstraint {
return false;
}
MCompoundUniqueConstraint other = (MCompoundUniqueConstraint) obj;
return Arrays.equals(columns, other.columns)
&& Arrays.equals(nullableColumns, other.nullableColumns)
// not including platforms in equals check
return oneToOne == other.oneToOne
&& Objects.equals(name, other.name)
&& oneToOne == other.oneToOne;
&& Arrays.equals(columns, other.columns)
&& Arrays.equals(nullableColumns, other.nullableColumns);
}
}
@@ -6,6 +6,7 @@ import io.ebeaninternal.dbmigration.migration.DropIndex;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
* Index as part of the logical model.
@@ -13,10 +14,12 @@ import java.util.List;
public class MIndex {
private String tableName;
private String indexName;
private String platforms;
private List<String> columns = new ArrayList<>();
private boolean unique;
private boolean concurrent;
private String definition;
/**
* Create a single column non unique index.
@@ -36,10 +39,27 @@ public class MIndex {
Collections.addAll(this.columns, columnNames);
}
public MIndex(String indexName, String tableName, String[] columnNames, String platforms, boolean unique, boolean concurrent, String definition) {
this(indexName, tableName, columnNames);
this.platforms = platforms;
this.unique = unique;
this.concurrent = concurrent;
this.definition = emptyToNull(definition);
}
public MIndex(CreateIndex createIndex) {
this.indexName = createIndex.getIndexName();
this.tableName = createIndex.getTableName();
this.columns = split(createIndex.getColumns());
this.platforms = createIndex.getPlatforms();
this.unique = Boolean.TRUE.equals(createIndex.isUnique());
this.concurrent = Boolean.TRUE.equals(createIndex.isConcurrent());
this.definition = emptyToNull(createIndex.getDefinition());
}
public String getKey() {
// currently indexName should be unique (not indexName + platforms)
return indexName;
}
/**
@@ -71,9 +91,24 @@ public class MIndex {
create.setIndexName(indexName);
create.setTableName(tableName);
create.setColumns(join());
create.setPlatforms(platforms);
if (Boolean.TRUE.equals(unique)) {
create.setUnique(Boolean.TRUE);
}
if (Boolean.TRUE.equals(concurrent)) {
create.setConcurrent(Boolean.TRUE);
}
create.setDefinition(emptyToNull(definition));
return create;
}
private String emptyToNull(String val) {
if (val == null || val.isEmpty()) {
return null;
}
return val;
}
/**
* Create a DropIndex migration for this index.
*/
@@ -81,6 +116,10 @@ public class MIndex {
DropIndex dropIndex = new DropIndex();
dropIndex.setIndexName(indexName);
dropIndex.setTableName(tableName);
dropIndex.setPlatforms(platforms);
if (Boolean.TRUE.equals(concurrent)) {
dropIndex.setConcurrent(Boolean.TRUE);
}
return dropIndex;
}
@@ -88,7 +127,6 @@ public class MIndex {
* Compare with an index of the same name.
*/
public void compare(ModelDiff modelDiff, MIndex newIndex) {
if (changed(newIndex)) {
// drop and recreate the index
modelDiff.addDropIndex(dropIndex());
@@ -103,6 +141,12 @@ public class MIndex {
if (!tableName.equals(newIndex.getTableName())) {
return true;
}
if (unique != newIndex.unique) {
return true;
}
if (!Objects.equals(definition, newIndex.definition)) {
return true;
}
List<String> newColumns = newIndex.getColumns();
if (columns.size() != newColumns.size()) {
return true;
@@ -117,6 +161,9 @@ public class MIndex {
private List<String> split(String columns) {
if (columns.isEmpty()) {
return Collections.emptyList();
}
String[] cols = columns.split(",");
List<String> colList = new ArrayList<>(cols.length);
Collections.addAll(colList, cols);
@@ -1,7 +1,6 @@
package io.ebeaninternal.dbmigration.model;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DdlHelp;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns;
import io.ebeaninternal.dbmigration.migration.AddColumn;
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
import io.ebeaninternal.dbmigration.migration.AddTableComment;
@@ -27,20 +26,19 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split;
/**
* Holds the logical model for a given Table and everything associated to it.
* <p>
* This effectively represents a table, its columns and all associated
* constraints, foreign keys and indexes.
* </p>
* <p>
* Migrations can be applied to this such that it represents the state
* of a given table after various migrations have been applied.
* </p>
* <p>
* This table model can also be derived from the EbeanServer bean descriptor
* and associated properties.
* </p>
*/
public class MTable {
@@ -173,11 +171,8 @@ public class MTable {
for (Column column : cols) {
addColumn(column);
}
List<UniqueConstraint> uqConstraints = createTable.getUniqueConstraint();
for (UniqueConstraint uq : uqConstraints) {
MCompoundUniqueConstraint mUq = new MCompoundUniqueConstraint(SplitColumns.split(uq.getColumnNames()), uq.isOneToOne(), uq.getName());
mUq.setNullableColumns(SplitColumns.split(uq.getNullableColumns()));
uniqueConstraints.add(mUq);
for (UniqueConstraint uq : createTable.getUniqueConstraint()) {
uniqueConstraints.add(new MCompoundUniqueConstraint(uq));
}
for (ForeignKey fk : createTable.getForeignKey()) {
@@ -189,11 +184,10 @@ public class MTable {
}
}
public void addForeignKey(String name, String refTableName, String indexName, String columnNames, String refColumnNames) {
MCompoundForeignKey foreignKey = new MCompoundForeignKey(name, refTableName, indexName);
String[] cols = SplitColumns.split(columnNames);
String[] refCols = SplitColumns.split(refColumnNames);
String[] cols = split(columnNames);
String[] refCols = split(refColumnNames);
for (int i = 0; i < cols.length && i < refCols.length; i++) {
foreignKey.addColumnPair(cols[i], refCols[i]);
}
@@ -422,6 +416,11 @@ public class MTable {
return name;
}
public String getSchema() {
int pos = name.indexOf('.');
return pos == -1 ? null : name.substring(0, pos);
}
/**
* Return true if this table is a 'Draft' table.
*/
@@ -443,6 +442,10 @@ public class MTable {
return partitionMeta;
}
public String getPkName() {
return pkName;
}
public void setPkName(String pkName) {
this.pkName = pkName;
}
@@ -593,19 +596,8 @@ public class MTable {
/**
* Add a unique constraint.
*/
public void addUniqueConstraint(String[] columns, boolean oneToOne, String constraintName) {
uniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne, constraintName));
}
/**
* Add a unique constraint.
*/
public void addUniqueConstraint(List<MColumn> columns, boolean oneToOne, String constraintName) {
String[] cols = new String[columns.size()];
for (int i = 0; i < columns.size(); i++) {
cols[i] = columns.get(i).getName();
}
addUniqueConstraint(cols, oneToOne, constraintName);
public void addUniqueConstraint(MCompoundUniqueConstraint uniqueConstraint) {
uniqueConstraints.add(uniqueConstraint);
}
/**
@@ -761,10 +753,7 @@ public class MTable {
List<String> nullableColumns = new ArrayList<>();
for (String columnName : uniq.getColumns()) {
MColumn col = getColumn(columnName);
if (col == null) {
throw new IllegalStateException("Column '" + columnName + "' not found in table " + getName());
}
if (!col.isNotnull()) {
if (col != null && !col.isNotnull()) {
nullableColumns.add(columnName);
}
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.dbmigration.model;
import io.ebean.migration.MigrationVersion;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DdlHelp;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns;
import io.ebeaninternal.dbmigration.migration.AddColumn;
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
import io.ebeaninternal.dbmigration.migration.AddTableComment;
@@ -21,9 +20,12 @@ import io.ebeaninternal.dbmigration.migration.Migration;
import io.ebeaninternal.dbmigration.migration.Sql;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
* Holds all the tables, views, indexes etc that represent the model.
@@ -33,6 +35,8 @@ import java.util.Map;
*/
public class ModelContainer {
private final Set<String> schemas = new TreeSet<>();
/**
* All the tables in the model.
*/
@@ -50,6 +54,13 @@ public class ModelContainer {
public ModelContainer() {
}
/**
* Return the schemas.
*/
public Set<String> getSchemas() {
return schemas;
}
/**
* Return true if the model contains tables that are partitioned.
*/
@@ -82,13 +93,6 @@ public class ModelContainer {
return tables;
}
/**
* Return the map of all the non unique non fk indexes.
*/
public Map<String, MIndex> getIndexes() {
return indexes;
}
/**
* Return the table by name.
*/
@@ -97,10 +101,21 @@ public class ModelContainer {
}
/**
* Return the index by name.
* Lookup the matching index during DIFF migration processing.
*/
public MIndex getIndex(String indexName) {
return indexes.get(indexName);
public MIndex getIndex(MIndex newIndex) {
return indexes.get(newIndex.getKey());
}
public Collection<MIndex> allIndexes() {
return indexes.values();
}
/**
* Return true if the index does not exist and should be dropped.
*/
public boolean dropIndex(MIndex existingIndex) {
return !indexes.containsKey(existingIndex.getKey());
}
/**
@@ -201,10 +216,7 @@ public class ModelContainer {
if (DdlHelp.isDropConstraint(change.getColumnNames())) {
table.getUniqueConstraints().removeIf(constraint -> constraint.getName().equals(change.getConstraintName()));
} else {
MCompoundUniqueConstraint constraint = new MCompoundUniqueConstraint(
SplitColumns.split(change.getColumnNames()), change.isOneToOne(), change.getConstraintName());
constraint.setNullableColumns(SplitColumns.split(change.getNullableColumns()));
table.getUniqueConstraints().add(constraint);
table.getUniqueConstraints().add(new MCompoundUniqueConstraint(change));
}
}
@@ -216,8 +228,7 @@ public class ModelContainer {
if (DdlHelp.isDropForeignKey(change.getColumnNames())) {
table.removeForeignKey(change.getName());
} else {
table.addForeignKey(change.getName(), change.getRefTableName(), change.getIndexName(), change.getColumnNames(),
change.getRefColumnNames());
table.addForeignKey(change.getName(), change.getRefTableName(), change.getIndexName(), change.getColumnNames(), change.getRefColumnNames());
}
}
@@ -259,7 +270,8 @@ public class ModelContainer {
if (indexes.containsKey(indexName)) {
throw new IllegalStateException("Index [" + indexName + "] already exists in model?");
}
indexes.put(createIndex.getIndexName(), new MIndex(createIndex));
MIndex index = new MIndex(createIndex);
indexes.put(index.getKey(), index);
}
/**
@@ -309,6 +321,10 @@ public class ModelContainer {
if (table.isPartitioned()) {
partitionedTables.add(table);
}
String schema = table.getSchema();
if (schema != null) {
schemas.add(schema);
}
return tables.put(table.getName(), table);
}
@@ -321,7 +337,7 @@ public class ModelContainer {
if (reusedElementCollection != null) {
final MIndex index = reusedElementCollection.setReusedElementCollection();
if (index != null) {
indexes.put(index.getIndexName(), index);
indexes.put(index.getKey(), index);
}
} else {
if (table.isPartitioned()) {
@@ -332,17 +348,10 @@ public class ModelContainer {
}
/**
* Add a single column index.
* Add an index.
*/
public void addIndex(String indexName, String tableName, String columnName) {
indexes.put(indexName, new MIndex(indexName, tableName, columnName));
}
/**
* Add a multi column index.
*/
public void addIndex(String indexName, String tableName, String[] columnNames) {
indexes.put(indexName, new MIndex(indexName, tableName, columnNames));
public void addIndex(MIndex index) {
indexes.put(index.getKey(), index);
}
/**
@@ -140,9 +140,8 @@ public class ModelDiff {
}
}
Map<String, MIndex> newIndexes = newModel.getIndexes();
for (MIndex newIndex : newIndexes.values()) {
MIndex currentIndex = baseModel.getIndex(newIndex.getIndexName());
for (MIndex newIndex : newModel.allIndexes()) {
MIndex currentIndex = baseModel.getIndex(newIndex);
if (currentIndex == null) {
addCreateIndex(newIndex.createIndex());
} else {
@@ -151,8 +150,8 @@ public class ModelDiff {
}
// search for indexes that are no longer used
for (MIndex existingIndex : baseModel.getIndexes().values()) {
if (!newIndexes.containsKey(existingIndex.getIndexName())) {
for (MIndex existingIndex : baseModel.allIndexes()) {
if (newModel.dropIndex(existingIndex)) {
addDropIndex(existingIndex.dropIndex());
}
}
@@ -1,10 +1,13 @@
package io.ebeaninternal.dbmigration.model.build;
import io.ebean.config.DbConstraintNaming;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.config.dbplatform.DbPlatformTypeMapping;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DefaultConstraintMaxLength;
import io.ebeaninternal.dbmigration.model.MColumn;
import io.ebeaninternal.dbmigration.model.MCompoundForeignKey;
import io.ebeaninternal.dbmigration.model.MIndex;
import io.ebeaninternal.dbmigration.model.MTable;
import io.ebeaninternal.dbmigration.model.ModelContainer;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -30,17 +33,30 @@ public class ModelBuildContext {
private final ModelContainer model;
private final DatabasePlatform databasePlatform;
private final DbConstraintNaming constraintNaming;
private final DbConstraintNaming.MaxLength maxLength;
private final boolean platformTypes;
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength, boolean platformTypes) {
public ModelBuildContext(ModelContainer model, DatabasePlatform databasePlatform, DbConstraintNaming naming, boolean platformTypes) {
this.model = model;
this.databasePlatform = databasePlatform;
this.constraintNaming = naming;
this.maxLength = maxLength;
this.platformTypes = platformTypes;
this.maxLength = maxLength();
}
/**
* Create the max length handling for constraint names.
*/
private DbConstraintNaming.MaxLength maxLength() {
if (constraintNaming.getMaxLength() != null) {
return constraintNaming.getMaxLength();
}
return new DefaultConstraintMaxLength(databasePlatform.getMaxConstraintNameLength());
}
/**
@@ -55,40 +71,51 @@ public class ModelBuildContext {
return constraintNaming.normaliseTable(baseTable);
}
/**
* Take into account max length and quoted identifiers in constraint and index names.
*/
private String name(String constraintName, int indexCount) {
return databasePlatform.convertQuotedIdentifiers(maxLength(constraintName, indexCount));
}
private String maxLength(String constraintName, int indexCount) {
return maxLength.maxLength(constraintName, indexCount);
}
public String primaryKeyName(String tableName) {
return maxLength(constraintNaming.primaryKeyName(tableName), 0);
return name(constraintNaming.primaryKeyName(tableName), 0);
}
public String foreignKeyConstraintName(String tableName, String columnName, int foreignKeyCount) {
return maxLength(constraintNaming.foreignKeyConstraintName(tableName, columnName), foreignKeyCount);
return name(constraintNaming.foreignKeyConstraintName(tableName, columnName), foreignKeyCount);
}
public String foreignKeyIndexName(String tableName, String[] columns, int indexCount) {
return maxLength(constraintNaming.foreignKeyIndexName(tableName, columns), indexCount);
return name(constraintNaming.foreignKeyIndexName(tableName, columns), indexCount);
}
public String foreignKeyIndexName(String tableName, String column, int indexCount) {
return maxLength(constraintNaming.foreignKeyIndexName(tableName, column), indexCount);
return name(constraintNaming.foreignKeyIndexName(tableName, column), indexCount);
}
public String indexName(String tableName, String column, int indexCount) {
return maxLength(constraintNaming.indexName(tableName, column), indexCount);
return name(constraintNaming.indexName(tableName, column), indexCount);
}
public String indexName(String tableName, String[] columns, int indexCount) {
return maxLength(constraintNaming.indexName(tableName, columns), indexCount);
return name(constraintNaming.indexName(tableName, columns), indexCount);
}
public String uniqueConstraintName(String tableName, String columnName, int indexCount) {
return maxLength(constraintNaming.uniqueConstraintName(tableName, columnName), indexCount);
return name(constraintNaming.uniqueConstraintName(tableName, columnName), indexCount);
}
public String uniqueConstraintName(String tableName, String[] columnNames, int indexCount) {
return maxLength(constraintNaming.uniqueConstraintName(tableName, columnNames), indexCount);
return name(constraintNaming.uniqueConstraintName(tableName, columnNames), indexCount);
}
public String checkConstraintName(String tableName, String columnName, int checkCount) {
return maxLength(constraintNaming.checkConstraintName(tableName, columnName), checkCount);
return name(constraintNaming.checkConstraintName(tableName, columnName), checkCount);
}
public MTable addTable(MTable table) {
@@ -99,16 +126,8 @@ public class ModelBuildContext {
model.addTableElementCollection(table);
}
public void addIndex(String indexName, String tableName, String columnName) {
model.addIndex(indexName, tableName, columnName);
}
public void addIndex(String indexName, String tableName, String[] columnNames) {
model.addIndex(indexName, tableName, columnNames);
}
private String maxLength(String constraintName, int indexCount) {
return maxLength.maxLength(constraintName, indexCount);
public void addIndex(MIndex index) {
model.addIndex(index);
}
/**
@@ -1,8 +1,11 @@
package io.ebeaninternal.dbmigration.model.build;
import io.ebean.annotation.Platform;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.util.IndexSet;
import io.ebeaninternal.dbmigration.model.MColumn;
import io.ebeaninternal.dbmigration.model.MCompoundForeignKey;
import io.ebeaninternal.dbmigration.model.MCompoundUniqueConstraint;
import io.ebeaninternal.dbmigration.model.MIndex;
import io.ebeaninternal.dbmigration.model.MTable;
import io.ebeaninternal.dbmigration.model.visitor.BaseTablePropertyVisitor;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -20,6 +23,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
/**
* Used as part of ModelBuildBeanVisitor and generally adds the MColumn to the associated
@@ -42,7 +46,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
private int countUnique;
private int countCheck;
public ModelBuildPropertyVisitor(ModelBuildContext ctx, MTable table, BeanDescriptor<?> beanDescriptor) {
this.ctx = ctx;
this.table = table;
@@ -54,36 +57,60 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
* Add unique constraints defined via JPA UniqueConstraint annotations.
*/
private void addIndexes(IndexDefinition[] indexes) {
if (indexes != null) {
for (IndexDefinition index : indexes) {
String[] columns = index.getColumns();
indexSet.add(columns);
if (index.isUnique()) {
String uqName = index.getName();
if (uqName == null || uqName.trim().isEmpty()) {
uqName = determineUniqueConstraintName(columns);
}
table.addUniqueConstraint(columns, false, uqName);
if (index.isUniqueConstraint()) {
table.addUniqueConstraint(createMUniqueConstraint(index, columns));
} else {
// 'just' an index (not a unique constraint)
String idxName = index.getName();
if (idxName == null || idxName.trim().isEmpty()) {
idxName = determineIndexName(columns);
}
ctx.addIndex(idxName, table.getName(), columns);
ctx.addIndex(createMIndex(indexName(index), table.getName(), index));
}
}
}
}
private MCompoundUniqueConstraint createMUniqueConstraint(IndexDefinition index, String[] columns) {
return new MCompoundUniqueConstraint(columns, false, uniqueConstraintName(index), platforms(index.getPlatforms()));
}
private String uniqueConstraintName(IndexDefinition index) {
String uqName = index.getName();
if (uqName == null || uqName.trim().isEmpty()) {
return uniqueConstraintName(index.getColumns());
}
return uqName;
}
private String indexName(IndexDefinition index) {
String idxName = index.getName();
if (idxName == null || idxName.trim().isEmpty()) {
idxName = indexName(index.getColumns());
}
return idxName;
}
private MIndex createMIndex(String indexName, String tableName, IndexDefinition index) {
return new MIndex(indexName, tableName, index.getColumns(), platforms(index.getPlatforms()), index.isUnique(), index.isConcurrent(), index.getDefinition());
}
private String platforms(Platform[] platforms) {
if (platforms == null || platforms.length == 0) {
return null;
}
StringJoiner joiner = new StringJoiner(",");
for (Platform platform : platforms) {
joiner.add(platform.name());
}
return joiner.toString();
}
@Override
public void visitEnd() {
// set the primary key name
table.setPkName(determinePrimaryKeyName());
table.setPkName(primaryKeyName());
// check if indexes on foreign keys should be suppressed
for (MColumn column : table.allColumns()) {
@@ -105,7 +132,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
}
addDraftTable();
table.updateCompoundIndices();
}
@@ -136,7 +162,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
if (cols.size() == 2) {
// always the second column that we put the unique constraint on
MColumn col = new ArrayList<>(cols).get(1);
col.setUnique(determineUniqueConstraintName(col.getName()));
col.setUnique(uniqueConstraintName(col.getName()));
}
}
} else if (p.isElementCollection()) {
@@ -146,9 +172,8 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
@Override
public void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded) {
if (p instanceof BeanPropertyAssocOne) {
visitOneImported((BeanPropertyAssocOne)p);
visitOneImported((BeanPropertyAssocOne<?>)p);
} else {
visitScalar(p);
}
@@ -174,8 +199,8 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
if (columns.length > 1) {
// compound foreign key
String refTable = p.getTargetDescriptor().getBaseTable();
String fkName = determineForeignKeyConstraintName(p.getName());
String fkIndex = determineForeignKeyIndexName(p.getName());
String fkName = foreignKeyConstraintName(p.getName());
String fkIndex = foreignKeyIndexName(p.getName());
compoundKey = new MCompoundForeignKey(fkName, refTable, fkIndex);
table.addForeignKey(compoundKey);
}
@@ -202,9 +227,9 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
refTable = p.getTargetDescriptor().getBaseTable();
}
col.setReferences(refTable + "." + refColumn);
col.setForeignKeyName(determineForeignKeyConstraintName(col.getName()));
col.setForeignKeyName(foreignKeyConstraintName(col.getName()));
if (p.hasForeignKeyIndex()) {
col.setForeignKeyIndex(determineForeignKeyIndexName(col.getName()));
col.setForeignKeyIndex(foreignKeyIndexName(col.getName()));
}
PropertyForeignKey foreignKey = p.getForeignKey();
if (foreignKey != null) {
@@ -222,13 +247,13 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
// for MsSqlServer we need different DDL to handle NULL values on this constraint
if (modelColumns.size() == 1) {
MColumn col = modelColumns.get(0);
col.setUniqueOneToOne(determineUniqueConstraintName(col.getName()));
indexSetAdd(col.getName());
col.setUniqueOneToOne(uniqueConstraintName(col.getName()));
} else {
String uqName = determineUniqueConstraintName(p.getName());
table.addUniqueConstraint(modelColumns, true, uqName);
indexSetAdd(modelColumns);
String[] cols = indexSetAdd(toColumnNames(modelColumns));
String uqName = uniqueConstraintName(p.getName());
table.addUniqueConstraint(new MCompoundUniqueConstraint(cols, uqName));
}
}
}
@@ -259,7 +284,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
if (foreignKey == null || !foreignKey.isNoConstraint()) {
TableJoinColumn[] columns = primaryKeyJoin.columns();
col.setReferences(primaryKeyJoin.getTable() + "." + columns[0].getForeignDbColumn());
col.setForeignKeyName(determineForeignKeyConstraintName(col.getName()));
col.setForeignKeyName(foreignKeyConstraintName(col.getName()));
if (foreignKey != null) {
col.setForeignKeyModes(foreignKey.getOnDelete(), foreignKey.getOnUpdate());
}
@@ -275,7 +300,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
col.setDbMigrationInfos(p.getDbMigrationInfos());
if (p.isUnique() && !p.isId()) {
col.setUnique(determineUniqueConstraintName(col.getName()));
col.setUnique(uniqueConstraintName(col.getName()));
indexSetAdd(col.getName());
}
Set<String> checkConstraintValues = p.getDbCheckConstraintValues();
@@ -285,7 +310,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
inheritInfo.appendCheckConstraintValues(p.getName(), checkConstraintValues);
}
col.setCheckConstraint(buildCheckConstraint(p.getDbColumn(), checkConstraintValues));
col.setCheckConstraintName(determineCheckConstraintName(col.getName()));
col.setCheckConstraintName(checkConstraintName(col.getName()));
}
lastColumn = col;
@@ -313,85 +338,73 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
indexSet.add(column);
}
private void indexSetAdd(List<MColumn> modelColumns) {
private String[] indexSetAdd(String[] cols) {
indexSet.add(cols);
return cols;
}
private String[] toColumnNames(List<MColumn> modelColumns) {
String[] cols = new String[modelColumns.size()];
for (int i = 0; i < modelColumns.size(); i++) {
cols[i] = modelColumns.get(i).getName();
}
indexSet.add(cols);
return cols;
}
/**
* Return the primary key constraint name.
*/
protected String determinePrimaryKeyName() {
protected String primaryKeyName() {
return ctx.primaryKeyName(table.getName());
}
/**
* Return the foreign key constraint name given a single column foreign key.
*/
protected String determineForeignKeyConstraintName(String columnName) {
protected String foreignKeyConstraintName(String columnName) {
return ctx.foreignKeyConstraintName(table.getName(), columnName, ++countForeignKey);
}
protected String determineForeignKeyIndexName(String column) {
protected String foreignKeyIndexName(String column) {
String[] cols = {column};
return determineForeignKeyIndexName(cols);
return foreignKeyIndexName(cols);
}
/**
* Return the foreign key constraint name given a single column foreign key.
*/
protected String determineForeignKeyIndexName(String[] columns) {
protected String foreignKeyIndexName(String[] columns) {
return ctx.foreignKeyIndexName(table.getName(), columns, ++countIndex);
}
/**
* Return the index name given a single column foreign key.
*/
protected String determineIndexName(String column) {
return ctx.indexName(table.getName(), column, ++countIndex);
}
/**
* Return the index name given multiple columns.
*/
protected String determineIndexName(String[] columns) {
protected String indexName(String[] columns) {
return ctx.indexName(table.getName(), columns, ++countIndex);
}
/**
* Return the unique constraint name.
*/
protected String determineUniqueConstraintName(String columnName) {
protected String uniqueConstraintName(String columnName) {
return ctx.uniqueConstraintName(table.getName(), columnName, ++countUnique);
}
/**
* Return the unique constraint name.
*/
protected String determineUniqueConstraintName(String[] columnNames) {
protected String uniqueConstraintName(String[] columnNames) {
return ctx.uniqueConstraintName(table.getName(), columnNames, ++countUnique);
}
/**
* Return the constraint name.
*/
protected String determineCheckConstraintName(String columnName) {
protected String checkConstraintName(String columnName) {
return ctx.checkConstraintName(table.getName(), columnName, ++countCheck);
}
private boolean hasValue(String val) {
return val != null && !val.isEmpty();
}

Some files were not shown because too many files have changed in this diff Show More