Compare commits

...
Author SHA1 Message Date
Rob Bygrave 6826fe1015 [maven-release-plugin] prepare release ebean-9.1.1 2016-11-08 00:32:38 +13:00
Rob Bygrave e67860cbe3 Merge branch 'master' of https://github.com/ebean-orm/ebean 2016-11-08 00:27:40 +13:00
Rob Bygrave b41238ddbb No effective change - modify TestHistoryInsert for more wait time and logging (PG test failing sometimes in CI) 2016-11-08 00:25:13 +13:00
Rob BygraveandGitHub c0b1c3d3ee Merge pull request #868 from 0xbaadf00d/feature/array-copy-performance
Use "Collection.addAll(...)" rather than manually copying arrays
2016-11-08 00:16:33 +13:00
Rob Bygrave ae69fcb80a #862 - ENH: Change ServerConfig such that if H2 ... no using createOnly = true in case the test EbeanServer instance is created for each test (and hence we need to drop if the same in memory db is used) 2016-11-08 00:10:15 +13:00
Rob Bygrave 6c4c33f1f3 No effective change - reduce logging in test (for CI) 2016-11-08 00:03:15 +13:00
Rob Bygrave 2986290947 Refactor - change use of 31 prime in various hash to 92821 2016-11-07 23:57:51 +13:00
Rob Bygrave 376cb9ebcb #869 - Clash on bind hash value for query cache with consecutive values of "01","20" and "02", "10" 2016-11-07 23:47:29 +13:00
Rob Bygrave 5cf5629232 #869 - Test for ... Clash on bind hash value for query cache with consecutive values of "01","20" and "02", "10" 2016-11-07 23:46:28 +13:00
Thibault Meyer 98aa5e9da9 Use "Collection.addAll(...)" rather than manually copying arrays 2016-11-07 11:07:37 +01:00
Rob BygraveandGitHub ed1df5bcbb Merge pull request #864 from 0xbaadf00d/feature/redundant-local-var
Remove redundant local variables
2016-11-07 22:14:59 +13:00
Thibault Meyer 6704ccc6a7 Merge branch 'master' into feature/redundant-local-var 2016-11-07 10:11:03 +01:00
Thibault Meyer 5f35e3c944 Remove redundant local variables 2016-11-07 10:03:50 +01:00
Rob Bygrave 0893972115 Fix for running CI tests as Postgres (where we need to explicitly turn on DDL generation and running for the tests). 2016-11-07 22:00:33 +13:00
Rob Bygrave 7a8d1b85a9 #866 - Fix RawSql mapping such that it automatically maps foreign key columns 2016-11-07 21:57:03 +13:00
Rob Bygrave 686593e9e8 No effective change - tidy up test Order entity bean 2016-11-07 21:36:19 +13:00
Rob Bygrave d05b593432 #862 - ENH: Change ServerConfig such that if H2 is the DataSource/DatabasePlatform then automatically it sets up for testing (ddl generation) 2016-11-07 19:50:05 +13:00
Rob Bygrave b581c893ec No effective change - tidy up test conversation User entity bean 2016-11-07 19:47:34 +13:00
Rob Bygrave 63f852475d #863 - @Enumerated(EnumType.STRING) DayOfWeek day; ... incorrectly maps to SQL Integer type 2016-11-07 17:15:47 +13:00
Rob BygraveandGitHub 51364763fb Merge pull request #860 from 0xbaadf00d/feature/replace-anonymous-classes
Replace anonymous classes with lambda expressions
2016-11-07 13:02:33 +13:00
Rob BygraveandGitHub ea408fd4c7 Merge pull request #861 from 0xbaadf00d/feature/coding-style
Remove redundant "public" modifier for interface methods
2016-11-07 12:58:23 +13:00
Thibault Meyer 8dc521ca8b Remove redundant "public" modifier for interface methods 2016-11-06 11:48:59 +01:00
Thibault Meyer 6680e2ea75 Replace anonymous classes with lambda expressions 2016-11-06 11:17:53 +01:00
Rob BygraveandGitHub da30df3b2b Merge pull request #858 from 0xbaadf00d/feature/deprecated-api-usage
Deprecated API usage - Modify ScalarTypeJodaLocalTime to use toDateTimeToday().getMillis()
2016-11-06 22:59:32 +13:00
Rob BygraveandGitHub d12ea89388 Merge pull request #854 from 0xbaadf00d/feature/explicit-type-to-diamond
Replace explicit type with <>
2016-11-06 22:54:24 +13:00
Thibault Meyer e0931e41e5 Remove deprecated API usage 2016-11-06 10:50:31 +01:00
Rob BygraveandGitHub c98d258127 Merge pull request #857 from 0xbaadf00d/feature/boxing-unboxing
Remove unnecessary boxing and unboxing
2016-11-06 22:43:33 +13:00
Rob BygraveandGitHub a4922a5b1d Merge pull request #856 from 0xbaadf00d/feature/identical-catch
Change identical 'catch' statements
2016-11-06 22:42:13 +13:00
Rob BygraveandGitHub edb2a69f6e Merge pull request #853 from 0xbaadf00d/fix/javadoc-error
Javadoc error
2016-11-06 22:40:52 +13:00
Thibault Meyer b94f852b67 Remove unnecessary boxing and unboxing 2016-11-06 10:29:42 +01:00
Thibault Meyer a8778ef14c Change identical 'catch' statements 2016-11-06 10:26:13 +01:00
Rob Bygrave cbfce0d14d #855 - Fix @Aggregation lazy loading and base select issue 2016-11-06 22:18:23 +13:00
Thibault Meyer abb25d397a Fix comments 2016-11-06 10:03:33 +01:00
Thibault Meyer 969a3c8b8d Replace explicit type with <> 2016-11-06 10:00:12 +01:00
Rob Bygrave 2a6d38eef2 #852 - javax.persistence.PersistenceException: No ScalarType registered for class Foo$1 ... where Foo is an Enum where individual instances override a method (example below). 2016-11-06 20:33:56 +13:00
Rob Bygrave d84080fb76 Refactor - clean up DefaultTypeManager, diamond operator and access modifiers only 2016-11-06 19:45:46 +13:00
Rob Bygrave 54d7a6fb42 Refactor - clean up docstore api mapping, diamond operator only 2016-11-05 23:04:33 +13:00
Rob Bygrave e5356e7118 Refactor - tidy up in com.avaje.ebeaninternal util, no effective change 2016-11-05 23:01:03 +13:00
Rob Bygrave e83556cada Refactor - clean up OrmQueryDetailParser, remove unused sections 2016-11-05 22:51:51 +13:00
Rob Bygrave 201a2826ab Refactor - tidy up in com.avaje.ebeaninternal.server.querydefn, no effective change 2016-11-05 22:46:43 +13:00
Rob Bygrave 670bac52f8 Refactor - tidy up in com.avaje.ebeaninternal.server.query, no effective change 2016-11-05 22:32:36 +13:00
Rob Bygrave 77e3346d9e Refactor - clean up CQueryPlan, CQueryPlanStats 2016-11-05 15:11:17 +13:00
Rob Bygrave 4663162f95 Refactor - no effective chang - Add SpiQuery getOriginKey() 2016-11-05 14:48:03 +13:00
Rob BygraveandGitHub 83a3ef43bd Merge pull request #851 from FOCONIS/fix/javawarnings
FIX some java warnings / rawtypes
2016-11-05 09:23:07 +13:00
Roland Praml 3701b314a0 FIX some java warnings / rawtypes 2016-11-04 12:19:38 +01:00
Rob Bygrave fad8358a9d Bump to java8-parent, update to Java8 LongAdder 2016-11-04 20:04:25 +13:00
Rob Bygrave 78c4dbb44d [maven-release-plugin] prepare for next development iteration 2016-11-04 19:19:11 +13:00
Rob Bygrave 9c74520a4b [maven-release-plugin] prepare release ebean-8.8.1 2016-11-04 19:19:02 +13:00
Rob Bygrave c911c710d5 Bump pom to 8.8.1-SNAPSHOT 2016-11-04 01:17:08 +13:00
Rob Bygrave f08dd01035 #836 - ENH: Add support for @DbArray even for H2 db 2016-11-04 01:16:32 +13:00
Rob Bygrave a1b4af2716 Refactor - no effective change - remove un-required callback from PersistExecute to PersistRequestBean 2016-11-03 23:42:43 +13:00
Rob Bygrave 8c500c5836 #846 - Add soft delete related callbacks 2016-11-03 23:27:39 +13:00
Rob Bygrave c1d6cc7b75 Refactor - no real change - tighter access on SqlTreeNodeBean 2016-11-03 23:18:14 +13:00
Rob Bygrave d6fe16ffda Change permissions on travis scripts 2016-11-03 23:14:14 +13:00
Rob Bygrave d0230491e5 #99 - ENH (419) : Simplify aggregation queries - part 2 2016-11-03 23:06:54 +13:00
Rob Bygrave 3526f71f0a #99 - ENH (419) : Simplify aggregation queries 2016-11-02 22:10:22 +13:00
Rob Bygrave 18f943ab2b [maven-release-plugin] prepare for next development iteration 2016-10-31 21:59:39 +13:00
Rob Bygrave 03ff53c7af [maven-release-plugin] prepare release ebean-8.7.1 2016-10-31 21:59:30 +13:00
Rob Bygrave c20d111ea2 Bump version to 8.7.1-SNAPSHOT 2016-10-31 21:58:43 +13:00
Rob Bygrave 920fa73d11 #837 - ENH: Support using @HistoryExclude on normal properties (other than @ManyToMany) 2016-10-31 21:57:16 +13:00
Rob Bygrave cd62686337 #845 - Fix EQL parsing to support the 'inverse' form - e.g. where 'Rob' eq firstName (where the path is on the RHS rather than LHS) 2016-10-31 21:32:29 +13:00
Rob Bygrave e9ad459fa5 #843 - Change ServerConfig name to default to "db" (prior default was null) and defaultServer to true 2016-10-31 20:40:26 +13:00
Rob Bygrave ea5e9fa75a #842 - For @DbJson map the type Map<String, ?> (using the wildcard) ... the same as Map<String, Object> 2016-10-31 20:15:23 +13:00
Rob BygraveandGitHub d44460e180 Merge pull request #841 from FOCONIS/bugfix/softdelete-calls-wrong-lifecycle-method
Bugfix/softdelete calls wrong lifecycle method
2016-10-27 10:17:29 +13:00
Roland Praml 0e5ebf3fea FIX: softDeleting an entity calls now preUpdate/postUpdate 2016-10-26 15:47:54 +02:00
Roland Praml 42d35f8ec6 FIX: removed trailing commas in logs 2016-10-26 15:45:10 +02:00
Rob Bygrave 7f52e466e0 [maven-release-plugin] prepare for next development iteration 2016-10-25 22:23:13 +13:00
Rob Bygrave 861a8a4ee5 [maven-release-plugin] prepare release ebean-8.6.1 2016-10-25 22:23:04 +13:00
Rob Bygrave abe2f76d5c Bump pom to 8.6.1-SNAPSHOT 2016-10-25 22:22:16 +13:00
Rob Bygrave d0f75a940c #239 - Support Geometric types of Postgres, Also adding LineString, MultiLineString and MultiPoint 2016-10-25 22:19:33 +13:00
Rob Bygrave 44ad78b5e0 #239 - Support Geometric types of Postgres 2016-10-21 02:45:06 +13:00
Rob Bygrave 967b4de784 #239 - Support Geometric types of Postgres 2016-10-21 02:42:25 +13:00
Rob Bygrave ea45201905 [maven-release-plugin] prepare for next development iteration 2016-10-17 20:58:19 +13:00
Rob Bygrave 938f4ec9c2 [maven-release-plugin] prepare release ebean-8.5.1 2016-10-17 20:58:10 +13:00
Rob Bygrave 99bd2972d0 Bump pom version to 8.5.1-SNAPSHOT 2016-10-17 20:57:26 +13:00
Rob Bygrave deac291951 #835 - A query that includes a fetch() of a many that is @SoftDelete where all the rows are soft deleted returns incorrect results 2016-10-17 20:52:18 +13:00
Rob Bygrave 3161e24677 #835 - Tests for - A query that includes a fetch() of a many that is @SoftDelete where all the rows are soft deleted returns incorrect results 2016-10-17 20:51:22 +13:00
Rob Bygrave 37804bd083 Modify tests to avoid MySql keyword (mod) for column names 2016-10-17 20:50:48 +13:00
Rob Bygrave 0a2a987695 Modify tests to avoid Oracle keywords for column names 2016-10-15 17:03:32 +13:00
Rob Bygrave 4a085cb819 #834 - Oracle DDL for drop index and drop constraints incorrectly includes "if exits" 2016-10-15 17:02:44 +13:00
Rob Bygrave 67469ef4d3 No effective change - change Line endings to CR (from CRLF) 2016-10-15 14:39:20 +13:00
Rob Bygrave c3f43d503f #832 - Refactor: Change generated SQL to use "left join" rather than "left outer join" - change tests 2016-10-15 14:37:36 +13:00
Rob Bygrave 9158f46bb3 #832 - Refactor: Change generated SQL to use "left join" rather than "left outer join" 2016-10-15 14:36:11 +13:00
Rob Bygrave b3bfa88eb5 [maven-release-plugin] prepare for next development iteration 2016-10-15 01:14:29 +13:00
Rob Bygrave 185dec9c02 [maven-release-plugin] prepare release ebean-8.4.2 2016-10-15 01:14:18 +13:00
Rob Bygrave 20634233ca Update tests only - handle MySql specifics (boolean literal, lack of order by nulls last) 2016-10-15 00:55:09 +13:00
Rob Bygrave 7c9dda586e No effective change - format only 2016-10-14 23:49:00 +13:00
Rob BygraveandGitHub 3ca0f7b776 Merge pull request #828 from FOCONIS/feature/postconstruct
Feature/postconstruct
2016-10-14 23:44:45 +13:00
Rob Bygrave 85caca48de No effective change - add tests for naming convention on m2m columns 2016-10-14 23:29:50 +13:00
Rob Bygrave ff85a51994 No effective change - format only 2016-10-14 23:29:27 +13:00
Rob BygraveandGitHub 6dc3038d0d Merge pull request #830 from lvffilho/master
Add NamingConvention support to ManyToMany columns
2016-10-14 23:27:32 +13:00
Rob BygraveandGitHub c0fcb77f3d Merge pull request #829 from kdazzle/patch-1
Remove outdated findPageList(int, int) javadocs
2016-10-14 23:17:42 +13:00
Rob Bygrave da5d5296b6 #831 - EQL query language parser needs to throw exception on invalid query ... "find ..." - remove unhelpful tests 2016-10-14 21:09:23 +13:00
Rob Bygrave f04ab28c3f #831 - EQL query language parser needs to throw exception on invalid query ... "find ..." 2016-10-14 21:08:23 +13:00
Rob Bygrave d6cd41f8d2 #831 - EQL query language parser needs to throw exception on invalid query ... "find ..." - tests 2016-10-14 21:07:31 +13:00
Rob Bygrave 504a209a78 Merge branch 'master' of https://github.com/ebean-orm/ebean 2016-10-14 20:24:13 +13:00
Rob Bygrave 9f98b5333d Update tests - for asserts trim column alias from generated SQL if necessary (to support generating without column alias) 2016-10-14 20:23:36 +13:00
Eddie Mc Greal 2a600adbcf Added tests for EQL - syntactically incorrect und named parameter on LHS of comparison operator 2016-10-12 19:42:31 +02:00
Luiz Filho 9ce6007330 Add NamingConvention support to ManyToMany columns 2016-10-07 16:46:40 -03:00
Kyle ValadeandGitHub 7780dd6272 Remove outdated findPageList(int, int) javadocs
The class no longer supports that type of call
2016-10-07 12:26:06 -04:00
Roland Praml b01ddea781 FIX: fixed non-deterministic failing TestHistoryInsert testcase 2016-10-05 21:51:42 +02:00
Roland Praml b848587cd3 ADD: Testcases for PostConstruct 2016-10-05 21:51:04 +02:00
Roland Praml fe7e929a99 Refactor: Removed duplicate code from BootupClasses - use generics. 2016-10-05 21:50:22 +02:00
Roland Praml 3ee0b0224e ENH: Support for javax.annotation.PostConstruct. BeanPostConstructListener will be informed when an entity-bean is constructed/created to perform dependency-injection (e.g. Spring-Autowire) 2016-10-05 21:48:11 +02:00
Roland Praml 169eba4296 No effective code change - fixed commets 2016-10-05 21:39:44 +02:00
Robin Bygrave 91d3279061 [maven-release-plugin] prepare for next development iteration 2016-10-03 23:40:32 +13:00
Robin Bygrave b4b7c631da [maven-release-plugin] prepare release ebean-8.4.1 2016-10-03 23:40:22 +13:00
Robin Bygrave 4f98ca5d91 #821 - CQueryIteratorSimple not working with consecutive calls to hasNext() - ie. without matching calls to next() 2016-10-03 23:36:03 +13:00
Robin Bygrave 014a9aef6f #826 - Remove deprecated methods - migrate findRowCount() to findCount() & findFutureRowCount() to findFutureCount() 2016-10-03 22:31:33 +13:00
Robin Bygrave f21c33df7b Bump pom to 8.4.1-SNAPSHOT 2016-10-03 22:16:52 +13:00
Robin Bygrave f1eb494e0d #824 - Refactor com.avaje.ebean.config.dbplatform DbType & DbPlatformType - handle logical and plaform ddl conversion 2016-10-03 22:04:37 +13:00
Robin Bygrave d26203db1f #824 - Refactor com.avaje.ebean.config.dbplatform DbType & DbPlatformType - support custom DbType mapping options 2016-10-03 20:52:53 +13:00
Robin Bygrave abfe58fb06 #824 - Refactor com.avaje.ebean.config.dbplatform DbType & DbPlatformType - no effective change, tidy. 2016-09-23 00:27:39 +12:00
Robin Bygrave d0ad5f6c48 #824 - Refactor com.avaje.ebean.config.dbplatform DbType & DbPlatformType 2016-09-23 00:17:51 +12:00
Robin Bygrave bc4a246f33 [maven-release-plugin] prepare for next development iteration 2016-09-22 22:25:14 +12:00
Robin Bygrave 61f590944b [maven-release-plugin] prepare release ebean-8.3.1 2016-09-22 22:25:05 +12:00
Robin Bygrave 223e53416d Bump pom version to 8.3.1-SNAPSHOT 2016-09-22 22:24:17 +12:00
Robin Bygrave a3143b1cf6 #822 - EbeanServer.getBeanId(entity) does not trigger jdbc batch flush - when bean inserted with jdbc batch mode 2016-09-22 21:25:22 +12:00
Robin Bygrave bd3e7c8035 #823 - Remove deprecated API from PagedList 2016-09-22 21:02:28 +12:00
Robin Bygrave b753ce3a73 #820 - #718 Removed PagedList.getPageIndex() - Can it be added back? 2016-09-22 20:57:17 +12:00
Robin Bygrave a0f2ebe448 [maven-release-plugin] prepare for next development iteration 2016-09-01 21:08:23 +12:00
Robin Bygrave 7e7810602e [maven-release-plugin] prepare release ebean-8.2.3 2016-09-01 21:08:09 +12:00
Robin Bygrave d218fff374 #819 - Fix for bug in @ManyToOne relations with enabled soft-deletes 2016-08-31 23:03:00 +12:00
Rob BygraveandGitHub a0e927d353 Merge pull request #819 from FOCONIS/test-softdelete
ADD: testcase for bug in @ManyToOne relations with enabled soft-deletes
2016-08-31 22:05:46 +12:00
Robin Bygrave 51a58d4993 No effective change - remove whitespace in test 2016-08-31 20:57:24 +12:00
Roland Praml b9f0ee7ac0 ADD: testcase for https://groups.google.com/forum/#!topic/ebean/WKbGmROoIRA 2016-08-31 09:48:11 +02:00
Roland Praml 4f3b461f8e FIX: TestHistoryInsert / TestNewTypes failing nondeterministic 2016-08-30 09:14:22 +02:00
Roland Praml adfe5f0305 FIX: Bean did not get dirty when modified with ExpressionPath.pathSet 2016-08-30 09:13:44 +02:00
Robin Bygrave 1796c8b9bc #817 - SqlRow getBoolean() does not treat numeric 1 value as true (with MySql and other DB's without native boolean type) - Fix test for PG 2016-08-29 21:50:14 +12:00
Robin Bygrave 4bad4358f0 Merge branch 'master' of https://github.com/ebean-orm/ebean 2016-08-29 21:06:55 +12:00
Robin Bygrave 92665ebc3b Refactor - tidy of DefaultSqlRow - no logical change 2016-08-29 21:06:31 +12:00
Robin Bygrave 59670d0303 #817 - SqlRow getBoolean() does not treat numeric 1 value as true (with MySql and other DB's without native boolean type) 2016-08-29 20:54:49 +12:00
Robin Bygrave 244275fd72 #816 - Error saving circular relationships (when generated Id values) 2016-08-25 22:44:22 +12:00
Robin Bygrave d1e2176a5a [maven-release-plugin] prepare for next development iteration 2016-08-24 22:53:15 +12:00
Robin Bygrave 43968e70b8 [maven-release-plugin] prepare release ebean-8.2.2 2016-08-24 22:53:02 +12:00
Robin Bygrave 0aa3bd3c97 Update README 2016-08-24 22:52:02 +12:00
Robin Bygrave 2d85a9a20c Update README 2016-08-24 22:45:14 +12:00
Robin Bygrave 157dfcfeb6 #815 - ENH: When loading ebean-autotune.xml also look in resources (if not found as file) 2016-08-24 22:19:46 +12:00
Robin Bygrave 2b7c204072 No effective change - adjust tests for deleting OneToOne - Tire to Wheel 2016-08-24 21:32:10 +12:00
Robin Bygrave be731feb6b No effective change - adjust tests for H2 error vs Postgres truncate with oversized varchar input 2016-08-23 20:01:11 +12:00
Robin Bygrave da15d0b2c6 No effective change - format javadoc 2016-08-23 20:00:07 +12:00
Rob BygraveandGitHub 9c5fd496c1 Merge pull request #814 from FOCONIS/master
ENHANCEMENT: multiple indices & meta-annotation support similar to spring-framework
2016-08-23 19:43:04 +12:00
Roland Praml 5075ea32b4 Merge branch 'master' of github.com:FOCONIS/avaje-ebeanorm 2016-08-23 09:27:28 +02:00
Roland Praml f5c8d8896f Used @Repeatable feature from JDK8 for @Indices 2016-08-23 09:27:12 +02:00
Roland Praml 32fdff9f11 Used @Repeatable feature from JDK8 for @Indices 2016-08-22 10:00:13 +02:00
Roland Praml 87f6964995 Ignored tests that make problems with Postgres 2016-08-22 09:34:45 +02:00
Roland Praml b45226dd41 Merge remote-tracking branch 'ebean/master' 2016-08-16 11:06:47 +02:00
Roland Praml 992c40d362 no effective code change - fix indentions 2016-08-16 11:06:01 +02:00
Rob BygraveandGitHub 9144d60948 Merge pull request #813 from zhangshifeng/fix-artifactId
Update README.md and pom.xml for artifactId change
2016-08-13 11:23:04 +12:00
zhangshifeng 6396143d49 Update README.md and pom.xml for artifactId change 2016-08-12 17:20:29 +08:00
Robin Bygrave ce045ca0fe No effective change - remove unused methods (from ImportedId) 2016-08-11 20:22:35 +12:00
Robin Bygrave d722d34072 [maven-release-plugin] prepare for next development iteration 2016-08-05 13:53:23 +12:00
Robin Bygrave 2cc4c2c265 [maven-release-plugin] prepare release ebean-8.2.1 2016-08-05 13:53:03 +12:00
Robin Bygrave 0a830841c4 Bump pom to 8.2.1-SNAPSHOT 2016-08-05 13:52:09 +12:00
Robin Bygrave c427009b93 #812 - Remove deprecated includeSoftDeletes() ... migrate to setIncludeSoftDeletes() 2016-08-05 13:47:32 +12:00
Robin Bygrave 7f42d045ac No effective change - javadoc typo 2016-08-05 13:29:28 +12:00
Robin Bygrave 43afaf1344 #811 - ENH: Restore findIterate() as alternative to findEach / findEachWhile 2016-08-05 13:01:42 +12:00
Robin Bygrave 6c182ecaa5 #810 - ENH: Add transaction.isRollbackOnly() 2016-08-05 12:14:58 +12:00
Robin Bygrave fdb839f90e #809 - Add test / example showing ... transaction.setPersistCascade(false) and transaction.commitAndContinue(); 2016-08-05 11:20:12 +12:00
Robin Bygrave 16be213faf #808 - ENH: Add Transaction commitAndContinue() ... 2016-08-05 10:39:17 +12:00
Robin Bygrave 3344f0ddb0 Refactor - remove unused method JdbcTransaction.notifyQueryOnly(). 2016-08-04 23:25:50 +12:00
Robin Bygrave 479ac38537 #807 - Deprecate TransactionEventListener ... migrate to TransactionCallback 2016-08-04 23:17:57 +12:00
Robin Bygrave e30ad80f5f #806 - Deprecate OnQueryOnly.CLOSE ... 2016-08-04 23:02:26 +12:00
Robin Bygrave 08e46d6bf3 #805 - ENH: Add BeanState.resetForInsert() ... This resets bean state such that a save() results in an insert 2016-08-04 22:49:07 +12:00
Robin Bygrave 876476fdc1 #804 - Remove API - findMap(property, type) ... migrate to query.setMapKey() 2016-08-04 20:30:18 +12:00
Robin Bygrave 81de83a6e7 #803 - Fix generics on findMap() to ... <K> Map<K, T> findMap(); 2016-08-04 20:23:11 +12:00
Robin Bygrave b5b221ffb1 No effective change - remove unused constructors 2016-08-04 17:32:18 +12:00
Robin Bygrave 3c6eab6c85 #802 - Find generics on findIds() - refactor internals of find ids to use find single attribute 2016-08-04 17:28:41 +12:00
Robin Bygrave 1be30f1671 #125 - ENH: Add support for query returning a List of single Attribute type 2016-08-04 16:41:50 +12:00
Robin Bygrave 9a5cb242ce No effective change - remove commented out line from pom 2016-08-04 13:56:09 +12:00
Robin Bygrave ea69cae4a3 [maven-release-plugin] prepare for next development iteration 2016-08-03 16:24:43 +12:00
Robin Bygrave 629fb7a433 [maven-release-plugin] prepare release ebean-8.1.1 2016-08-03 16:24:23 +12:00
Robin Bygrave 4ff10da739 #801 - Change maven groupId ... to org.avaje.ebean, artifactId to ebean 2016-08-03 16:23:26 +12:00
Robin Bygrave 9472592a50 [maven-release-plugin] prepare for next development iteration 2016-08-03 00:40:37 +12:00
Robin Bygrave f42682ca90 [maven-release-plugin] prepare release avaje-ebeanorm-8.1.1 2016-08-03 00:40:18 +12:00
Robin Bygrave 5dc296e644 #798 - Add @Transactional based test 2016-08-03 00:38:58 +12:00
Robin Bygrave 380660913f No effective change - javadoc update on Query 2016-08-02 23:42:00 +12:00
Robin Bygrave d08ac6973e #800 - ENH: Add query.fetchQuery() and query.fetchLazy() ... as nicer alternatives to FetchConfig use 2016-08-02 23:33:02 +12:00
Robin Bygrave 9d23c1d56e #800 - ENH: Add query.fetchQuery() and query.fetchLazy() ... as nicer alternatives to FetchConfig use 2016-08-02 23:30:26 +12:00
Robin Bygrave b5d6c5f70b #800 - ENH: Add query.fetchQuery() and query.fetchLazy() ... as nicer alternatives to FetchConfig use 2016-08-02 23:30:04 +12:00
Robin Bygrave 3657d05774 #798 - ENH: Add support for transparent full JDBC batch. Via enhancement agent 8.1.1 ... 2016-08-02 21:41:13 +12:00
Robin Bygrave 2de8ae777d Merge branch 'wip/getterCallback' 2016-08-02 21:34:41 +12:00
Robin Bygrave 16950a5641 [maven-release-plugin] prepare for next development iteration 2016-08-02 21:32:08 +12:00
Robin Bygrave ad992d07ce [maven-release-plugin] prepare release avaje-ebeanorm-7.21.2 2016-08-02 21:31:47 +12:00
Robin Bygrave cbcec8f5ea No effective change - tidy 2016-08-02 20:32:59 +12:00
Robin Bygrave 6e2148d20b #799 - Query.fetch(path) when converted to query join default to batchSize 10 rather than 100 2016-08-02 20:19:38 +12:00
Robin Bygrave ca1c0a08f3 No effective change - remove whitespace on DLoadBeanContext 2016-08-02 20:14:46 +12:00
Robin Bygrave baa6fc355e No effective change - javadoc update on FetchConfig 2016-08-02 20:14:07 +12:00
Robin Bygrave dacdc26902 #798 - ENH: Add support for transparent full JDBC batch. Via enhancement agent 8.1.1 intercept bean getter to automatically flush the JDBC batch buffer. 2016-08-02 16:16:34 +12:00
Robin Bygrave 48edf64013 No effective change - typo in javadoc 2016-08-02 11:10:19 +12:00
Robin Bygrave e2ee6e8e98 No effective change - update tests with EBasicVer new constructor 2016-08-02 11:06:09 +12:00
Robin Bygrave e6e6a28245 No effective change - tidy asserts on TestQueryDistinct (AssertJ string contains etc) 2016-08-01 22:53:47 +12:00
Rob BygraveandGitHub 82a695a98a Merge pull request #797 from backslash47/master
Add check for distinct query when adding id attribute to order clause in paging query
2016-08-01 22:47:34 +12:00
Matus Zamborsky cdad31bd8a Added test for distinct paging query 2016-08-01 12:20:50 +02:00
Matus Zamborsky 4d16cf9caa Add check for distinct query when adding id attribute to order clause in paging query 2016-08-01 10:13:05 +02:00
Robin Bygrave 84a86cad0e #794 - Refactor - tidy code, remove unused mimetypes properties 2016-07-31 23:34:55 +12:00
Robin Bygrave dfdf87fa2d #794 - Refactor - tidy code, javadoc tidy 2016-07-31 23:33:29 +12:00
Robin Bygrave ee0615caec #794 - Refactor - tidy code, use uppercase L for Long literal 2016-07-31 23:33:07 +12:00
Robin Bygrave 79b8395f8f #794 - Refactor - tidy code, simplify if 2016-07-31 23:32:37 +12:00
Robin Bygrave 87c479cd95 #794 - Refactor - tidy code, remove unused imports 2016-07-31 23:24:30 +12:00
Robin Bygrave abbdda810a #794 - Refactor - tidy code, remove unused method arguments 2016-07-31 23:23:57 +12:00
Robin Bygrave e621900de9 #794 - Refactor - tidy code, remove unused method arguments 2016-07-31 23:23:43 +12:00
Robin Bygrave 76b33511e1 #793 - com.avaje.ebean.event.changelog.BeanChange not keeping passed id value 2016-07-31 23:14:08 +12:00
Robin Bygrave 77deab5cf0 #792 - Change Logging Rollback message on org.avaje.ebean.TXN from INFO level to DEBUG level 2016-07-31 22:52:48 +12:00
Robin Bygrave 4a9f8cef0e No effective change - rename SpiQuery method for m2mIncludeJoin and simplify OrmQueryPlanKey to associated intersection table name 2016-07-31 22:49:10 +12:00
Robin Bygrave 4d1340c16c No effective change - rename SpiQuery method for m2mIncludeJoin and simplify OrmQueryPlanKey to associated intersection table name 2016-07-31 22:46:07 +12:00
Robin Bygrave 74c6c71301 [maven-release-plugin] prepare for next development iteration 2016-07-31 21:28:17 +12:00
Robin Bygrave 0f0028eb1f [maven-release-plugin] prepare release avaje-ebeanorm-7.21.1 2016-07-31 21:27:58 +12:00
Robin Bygrave b4a1d52067 #791 - ENH: Add transaction.setRollbackOnly() ... (and Ebean.setRollbackOnly()) 2016-07-31 21:24:31 +12:00
Robin Bygrave d82148248c No effective change - javadoc tidy 2016-07-31 20:55:34 +12:00
Robin Bygrave dc7c854432 #788 - Deprecate findRowCount() ... add findCount(). Effectively renaming findRowCount() to findCount() 2016-07-31 19:06:21 +12:00
Robin Bygrave 7c83010df1 #788 - Deprecate findRowCount() ... add findCount(). Effectively renaming findRowCount() to findCount() 2016-07-31 16:39:23 +12:00
Robin Bygrave ed41e58073 Bump pom version to 7.21.1-SNAPSHOT 2016-07-31 16:01:00 +12:00
Robin Bygrave 5bab9eb648 #790 - DB Migration with multiple platforms (and no maven H2 dependency) gives: java.lang.NoClassDefFoundError: org/h2/api/Trigger 2016-07-31 15:59:54 +12:00
Robin Bygrave 5ce8eb6046 No effective change - remove unused methods 2016-07-31 15:02:05 +12:00
Robin Bygrave 56fee2ea9b #789 - findCount() ... with where raw(...) expression that includes a "many" produces incorrect SQL 2016-07-31 14:57:12 +12:00
Roland Praml 84f32c2ace ENH: support for multiple indices added 2016-07-30 16:06:01 +02:00
Roland Praml 85288a0652 Added a testcase that checks if meta-annotations are recognized 2016-07-30 13:13:54 +02:00
Roland Praml 3183287833 ENH: meta-annotation support similar to spring.
See http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-meta-annotations for detailed explanation
2016-07-30 12:44:14 +02:00
Robin Bygrave 780ee7c7c0 [maven-release-plugin] prepare for next development iteration 2016-07-25 23:37:18 +12:00
Robin Bygrave 2bac7bf84d [maven-release-plugin] prepare release avaje-ebeanorm-7.20.1 2016-07-25 23:36:58 +12:00
Robin Bygrave 499862438d Bump pom to 7.20.1-SNAPSHOT 2016-07-25 23:36:12 +12:00
Robin Bygrave 4ad0b7cf66 #786 - Bump avaje-dbmigration to 1.2.1 ... which uses autoCommit true when running drop-all ddl 2016-07-25 23:34:17 +12:00
Robin Bygrave 6108ef484b #782 - History Many-To-Many Lazy-Loads fail 2016-07-25 23:31:02 +12:00
Robin Bygrave b763f4c875 #783 - HistoryExclude Many-to-Many Query-Generation Error 2016-07-25 23:29:33 +12:00
Robin Bygrave ca7285b2ad #783 - tests for ... HistoryExclude Many-to-Many Query-Generation Error 2016-07-25 23:28:45 +12:00
Robin Bygrave 75b639bc15 #782 - tests for ... History Many-To-Many Lazy-Loads fail 2016-07-25 23:22:33 +12:00
Robin Bygrave 1a7c4dac3f #1 - Change DdlGenerator.runScript() so that it uses connection.setAutoCommit(true) for drop ddl - when expectErrors is true 2016-07-25 23:03:00 +12:00
Robin Bygrave 6828fa1786 #784 - DDL DB Migration - Add @ManyToOne does not generate Foreign key and index ddl statements in migration script 2016-07-25 20:44:15 +12:00
Robin Bygrave ba7e729ae1 #785 - Bump avaje-classpath-scanner-api dependency to 2.2 for Windows fixes to classpath-scanner 2016-07-25 11:39:41 +12:00
Rob BygraveandGitHub c3fba72a24 Merge pull request #781 from FOCONIS/master
FIX: PathTests - on Windows
2016-07-25 11:14:23 +12:00
Robin Bygrave ff401cfc72 [maven-release-plugin] prepare for next development iteration 2016-07-20 00:03:20 +12:00
Robin Bygrave 7902276296 [maven-release-plugin] prepare release avaje-ebeanorm-7.19.1 2016-07-20 00:02:59 +12:00
Robin Bygrave 95f7a85aa1 Bump version to 7.19.1-SNAPSHOT 2016-07-20 00:02:08 +12:00
Roland Praml cf9eb4ed97 FIX: PathTests - they fail on windows machine, because the OS translates "/tmp" to "c:\tmp". bumped classpath-canner to current API version 2016-07-19 13:25:53 +02:00
Robin Bygrave b5cb04a6ed #780 - Remove ServerConfig registerJmxMBeans ... as it is no longer used 2016-07-18 09:22:22 +12:00
Robin Bygrave 5a9193f732 #779 - Refactor - Tidy internals of DefaultOrmQuery, remove unused String query property. 2016-07-15 23:51:27 +12:00
Robin Bygrave 55584f09d5 #778 - ENH: Add support for loading named queries from ebean.xml 2016-07-15 23:33:09 +12:00
Robin Bygrave 05eb0bfc55 #777 - ENH: Add support for @NamedQuery and @NamedQueries 2016-07-15 23:15:18 +12:00
Robin Bygrave cf13119b49 #776 - Remove ServerConfig.cacheWarmingDelay ... as it is no longer used 2016-07-15 20:51:22 +12:00
Robin Bygrave e0eff149b5 #775 - Change DefaultBackgroundExecutor to use JDK cached thread pool (rather than configure min/max size etc) 2016-07-15 20:48:41 +12:00
Robin Bygrave 474c2d5595 EQL - Add / expose via EbeanServer.createQuery(type, eql) method 2016-07-13 16:40:52 +12:00
Robin Bygrave e58cec8bdd EQL - parsing order by clause 2016-07-13 15:28:06 +12:00
Robin Bygrave 9dd82c0dd7 EQL - parsing limit offset clause 2016-07-13 14:30:12 +12:00
Robin Bygrave 49d3cc91e4 EQL - parsing select clause with distinct option 2016-07-13 14:07:59 +12:00
Robin Bygrave a8c2fc2ed5 EQL - parsing select clause 2016-07-13 13:55:56 +12:00
Robin Bygrave 45d7e3cafd EQL - parsing fetch clause with lazy/query option 2016-07-13 13:04:38 +12:00
Robin Bygrave be6754bd06 EQL - parsing fetch clause 2016-07-13 11:01:44 +12:00
Robin Bygrave 83c16ad1c6 EQL - parsing IN expressions with named parameters 2016-07-13 10:12:15 +12:00
Robin Bygrave 3f8b389999 EQL - parsing BETWEEN property expressions 2016-07-13 09:48:58 +12:00
Robin Bygrave b4b6a13e75 EQL - parsing BETWEEN expressions 2016-07-13 09:30:00 +12:00
Robin Bygrave 3fad4aae2f EQL - parsing IN expressions 2016-07-12 23:29:34 +12:00
Robin Bygrave ceab95e6c2 EQL - Simplify nested query where expressions after parsing 2016-07-12 22:51:02 +12:00
Robin Bygrave 84b37fb014 EQL Named parameter support for Like and ieq 2016-07-12 21:56:43 +12:00
Robin Bygrave 1a1c432c2a Initial add of SpiNamedParam 2016-07-12 20:45:33 +12:00
Robin Bygrave 86faa947af No effective change - tidy tests 2016-07-12 16:22:18 +12:00
Robin Bygrave 6b54b6ef46 Refactor BeanPropertyAssocOne findByParentIds use of raw expression 2016-07-12 16:11:51 +12:00
Robin Bygrave d8dfd66af3 Refactor BeanPropertyAssocMany findByParentIds use of raw expression 2016-07-12 16:01:32 +12:00
Robin Bygrave 675c51b8c1 Add IEQ support 2016-07-12 15:22:04 +12:00
Robin Bygrave 3cd7ecaa4a Merge branch 'wip/eql1' into wip/eql2 2016-07-12 15:05:00 +12:00
Robin Bygrave 1b322955ee [maven-release-plugin] prepare for next development iteration 2016-07-11 21:31:44 +12:00
Robin Bygrave 8115c5e230 [maven-release-plugin] prepare release avaje-ebeanorm-7.18.1 2016-07-11 21:31:25 +12:00
Robin Bygrave ad180c5531 No effective change - reduce test logging 2016-07-11 21:27:34 +12:00
Robin Bygrave b454f46dd4 Bump pom to 7.18.1-SNAPSHOT 2016-07-11 21:27:06 +12:00
Robin Bygrave 8a853b28f3 #772 - DB Migration DDL - alter table add column ... needs type conversion when using multiple platforms. e.g. varchar(20) ... convert to varchar2(20) for Oracle 2016-07-11 21:25:58 +12:00
Robin Bygrave a1be7ba5dd #771 - DB Migration DDL when using multiple platforms ... destination into sub directories rather than file suffix 2016-07-11 21:17:12 +12:00
Robin Bygrave 3914516793 #770 - DB Migration DDL generation run offline when using multiple platforms 2016-07-11 20:20:26 +12:00
Robin Bygrave 8c5854f77c #770 - DB Migration DDL generation run offline when using multiple platforms 2016-07-11 20:14:29 +12:00
Robin Bygrave 0bc5b94eae #770 - DB Migration DDL generation run offline when using multiple platforms 2016-07-11 20:08:26 +12:00
Robin Bygrave 12fa287f35 #769 - DB Migration DDL generation for UUID type when generating multiple platforms 2016-07-11 19:54:50 +12:00
Robin Bygrave 2991cb9ad1 #768 - Query.setDisableLazyLoading(true) ... not disabling lazy loading on @ManyToOne reference bean 2016-07-11 15:09:59 +12:00
Robin Bygrave 3b7f5496a8 #767 - Query.setDisableLazyLoading(true) ... not disabling lazy loading on @OneToMany 2016-07-11 12:28:31 +12:00
Robin Bygrave 4be703ff6e #767 - Query.setDisableLazyLoading(true) ... not disabling lazy loading on @OneToMany 2016-07-11 11:58:02 +12:00
Robin Bygrave d2c5765ac1 No effective change - tidy comments 2016-07-11 11:24:57 +12:00
Robin Bygrave aaf256b9be #766 - RawSql should automatically map column alias with underscore to camelCase ... so item_total should automatically map to bean property itemTotal 2016-07-08 23:44:11 +12:00
Robin Bygrave c7c6410cd9 #765 - ENH: Add ebean.xml with support for named RawSql, also adds EbeanServer.createNamedQuery() 2016-07-08 22:35:04 +12:00
Robin Bygrave 2c3c23725a No effective change - reformat code 2016-07-08 15:37:26 +12:00
Robin Bygrave 92069c0319 #764 - NPE on BeanDescriptorManager.processViewInvalidation(BeanDescriptorManager.java:385) 2016-07-08 15:34:43 +12:00
Robin Bygrave 630ad66ff1 #763 - Internal Code cleanup - remove redundant null checking etc 2016-07-08 15:01:39 +12:00
Robin Bygrave b732b390c7 [maven-release-plugin] prepare for next development iteration 2016-07-07 21:51:15 +12:00
Robin Bygrave 8c62fcdcb2 [maven-release-plugin] prepare release avaje-ebeanorm-7.17.1 2016-07-07 21:50:53 +12:00
Robin Bygrave e458f577fe No effective change - reduce logging for BeanDescriptorManager entity count message from INFO to DEBUG 2016-07-07 21:49:43 +12:00
Robin Bygrave 23434bab8c Bump pom to 7.17.1-SNAPSHOT 2016-07-07 21:45:40 +12:00
Robin Bygrave c47b5a1595 #762 - Change H2 Platform to IDENTITY (from SEQUENCE) with version 1.4.192 2016-07-07 21:43:15 +12:00
Robin Bygrave 411846347b #762 - Change H2 Platform to IDENTITY (from SEQUENCE) with version 1.4.192 2016-07-07 21:33:19 +12:00
Robin Bygrave 3722d19424 #761 - Change default for persistBatchOnCascade to be platform specific rather than NONE 2016-07-07 21:19:08 +12:00
Robin Bygrave 04a7310e5d [maven-release-plugin] prepare for next development iteration 2016-07-06 12:27:45 +12:00
Robin Bygrave 3490e90f03 [maven-release-plugin] prepare release avaje-ebeanorm-7.16.3 2016-07-06 12:27:26 +12:00
Robin Bygrave d89817a5c5 #760 - Change @Transactional(batchSize=100) ... to imply batch mode (remove need to also specify batch=PersistBatch.ALL) 2016-07-06 12:26:18 +12:00
Robin Bygrave db1ba5f20e #759 - Use default value of 100 for JDBC buffer fetchSize for findEach() / findEachWhile() - Add global defaults ServerConfig jdbcFetchSizeFindEach, jdbcFetchSizeFindList 2016-07-04 21:56:33 +12:00
Robin Bygrave 4f9a9a5094 No effective change - remove unused method 2016-06-30 14:45:06 +12:00
Robin Bygrave 1c6ac1289d #758 - DDL - @Index(unique=true) on field/property not creating unique index 2016-06-30 13:59:38 +12:00
Robin Bygrave b96be84106 Merge branch 'master' of github.com:ebean-orm/avaje-ebeanorm 2016-06-30 05:38:32 +12:00
Robin Bygrave 3c40293183 #757 - Reduce logging of Commit message of org.avaje.ebean.TXN from INFO to DEBUG 2016-06-30 05:38:16 +12:00
Rob BygraveandGitHub a9a6031986 Merge pull request #755 from MatthewMerrill/patch-1
Javadoc typo in SqlUpdate
2016-06-28 09:32:27 +12:00
Robin Bygrave b82085da42 [maven-release-plugin] prepare for next development iteration 2016-06-28 07:13:26 +12:00
Matthew MerrillandGitHub 2c34bc1636 Example code typo
Change "there where" to "there were" and added space between modify count and next word.
2016-06-27 09:07:45 -07:00
Robin Bygrave a954f8e9e1 EQL - initial 2016-06-01 17:27:35 +12:00
823 changed files with 21787 additions and 11165 deletions
+5 -5
View File
@@ -6,12 +6,12 @@ Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Web
## Maven cental links:
[Maven central - avaje-ebeanorm](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebeanorm%22%20AND%20a%3A%22avaje-ebeanorm%22 "maven central ebeanorm")
[Maven central - ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebean%22%20AND%20a%3A%22ebean%22 "maven central ebean")
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cavaje-ebeanorm "maven central ebeanorm")
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
## Current versions
* [![Maven Central : avaje-ebeanorm](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm) - avaje-ebeanorm
* [![Maven Central : avaje-ebeanorm-agent](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent) - avaje-ebeanorm-agent
* [![Maven Central : avaje-ebeanorm-agent](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer) - avaje-ebeanorm-mavenenhancer
* [![Maven Central : ebean](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean) - ebean
* [![Maven Central : ebean-agent](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent) - ebean-agent
* [![Maven Central : ebean-maven-plugin](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin) - ebean-maven-plugin
+24 -45
View File
@@ -3,41 +3,25 @@
<parent>
<groupId>org.avaje</groupId>
<artifactId>oss-parent</artifactId>
<artifactId>java8-parent</artifactId>
<version>1.1</version>
</parent>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>7.16.2</version>
<groupId>org.avaje.ebean</groupId>
<artifactId>ebean</artifactId>
<version>9.1.1</version>
<packaging>jar</packaging>
<name>avaje-ebeanorm</name>
<name>ebean</name>
<url>http://ebean-orm.github.io/</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>rbygrave</id>
<name>Rob Bygrave</name>
<email>robin.bygrave@gmail.com</email>
</developer>
</developers>
<scm>
<developerConnection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git</developerConnection>
<tag>avaje-ebeanorm-7.16.2</tag>
<developerConnection>scm:git:https://github.com/ebean-orm/ebean.git</developerConnection>
<tag>ebean-9.1.1</tag>
</scm>
<dependencies>
@@ -69,19 +53,19 @@
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-classpath-scanner-api</artifactId>
<version>2.1</version>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-classpath-scanner</artifactId>
<version>2.1.1</version>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-dbmigration</artifactId>
<version>1.1.1</version>
<version>1.2.1</version>
</dependency>
<dependency>
@@ -90,6 +74,12 @@
<version>[1.7.1,1.7.99)</version>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
<version>4.5.3</version>
</dependency>
<!-- Jackson core used internally by Ebean -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
@@ -166,9 +156,9 @@
</dependency>
<dependency>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-agent</artifactId>
<version>4.11.1</version>
<groupId>org.avaje.ebean</groupId>
<artifactId>ebean-agent</artifactId>
<version>8.1.1</version>
<scope>test</scope>
</dependency>
@@ -177,7 +167,7 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.189</version>
<version>1.4.192</version>
<scope>provided</scope>
</dependency>
@@ -231,26 +221,15 @@
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
<version>4.11.1</version>
<groupId>org.avaje.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>8.1.1</version>
<executions>
<execution>
<id>test</id>
<phase>process-test-classes</phase>
<configuration>
<classSource>target/test-classes</classSource>
<!--<packages>com.avaje.tests.**</packages>-->
<transformArgs>debug=1</transformArgs>
</configuration>
<goals>
@@ -298,7 +277,7 @@
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<doctitle>Ebean 7</doctitle>
<doctitle>Ebean 9</doctitle>
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
<source>1.8</source>
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
@@ -38,6 +38,11 @@ public interface BeanState {
*/
void setDisableLazyLoad(boolean disableLazyLoading);
/**
* Return true if the bean has lazy loading disabled.
*/
boolean isDisableLazyLoad();
/**
* Set the loaded state of the property given it's name.
*
@@ -115,4 +120,9 @@ public interface BeanState {
* for a fully loaded entity bean.
*/
void setLoaded();
/**
* Reset the bean putting it into NEW state such that a save() results in an insert.
*/
void resetForInsert();
}
@@ -30,7 +30,7 @@ final class DRawSqlColumnsParser {
private ColumnMapping parse() {
ArrayList<ColumnMapping.Column> columns = new ArrayList<ColumnMapping.Column>();
ArrayList<ColumnMapping.Column> columns = new ArrayList<>();
while (pos <= end) {
ColumnMapping.Column c = nextColumnInfo();
columns.add(c);
@@ -47,7 +47,7 @@ final class DRawSqlColumnsParser {
String[] split = colInfo.split("\\s(?=[^\\)]*(?:\\(|$))");
if (split.length > 1) {
ArrayList<String> tmp = new ArrayList<String>(split.length);
ArrayList<String> tmp = new ArrayList<>(split.length);
for (int i = 0; i < split.length; i++) {
if (!split[i].trim().isEmpty()) {
tmp.add(split[i].trim());
@@ -1,6 +1,7 @@
package com.avaje.ebean;
import com.avaje.ebean.RawSql.Sql;
import com.avaje.ebeaninternal.server.querydefn.SimpleTextParser;
/**
* Parses sql-select queries to try and determine the location where WHERE and
@@ -8,13 +9,13 @@ import com.avaje.ebean.RawSql.Sql;
*/
class DRawSqlParser {
public static final String $_AND_HAVING = "${andHaving}";
private static final String $_AND_HAVING = "${andHaving}";
public static final String $_HAVING = "${having}";
private static final String $_HAVING = "${having}";
public static final String $_AND_WHERE = "${andWhere}";
private static final String $_AND_WHERE = "${andWhere}";
public static final String $_WHERE = "${where}";
private static final String $_WHERE = "${where}";
private final SimpleTextParser textParser;
+66 -35
View File
@@ -132,13 +132,13 @@ public final class Ebean {
/**
* Cache for fast concurrent read access.
*/
private final ConcurrentHashMap<String, EbeanServer> concMap = new ConcurrentHashMap<String, EbeanServer>();
private final ConcurrentHashMap<String, EbeanServer> concMap = new ConcurrentHashMap<>();
/**
* Cache for synchronized read, creation and put. Protected by the monitor
* object.
*/
private final HashMap<String, EbeanServer> syncMap = new HashMap<String, EbeanServer>();
private final HashMap<String, EbeanServer> syncMap = new HashMap<>();
private final Object monitor = new Object();
@@ -499,6 +499,13 @@ public final class Ebean {
serverMgr.getDefaultServer().endTransaction();
}
/**
* Mark the current transaction as rollback only.
*/
public static void setRollbackOnly() {
serverMgr.getDefaultServer().currentTransaction().setRollbackOnly();
}
/**
* Return a map of the differences between two objects of the same type.
* <p>
@@ -945,6 +952,21 @@ public final class Ebean {
return serverMgr.getDefaultServer().createCsvReader(beanType);
}
/**
* Create a named query.
* <p>
* For RawSql the named query is expected to be in ebean.xml.
* </p>
*
* @param beanType The type of entity bean
* @param namedQuery The name of the query
* @param <T> The type of entity bean
* @return The query
*/
public static <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery) {
return serverMgr.getDefaultServer().createNamedQuery(beanType, namedQuery);
}
/**
* Create a query for a type of entity bean.
* <p>
@@ -960,39 +982,7 @@ public final class Ebean {
* {@link Query#findSet()} etc will execute against the same EbeanServer from
* which is was created.
* </p>
*
* <pre>{@code
* // Find order 2 additionally fetching the customer, details and details.product
* // name.
*
* Order order = Ebean.find(Order.class)
* .fetch("customer")
* .fetch("details")
* .fetch("detail.product", "name")
* .setId(2)
* .findUnique();
*
* // Find order 2 additionally fetching the customer, details and details.product
* // name.
* // Note: same query as above but using the query language
* // Note: using a named query would be preferred practice
*
* String oql = "find order fetch customer fetch details fetch details.product (name) where id = :orderId ";
*
* Query<Order> query = Ebean.find(Order.class);
* query.setQuery(oql);
* query.setParameter("orderId", 2);
*
* Order order = query.findUnique();
*
* // Using a named query
* Query<Order> query = Ebean.find(Order.class, "with.details");
* query.setParameter("orderId", 2);
*
* Order order = query.findUnique();
*
* }</pre>
*
*
* @param beanType
* the class of entity to be fetched
* @return A ORM Query object for this beanType
@@ -1002,6 +992,47 @@ public final class Ebean {
return serverMgr.getDefaultServer().createQuery(beanType);
}
/**
* Parse the Ebean query language statement returning the query which can then
* be modified (add expressions, change order by clause, change maxRows, change
* fetch and select paths etc).
*
* <h3>Example</h3>
*
* <pre>{@code
*
*
* // Find order additionally fetching the customer, details and details.product name.
*
* String eql = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
*
* Query<Order> query = Ebean.createQuery(Order.class, eql);
* query.setParameter("orderId", 2);
*
* Order order = query.findUnique();
*
* // This is the same as:
*
* Order order = Ebean.find(Order.class)
* .fetch("customer")
* .fetch("details")
* .fetch("detail.product", "name")
* .setId(2)
* .findUnique();
*
* }</pre>
*
* @param beanType The type of bean to fetch
* @param eql The Ebean query
* @param <T> The type of the entity bean
*
* @return The query with expressions defined as per the parsed query statement
*/
public static <T> Query<T> createQuery(Class<T> beanType, String eql) {
return serverMgr.getDefaultServer().createQuery(beanType, eql);
}
/**
* Create a query for a type of entity bean.
* <p>
+115 -12
View File
@@ -167,8 +167,9 @@ public interface EbeanServer {
/**
* Create a new instance of T that is an EntityBean.
* <p>
* Generally not expected to be useful (now dynamic subclassing support was removed in
* favour of always using enhancement).
* Useful if you use BeanPostConstructListeners or &#64;PostConstruct Annotations.
* In this case you should not use "new Bean...()". Making all bean construtors protected
* could be a good idea here.
* </p>
*/
<T> T createEntityBean(Class<T> type);
@@ -199,6 +200,19 @@ public interface EbeanServer {
*/
<T> UpdateQuery<T> update(Class<T> beanType);
/**
* Create a named query.
* <p>
* For RawSql the named query is expected to be in ebean.xml.
* </p>
*
* @param beanType The type of entity bean
* @param namedQuery The name of the query
* @param <T> The type of entity bean
* @return The query
*/
<T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery);
/**
* Create a query for an entity bean and synonym for {@link #find(Class)}.
*
@@ -206,6 +220,43 @@ public interface EbeanServer {
*/
<T> Query<T> createQuery(Class<T> beanType);
/**
* Parse the Ebean query language statement returning the query which can then
* be modified (add expressions, change order by clause, change maxRows, change
* fetch and select paths etc).
*
* <h3>Example</h3>
*
* <pre>{@code
*
* // Find order additionally fetching the customer, details and details.product name.
*
* String eql = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
*
* Query<Order> query = Ebean.createQuery(Order.class, eql);
* query.setParameter("orderId", 2);
*
* Order order = query.findUnique();
*
* // This is the same as:
*
* Order order = Ebean.find(Order.class)
* .fetch("customer")
* .fetch("details")
* .fetch("detail.product", "name")
* .setId(2)
* .findUnique();
*
* }</pre>
*
* @param beanType The type of bean to fetch
* @param eql The Ebean query
* @param <T> The type of the entity bean
*
* @return The query with expressions defined as per the parsed query statement
*/
<T> Query<T> createQuery(Class<T> beanType, String eql);
/**
* Create a query for a type of entity bean.
* <p>
@@ -689,20 +740,38 @@ public interface EbeanServer {
<T> T getReference(Class<T> beanType, Object id);
/**
* Return the number of 'top level' or 'root' entities this query should
* return.
* Return the number of 'top level' or 'root' entities this query should return.
*
* @see Query#findRowCount()
* @see com.avaje.ebean.Query#findFutureRowCount()
* @see Query#findCount()
* @see Query#findFutureCount()
*/
<T> int findRowCount(Query<T> query, Transaction transaction);
<T> int findCount(Query<T> query, Transaction transaction);
/**
* Return the Id values of the query as a List.
*
* @see com.avaje.ebean.Query#findIds()
* @see Query#findIds()
*/
<T> List<Object> findIds(Query<T> query, Transaction transaction);
<A, T> List<A> findIds(Query<T> query, Transaction transaction);
/**
* Return a QueryIterator for the query.
* <p>
* Generally using {@link #findEach(Query, QueryEachConsumer, Transaction)} or
* {@link #findEachWhile(Query, QueryEachWhileConsumer, Transaction)} is preferred
* to findIterate(). The reason is that those methods automatically take care of
* closing the queryIterator (and the underlying jdbc statement and resultSet).
* </p>
* <p>
* This is similar to findEach in that not all the result beans need to be held
* in memory at the same time and as such is good for processing large queries.
* </p>
*
* @see Query#findIterate()
* @see Query#findEach(QueryEachConsumer)
* @see Query#findEachWhile(QueryEachWhileConsumer)
*/
<T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction);
/**
* Execute the query visiting the each bean one at a time.
@@ -816,9 +885,9 @@ public interface EbeanServer {
* @param query the query to execute the row count on
* @param transaction the transaction (can be null).
* @return a Future object for the row count query
* @see com.avaje.ebean.Query#findFutureRowCount()
* @see com.avaje.ebean.Query#findFutureCount()
*/
<T> FutureRowCount<T> findFutureRowCount(Query<T> query, Transaction transaction);
<T> FutureRowCount<T> findFutureCount(Query<T> query, Transaction transaction);
/**
* Execute find Id's query in a background thread.
@@ -921,7 +990,41 @@ public interface EbeanServer {
* @return the map of fetched beans.
* @see Query#findMap()
*/
<T> Map<?, T> findMap(Query<T> query, Transaction transaction);
<K, T> Map<K, T> findMap(Query<T> query, Transaction transaction);
/**
* Execute the query returning a list of values for a single property.
*
* <h3>Example 1:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .findSingleAttributeList();
*
* }</pre>
*
* <h3>Example 2:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
* .orderBy().asc("name")
* .setMaxRows(100)
* .findSingleAttributeList();
*
* }</pre>
*
* @return the list of values for the selected property
*
* @see Query#findSingleAttributeList()
*/
<A, T> List<A> findSingleAttributeList(Query<T> query, Transaction transaction);
/**
* Execute the query returning at most one entity bean or null (if no matching
@@ -135,6 +135,11 @@ public interface ExpressionFactory {
*/
Expression ieq(String propertyName, String value);
/**
* Case Insensitive Equal To that allows for named parameter use.
*/
Expression ieqObject(String propertyName, Object value);
/**
* Between - property between the two given values.
*/
@@ -192,6 +197,11 @@ public interface ExpressionFactory {
*/
ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType);
/**
* Like with support for named parameters.
*/
Expression like(String propertyName, Object value, boolean caseInsensitive, LikeType likeType);
/**
* Like - property like value where the value contains the SQL wild card
* characters % (percentage) and _ (underscore).
@@ -31,7 +31,7 @@ import java.util.Set;
* more methods than you would initially expect (the ones duplicated from
* Query).
* </p>
*
*
* @see Query#where()
*/
public interface ExpressionList<T> {
@@ -83,14 +83,14 @@ public interface ExpressionList<T> {
/**
* Add an orderBy clause to the query.
*
*
* @see Query#orderBy(String)
*/
Query<T> orderBy(String orderBy);
/**
* Add an orderBy clause to the query.
*
*
* @see Query#orderBy(String)
*/
Query<T> setOrderBy(String orderBy);
@@ -116,12 +116,6 @@ public interface ExpressionList<T> {
*/
Query<T> asDraft();
/**
* Deprecated in favour of setIncludeSoftDeletes().
*/
@Deprecated
Query<T> includeSoftDeletes();
/**
* Execute the query including soft deleted rows.
*/
@@ -147,6 +141,13 @@ public interface ExpressionList<T> {
*/
int update();
/**
* Execute the query iterating over the results.
*
* @see Query#findIterate()
*/
QueryIterator<T> findIterate();
/**
* Execute the query process the beans one at a time.
*
@@ -164,17 +165,17 @@ public interface ExpressionList<T> {
/**
* Execute the query returning a list.
*
*
* @see Query#findList()
*/
List<T> findList();
/**
* Execute the query returning the list of Id's.
*
*
* @see Query#findIds()
*/
List<Object> findIds();
<A> List<A> findIds();
/**
* Return the count of entities this query should return.
@@ -182,26 +183,53 @@ public interface ExpressionList<T> {
* This is the number of 'top level' or 'root level' entities.
* </p>
*/
int findRowCount();
int findCount();
/**
* Execute the query returning a set.
*
*
* @see Query#findSet()
*/
Set<T> findSet();
/**
* Execute the query returning a map.
*
*
* @see Query#findMap()
*/
Map<?, T> findMap();
<K> Map<K, T> findMap();
/**
* Return a typed map specifying the key property and type.
* Execute the query returning a list of values for a single property.
*
* <h3>Example 1:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .findSingleAttributeList();
*
* }</pre>
*
* <h3>Example 2:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
* .orderBy().asc("name")
* .setMaxRows(100)
* .findSingleAttributeList();
*
* }</pre>
*
* @return the list of values for the selected property
*/
<K> Map<K, T> findMap(String keyProperty, Class<K> keyType);
<A> List<A> findSingleAttributeList();
/**
* Execute the query returning a single bean or null (if no matching
@@ -225,10 +253,10 @@ public interface ExpressionList<T> {
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
*
* @return a Future object for the row count query
*/
FutureRowCount<T> findFutureRowCount();
FutureRowCount<T> findFutureCount();
/**
* Execute find Id's query in a background thread.
@@ -237,7 +265,7 @@ public interface ExpressionList<T> {
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
*
* @return a Future object for the list of Id's
*/
FutureIds<T> findFutureIds();
@@ -249,7 +277,7 @@ public interface ExpressionList<T> {
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
*
* @return a Future object for the list result of the query
*/
FutureList<T> findFutureList();
@@ -312,7 +340,7 @@ public interface ExpressionList<T> {
/**
* Specify specific properties to fetch on the main/root bean (aka partial
* object).
*
*
* @see Query#select(String)
*/
Query<T> select(String properties);
@@ -337,28 +365,28 @@ public interface ExpressionList<T> {
/**
* Set the first row to fetch.
*
*
* @see Query#setFirstRow(int)
*/
Query<T> setFirstRow(int firstRow);
/**
* Set the maximum number of rows to fetch.
*
*
* @see Query#setMaxRows(int)
*/
Query<T> setMaxRows(int maxRows);
/**
* Set the name of the property which values become the key of a map.
*
*
* @see Query#setMapKey(String)
*/
Query<T> setMapKey(String mapKey);
/**
* Set to true to use the query for executing this query.
*
*
* @see Query#setUseCache(boolean)
*/
Query<T> setUseCache(boolean useCache);
@@ -619,7 +647,7 @@ public interface ExpressionList<T> {
* To get control over the options you can create an ExampleExpression and set
* those options such as case insensitive etc.
* </p>
*
*
* <pre>{@code
*
* // create an example bean and set the properties
@@ -627,26 +655,26 @@ public interface ExpressionList<T> {
* Customer example = new Customer();
* example.setName("Rob%");
* example.setNotes("%something%");
*
*
* List&lt;Customer&gt; list = Ebean.find(Customer.class).where()
* // pass the bean into the where() clause
* .exampleLike(example)
* // you can add other expressions to the same query
* .gt("id", 2).findList();
*
*
* }</pre>
*
*
* Similarly you can create an ExampleExpression
*
*
* <pre>{@code
*
* Customer example = new Customer();
* example.setName("Rob%");
* example.setNotes("%something%");
*
*
* // create a ExampleExpression with more control
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO).includeZeros();
*
*
* List<Customer> list = Ebean.find(Customer.class).where().add(qbe).findList();
*
* }</pre>
@@ -748,7 +776,7 @@ public interface ExpressionList<T> {
* Exists expression
*/
ExpressionList<T> exists(Query<?> subQuery);
/**
* Not exists expression
*/
@@ -775,7 +803,7 @@ public interface ExpressionList<T> {
* Expression where all the property names in the map are equal to the
* corresponding value.
* </p>
*
*
* @param propertyMap
* a map keyed by property names.
*/
@@ -29,8 +29,7 @@ import java.io.Serializable;
* // Find Orders join details using a single SQL query
* }</pre>
* <p>
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL
* queries
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL queries
* </p>
*
* <pre>{@code
@@ -117,7 +116,7 @@ import java.io.Serializable;
* <pre>{@code
* List<Order> list = Ebean.find(Order.class)
* .fetch("customer","name", new FetchConfig().lazy(5))
* .fetch("customer.contacts",&quotcontactName, phone, email&quot)
* .fetch("customer.contacts","contactName, phone, email")
* .fetch("customer.shippingAddress")
* .where().eq("status",Order.Status.NEW)
* .findList();
@@ -125,12 +124,7 @@ import java.io.Serializable;
* // query 1) find order where status = Order.Status.NEW
* //
* // .. if lazy loading of customers is invoked
* // .. use a batch size of 5 to load the customers
*
* find customer (name)
* fetch customer.contacts (contactName, phone, email)
* fetch customer.shippingAddress (*)
* where id in (?,?,?,?,?)
* // .. use a batch size of 5 to load the customers
*
* }</pre>
*
@@ -9,8 +9,6 @@ import java.util.concurrent.Future;
* It extends the java.util.concurrent.Future with the ability to get the Id's
* while the query is still executing in the background.
* </p>
*
* @author rbygrave
*/
public interface FutureIds<T> extends Future<List<Object>> {
@@ -19,16 +17,4 @@ public interface FutureIds<T> extends Future<List<Object>> {
*/
Query<T> getQuery();
/**
* Return the list of Id's which could be partially populated.
* <p>
* That is the query getting the id's could still be running and adding id's
* to this list.
* </p>
* <p>
* To get the list of Id's ensuring the query has finished use the
* {@link Future#get()} method instead of this one.
* </p>
*/
List<Object> getPartialIds();
}
@@ -9,6 +9,7 @@ import java.util.concurrent.Future;
* It extends the java.util.concurrent.Future.
* </p>
*
* @param <T> the BeanType
* @author rbygrave
*/
public interface FutureRowCount<T> extends Future<Integer> {
+21 -11
View File
@@ -59,11 +59,11 @@ package com.avaje.ebean;
* .and()
* .startsWith("name", "r")
* .eq("anniversary", onAfter)
* .endJunction()
* .endAnd()
* .and()
* .eq("status", Customer.Status.ACTIVE)
* .gt("id", 0)
* .endJunction()
* .endAnd()
* .order().asc("name");
*
* q.findList();
@@ -84,39 +84,41 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
/**
* AND group.
*/
AND(" and ", ""),
AND(" and ", "", false),
/**
* OR group.
*/
OR(" or ", ""),
OR(" or ", "", false),
/**
* NOT group.
*/
NOT(" and ", "not "),
NOT(" and ", "not ", false),
/**
* Text search AND group.
*/
MUST("must", ""),
MUST("must", "", true),
/**
* Text search NOT group.
*/
MUST_NOT("must_not", ""),
MUST_NOT("must_not", "", true),
/**
* Text search OR group.
*/
SHOULD("should", "");
SHOULD("should", "", true);
String prefix;
String literal;
private String prefix;
private String literal;
private boolean text;
Type(String literal, String prefix) {
Type(String literal, String prefix, boolean text) {
this.literal = literal;
this.prefix = prefix;
this.text = text;
}
/**
@@ -132,6 +134,14 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
public String prefix() {
return prefix;
}
/**
* Return true if this is a text type.
*/
public boolean isText() {
return text;
}
}
}
+25 -18
View File
@@ -495,7 +495,7 @@ public abstract class Model {
/**
* Return typically a different EbeanServer to the default.
* <p>
* This is equivilent to {@link Ebean#getServer(String)}
* This is equivalent to {@link Ebean#getServer(String)}
*
* @param server
* The name of the EbeanServer. If this is null then the default EbeanServer is
@@ -512,7 +512,7 @@ public abstract class Model {
* Create and return a new Finder for a different server.
*/
public Finder<I, T> on(String server) {
return new Finder<I, T>(server, type);
return new Finder<>(server, type);
}
/**
@@ -598,7 +598,7 @@ public abstract class Model {
* <p>
* Equivalent to {@link Query#findIds()}
*/
public List<Object> findIds() {
public <A> List<A> findIds() {
return query().findIds();
}
@@ -660,36 +660,43 @@ public abstract class Model {
* <p>
* Equivalent to {@link Query#findMap()}
*/
public Map<?, T> findMap() {
public <K> Map<K, T> findMap() {
return query().findMap();
}
/**
* Executes the query and returns the results as a map of the objects specifying the map key
* property.
* <p>
* Equivalent to {@link Query#findMap(String, Class)}
*/
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
return query().findMap(keyProperty, keyType);
}
/**
* Executes a find row count query in a background thread.
* <p>
* Equivalent to {@link Query#findFutureRowCount()}
* Equivalent to {@link Query#findFutureCount()}
*/
public FutureRowCount<T> findFutureCount() {
return query().findFutureCount();
}
/**
* Deprecated in favor of findFutureCount().
* <p>
* Equivalent to {@link Query#findFutureCount()}
*/
public FutureRowCount<T> findFutureRowCount() {
return query().findFutureRowCount();
return query().findFutureCount();
}
/**
* Returns the total number of entities for this type. *
* <p>
* Equivalent to {@link Query#findRowCount()}
* Equivalent to {@link Query#findCount()}
*/
public int findCount() {
return query().findCount();
}
/**
* Deprecated in favor of findCount().
* @deprecated
*/
public int findRowCount() {
return query().findRowCount();
return query().findCount();
}
/**
+15 -7
View File
@@ -28,7 +28,7 @@ public final class OrderBy<T> implements Serializable {
* Create an empty OrderBy with no associated query.
*/
public OrderBy() {
this.list = new ArrayList<Property>(3);
this.list = new ArrayList<>(3);
}
private OrderBy(List<Property> list) {
@@ -52,7 +52,7 @@ public final class OrderBy<T> implements Serializable {
*/
public OrderBy(Query<T> query, String orderByClause) {
this.query = query;
this.list = new ArrayList<Property>(3);
this.list = new ArrayList<>(3);
parse(orderByClause);
}
@@ -100,11 +100,11 @@ public final class OrderBy<T> implements Serializable {
* Return a copy of this OrderBy with the path trimmed.
*/
public OrderBy<T> copyWithTrim(String path) {
List<Property> newList = new ArrayList<Property>(list.size());
List<Property> newList = new ArrayList<>(list.size());
for (int i = 0; i < list.size(); i++) {
newList.add(list.get(i).copyWithTrim(path));
}
return new OrderBy<T>(newList);
return new OrderBy<>(newList);
}
/**
@@ -141,13 +141,20 @@ public final class OrderBy<T> implements Serializable {
*/
public OrderBy<T> copy() {
OrderBy<T> copy = new OrderBy<T>();
OrderBy<T> copy = new OrderBy<>();
for (int i = 0; i < list.size(); i++) {
copy.add(list.get(i).copy());
}
return copy;
}
/**
* Add to the order by by parsing a raw expression.
*/
public void add(String rawExpression) {
parse(rawExpression);
}
/**
* Add a property to the order by.
*/
@@ -206,8 +213,9 @@ public final class OrderBy<T> implements Serializable {
* order by clause and replace.
* </p>
*/
public void clear() {
public OrderBy<T> clear() {
list.clear();
return this;
}
/**
@@ -362,7 +370,7 @@ public final class OrderBy<T> implements Serializable {
return null;
}
ArrayList<String> wordList = new ArrayList<String>(pairs.length);
ArrayList<String> wordList = new ArrayList<>(pairs.length);
for (int i = 0; i < pairs.length; i++) {
if (!isEmptyString(pairs[i])) {
wordList.add(pairs[i]);
+12 -28
View File
@@ -8,7 +8,7 @@ import java.util.concurrent.Future;
* <p>
* The benefit of using PagedList over just using the normal Query with
* {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} is that it additionally wraps
* functionality that can call {@link Query#findFutureRowCount()} to determine total row count,
* functionality that can call {@link Query#findFutureCount()} to determine total row count,
* total page count etc.
* </p>
* <p>
@@ -44,30 +44,6 @@ import java.util.concurrent.Future;
*
* }</pre>
*
* <h4>Example: typical use including total row count</h4>
* <pre>{@code
*
* // We want to find the first 100 new orders
* // ... 0 means first page
* // ... page size is 100
*
* PagedList<Order> pagedList
* = ebeanServer.find(Order.class)
* .where().eq("status", Order.Status.NEW)
* .order().asc("id")
* .findPagedList(0, 100);
*
* // Optional: initiate the loading of the total
* // row count in a background thread
* pagedList.loadRowCount();
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* // get the total row count (from the future)
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*
* <h4>Example: No total row count required</h4>
* <pre>{@code
@@ -110,7 +86,7 @@ public interface PagedList<T> {
* wrapped in the unchecked PersistenceException (which might be preferrable).
* </p>
*/
void loadRowCount();
void loadCount();
/**
* Return the Future row count. You might get this if you wish to cancel the total row count query
@@ -138,7 +114,7 @@ public interface PagedList<T> {
*
* }</pre>
*/
Future<Integer> getFutureRowCount();
Future<Integer> getFutureCount();
/**
* Return the list of entities for this page.
@@ -170,7 +146,7 @@ public interface PagedList<T> {
*
* }</pre>
*/
int getTotalRowCount();
int getTotalCount();
/**
* Return the total number of pages based on the page size and total row count.
@@ -186,6 +162,14 @@ public interface PagedList<T> {
*/
int getPageSize();
/**
* Return the index position of this page (Zero based).
* <p>
* This is a calculated value based on firstRow/maxRows.
* </p>
*/
int getPageIndex();
/**
* Return true if there is a next page.
* <p>
@@ -7,6 +7,8 @@ import javax.persistence.PersistenceException;
*/
public class PersistenceIOException extends PersistenceException {
private static final long serialVersionUID = -7630050437148176148L;
public PersistenceIOException(String msg, Exception cause) {
super(msg, cause);
}
+289 -229
View File
@@ -13,10 +13,10 @@ import java.util.Set;
* <p>
* Example: Create the query using the API.
* </p>
*
* <p>
* <pre>{@code
*
* List<Order> orderList =
* List<Order> orderList =
* ebeanServer.find(Order.class)
* .fetch("customer")
* .fetch("details")
@@ -26,46 +26,40 @@ import java.util.Set;
* .orderBy("customer.id, id desc")
* .setMaxRows(50)
* .findList();
*
*
* ...
* }</pre>
*
* <p>
* Example: The same query using the query language
* </p>
*
* <pre>{@code
*
* String oql =
* " find order "
* String oql =
* +" fetch customer "
* +" fetch details "
* +" where customer.name like :custName and orderDate > :minOrderDate "
* +" order by customer.id, id desc "
* +" limit 50 ";
*
*
* Query<Order> query = ebeanServer.createQuery(Order.class, oql);
* query.setParameter("custName", "Rob%");
* query.setParameter("minOrderDate", lastWeek);
*
*
* List<Order> orderList = query.findList();
* ...
* }</pre>
*
* <p>
* Example: Using a named query called "with.cust.and.details"
* </p>
*
* <pre>{@code
*
* Query<Order> query = ebeanServer.createNamedQuery(Order.class,"with.cust.and.details");
* query.setParameter("custName", "Rob%");
* query.setParameter("minOrderDate", lastWeek);
*
*
* List<Order> orderList = query.findList();
* ...
* }</pre>
*
* <h3>AutoTune</h3>
* <p>
* Ebean has built in support for "AutoTune". This is a mechanism where a query
@@ -82,7 +76,6 @@ import java.util.Set;
* to a remote client or where there is some requirement for "Read Consistency"
* guarantees.
* </p>
*
* <h3>Query Language</h3>
* <p>
* <b>Partial Objects</b>
@@ -101,36 +94,25 @@ import java.util.Set;
* concurrency checking will occur but only include the fetched properties.
* Refer to "ALL Properties/Columns" mode of Optimistic Concurrency checking.
* </p>
*
* <pre>{@code
* [ find {bean type} [ ( * | {fetch properties} ) ] ]
* [ fetch {associated bean} [ ( * | {fetch properties} ) ] ]
* [ select [ ( * | {fetch properties} ) ] ]
* [ fetch {path} [ ( * | {fetch properties} ) ] ]
* [ where {predicates} ]
* [ order by {order by properties} ]
* [ limit {max rows} [ offset {first row} ] ]
* }</pre>
*
* <p>
* <b>FIND</b> <b>{bean type}</b> [ ( <i>*</i> | <i>{fetch properties}</i> ) ]
* <b>SELECT</b> [ ( <i>*</i> | <i>{fetch properties}</i> ) ]
* </p>
* <p>
* With the find you specify the type of beans to fetch. You can optionally
* specify a list of properties to fetch. If you do not specify a list of
* properties ALL the properties for those beans are fetched.
* With the select you can specify a list of properties to fetch.
* </p>
* <p>
* In object graph terms the <em>find</em> clause specifies the type of bean at
* the root level and the <em>fetch</em> clauses specify the paths of the object
* graph to populate.
* </p>
* <p>
* <b>FETCH</b> <b>{associated property}</b> [ ( <i>*</i> | <i>{fetch
* properties}</i> ) ]
* <b>FETCH</b> <b>{path}</b> [ ( <i>*</i> | <i>{fetch properties}</i> ) ]
* </p>
* <p>
* With the fetch you specify the associated property to fetch and populate. The
* associated property is a OneToOnem, ManyToOne, OneToMany or ManyToMany
* property. When the query is executed Ebean will fetch the associated data.
* path is a OneToOne, ManyToOne, OneToMany or ManyToMany property.
* </p>
* <p>
* For fetch of a path we can optionally specify a list of properties to fetch.
@@ -161,52 +143,34 @@ import java.util.Set;
* </p>
* <h4>Examples of Ebean's Query Language</h4>
* <p>
* Find orders fetching all its properties
* </p>
*
* <pre>{@code
* find order
* }</pre>
*
* <p>
* Find orders fetching all its properties
* </p>
*
* <pre>{@code
* find order (*)
* }</pre>
*
* <p>
* Find orders fetching its id, shipDate and status properties. Note that the id
* property is always fetched even if it is not included in the list of fetch
* properties.
* </p>
*
* <pre>{@code
* find order (shipDate, status)
*
* select (shipDate, status)
*
* }</pre>
*
* <p>
* Find orders with a named bind variable (that will need to be bound via
* {@link Query#setParameter(String, Object)}).
* </p>
*
* <pre>{@code
* find order
*
* where customer.name like :custLike
*
* }</pre>
*
* <p>
* Find orders and also fetch the customer with a named bind parameter. This
* will fetch and populate both the order and customer objects.
* </p>
*
* <pre>{@code
* find order
*
* fetch customer
* where customer.id = :custId
*
* }</pre>
*
* <p>
* Find orders and also fetch the customer, customer shippingAddress, order
* details and related product. Note that customer and product objects will be
@@ -215,63 +179,16 @@ import java.util.Set;
* objects (associated with each order detail) will have their id, sku and name
* populated.
* </p>
*
* <pre>{@code
* find order
*
* fetch customer (name)
* fetch customer.shippingAddress
* fetch details
* fetch details.product (sku, name)
*
* }</pre>
*
* <h3>Early parsing of the Query</h3>
* <p>
* When you get a Query object from a named query, the query statement has
* already been parsed. You can then add to that query (add fetch paths, add to
* the where clause) or override some of its settings (override the order by
* clause, first rows, max rows).
* </p>
* <p>
* The thought is that you can use named queries as a 'starting point' and then
* modify the query to suit specific needs.
* </p>
* <h3>Building the Where clause</h3>
* <p>
* You can add to the where clause using Expression objects or a simple String.
* Note that the ExpressionList has methods to add most of the common
* expressions that you will need.
* <ul>
* <li>where(String addToWhereClause)</li>
* <li>where().add(Expression expression)</li>
* <li>where().eq(propertyName, value).like(propertyName , value)...</li>
* </ul>
* </p>
* <p>
* The full WHERE clause is constructed by appending together
* <li>original query where clause (Named query or query.setQuery(String oql))</li>
* <li>clauses added via query.where(String addToWhereClause)</li>
* <li>clauses added by Expression objects</li>
* </p>
* <p>
* The above is the order that these are clauses are appended to give the full
* WHERE clause.
* </p>
* <h3>Design Goal</h3>
* <p>
* This query language is NOT designed to be a replacement for SQL. It is
* designed to be a simple way to describe the "Object Graph" you want Ebean to
* build for you. Each find/fetch represents a node in that "Object Graph" which
* makes it easy to define for each node which properties you want to fetch.
* </p>
* <p>
* Once you hit the limits of this language such as wanting aggregate functions
* (sum, average, min etc) or recursive queries etc you use SQL. Ebean's goal is
* to make it as easy as possible to use your own SQL to populate entity beans.
* Refer to {@link RawSql} .
* </p>
*
* @param <T>
* the type of Entity bean this query will fetch.
*
* @param <T> the type of Entity bean this query will fetch.
*/
public interface Query<T> {
@@ -289,7 +206,7 @@ public interface Query<T> {
* Perform an 'As of' query using history tables to return the object graph
* as of a time in the past.
* <p>
* To perform this query the DB must have underlying history tables.
* To perform this query the DB must have underlying history tables.
* </p>
*
* @param asOf the date time in the past at which you want to view the data
@@ -325,7 +242,7 @@ public interface Query<T> {
* Specify the PersistenceContextScope to use for this query.
* <p/>
* When this is not set the 'default' configured on {@link com.avaje.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)}
* is used - this value defaults to {@link com.avaje.ebean.PersistenceContextScope#TRANSACTION}.
* is used - this value defaults to {@link PersistenceContextScope#TRANSACTION}.
* <p/>
* Note that the same persistence Context is used for subsequent lazy loading and query join queries.
* <p/>
@@ -392,14 +309,15 @@ public interface Query<T> {
Query<T> setDisableReadAuditing();
/**
* Explicitly set a comma delimited list of the properties to fetch on the
* 'main' root level entity bean (aka partial object). Note that '*' means all
* properties.
* Specify the properties to fetch on the root level entity bean in comma delimited format.
* <p>
* You use {@link #fetch(String, String)} to specify specific properties to fetch
* The Id property is automatically included in the properties to fetch unless setDistinct(true)
* is set on the query.
* </p>
* <p>
* Use {@link #fetch(String, String)} to specify specific properties to fetch
* on other non-root level paths of the object graph.
* </p>
*
* <pre>{@code
*
* List<Customer> customers =
@@ -412,42 +330,33 @@ public interface Query<T> {
*
* }</pre>
*
* @param fetchProperties
* the properties to fetch for this bean (* = all properties).
* @param fetchProperties the properties to fetch for this bean (* = all properties).
*/
Query<T> select(String fetchProperties);
/**
* Specify a path to <em>fetch</em> with its specific properties to include
* (aka partial object).
* Specify a path to fetch eagerly including specific properties.
* <p>
* When you specify a join this means that property (associated bean(s)) will
* be fetched and populated. If you specify "*" then all the properties of the
* associated bean will be fetched and populated. You can specify a comma
* delimited list of the properties of that associated bean which means that
* only those properties are fetched and populated resulting in a
* "Partial Object" - a bean that only has some of its properties populated.
* Ebean will endeavour to fetch this path using a SQL join. If Ebean determines that it can
* not use a SQL join (due to maxRows or because it would result in a cartesian product) Ebean
* will automatically convert this fetch query into a "query join" - i.e. use fetchQuery().
* </p>
*
* <pre>{@code
*
* // query orders...
* List<Order> orders =
* ebeanserver.find(Order.class)
* ebeanServer.find(Order.class)
* // fetch the customer...
* // ... getting the customers name and phone number
* .fetch("customer", "name, phoneNumber")
*
*
* // ... also fetch the customers billing address (* = all properties)
* .fetch("customer.billingAddress", "*")
* .findList();
* }</pre>
*
* <p>
* If columns is null or "*" then all columns/properties for that path are
* fetched.
* If columns is null or "*" then all columns/properties for that path are fetched.
* </p>
*
* <pre>{@code
*
* // fetch customers (their id, name and status)
@@ -458,19 +367,66 @@ public interface Query<T> {
* .findList();
*
* }</pre>
*
* @param path
* the path of an associated (1-1,1-M,M-1,M-M) bean.
* @param fetchProperties
* properties of the associated bean that you want to include in the
* fetch (* means all properties, null also means all properties).
*
* @param path the property path we wish to fetch eagerly.
* @param fetchProperties properties of the associated bean that you want to include in the
* fetch (* means all properties, null also means all properties).
*/
Query<T> fetch(String path, String fetchProperties);
/**
* Fetch the path and properties using a "query join" (separate SQL query).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, fetchProperties, new FetchConfig().query())
*
* }</pre>
* <p>
* This would be used instead of a fetch() when we use a separate SQL query to fetch this
* part of the object graph rather than a SQL join.
* </p>
* <p>
* We might typically get a performance benefit when the path to fetch is a OneToMany
* or ManyToMany, the 'width' of the 'root bean' is wide and the cardinality of the many
* is high.
* </p>
*
* @param path the property path we wish to fetch eagerly.
* @param fetchProperties properties of the associated bean that you want to include in the
* fetch (* means all properties, null also means all properties).
*/
Query<T> fetchQuery(String path, String fetchProperties);
/**
* Fetch the path and properties lazily (via batch lazy loading).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, fetchProperties, new FetchConfig().lazy())
*
* }</pre>
* <p>
* The reason for using fetchLazy() is to either:
* </p>
* <ul>
* <li>Control/tune what is fetched as part of lazy loading</li>
* <li>Make use of the L2 cache, build this part of the graph from L2 cache</li>
* </ul>
*
* @param path the property path we wish to fetch lazily.
* @param fetchProperties properties of the associated bean that you want to include in the
* fetch (* means all properties, null also means all properties).
*/
Query<T> fetchLazy(String path, String fetchProperties);
/**
* Additionally specify a FetchConfig to use a separate query or lazy loading
* to load this path.
*
* <pre>{@code
*
* // fetch customers (their id, name and status)
@@ -481,13 +437,17 @@ public interface Query<T> {
* .findList();
*
* }</pre>
*
* @param path the property path we wish to fetch eagerly.
*/
Query<T> fetch(String assocProperty, String fetchProperties, FetchConfig fetchConfig);
Query<T> fetch(String path, String fetchProperties, FetchConfig fetchConfig);
/**
* Specify a path to load including all its properties.
* Specify a path to fetch eagerly including all its properties.
* <p>
* The same as {@link #fetch(String, String)} with the fetchProperties as "*".
* Ebean will endeavour to fetch this path using a SQL join. If Ebean determines that it can
* not use a SQL join (due to maxRows or because it would result in a cartesian product) Ebean
* will automatically convert this fetch query into a "query join" - i.e. use fetchQuery().
* </p>
* <pre>{@code
*
@@ -500,16 +460,59 @@ public interface Query<T> {
*
* }</pre>
*
* @param path
* the property of an associated (1-1,1-M,M-1,M-M) bean.
* @param path the property path we wish to fetch eagerly.
*/
Query<T> fetch(String path);
/**
* Fetch the path eagerly using a "query join" (separate SQL query).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, new FetchConfig().query())
*
* }</pre>
* <p>
* This would be used instead of a fetch() when we use a separate SQL query to fetch this
* part of the object graph rather than a SQL join.
* </p>
* <p>
* We might typically get a performance benefit when the path to fetch is a OneToMany
* or ManyToMany, the 'width' of the 'root bean' is wide and the cardinality of the many
* is high.
* </p>
*
* @param path the property path we wish to fetch eagerly
*/
Query<T> fetchQuery(String path);
/**
* Fetch the path lazily (via batch lazy loading).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, new FetchConfig().lazy())
*
* }</pre>
* <p>
* The reason for using fetchLazy() is to either:
* </p>
* <ul>
* <li>Control/tune what is fetched as part of lazy loading</li>
* <li>Make use of the L2 cache, build this part of the graph from L2 cache</li>
* </ul>
*
* @param path the property path we wish to fetch lazily.
*/
Query<T> fetchLazy(String path);
/**
* Additionally specify a JoinConfig to specify a "query join" and or define
* the lazy loading query.
*
*
* <pre>{@code
*
* // fetch customers (their id, name and status)
@@ -536,10 +539,50 @@ public interface Query<T> {
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
*
*
* @see EbeanServer#findIds(Query, Transaction)
*/
List<Object> findIds();
<A> List<A> findIds();
/**
* Execute the query iterating over the results.
* <p>
* Note that findIterate (and findEach and findEachWhile) uses a "per graph"
* persistence context scope and adjusts jdbc fetch buffer size for large
* queries. As such it is better to use findList for small queries.
* </p>
* <p>
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
* when you have finished iterating the results (typically in a finally block).
* </p>
* <p>
* findEach() and findEachWhile() are preferred to findIterate() as they ensure
* the jdbc statement and resultSet are closed at the end of the iteration.
* </p>
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
* <pre>{@code
*
* Query<Customer> query =
* ebeanServer.find(Customer.class)
* .where().eq("status", Status.NEW)
* .order().asc("id");
*
* QueryIterator<Customer> it = query.findIterate();
* try {
* while (it.hasNext()) {
* Customer customer = it.next();
* // do something with customer ...
* }
* } finally {
* // close the underlying resources
* it.close();
* }
*
* }</pre>
*/
QueryIterator<T> findIterate();
/**
* Execute the query processing the beans one at a time.
@@ -549,6 +592,11 @@ public interface Query<T> {
* (unlike #findList #findSet etc)
* </p>
* <p>
* Note that findEach (and findEachWhile and findIterate) uses a "per graph"
* persistence context scope and adjusts jdbc fetch buffer size for large
* queries. As such it is better to use findList for small queries.
* </p>
* <p>
* Note that internally Ebean can inform the JDBC driver that it is expecting larger
* resultSet and specifically for MySQL this hint is required to stop it's JDBC driver
* from buffering the entire resultSet. As such, for smaller resultSets findList() is
@@ -564,7 +612,6 @@ public interface Query<T> {
* iterator uses the QueryEachConsumer (SAM) interface which is better suited to use
* with Java8 closures.
* </p>
*
* <pre>{@code
*
* ebeanServer.find(Customer.class)
@@ -578,8 +625,7 @@ public interface Query<T> {
*
* }</pre>
*
* @param consumer
* the consumer used to process the queried beans.
* @param consumer the consumer used to process the queried beans.
*/
void findEach(QueryEachConsumer<T> consumer);
@@ -587,12 +633,15 @@ public interface Query<T> {
* Execute the query using callbacks to a visitor to process the resulting
* beans one at a time.
* <p>
* Note that findEachWhile (and findEach and findIterate) uses a "per graph"
* persistence context scope and adjusts jdbc fetch buffer size for large
* queries. As such it is better to use findList for small queries.
* </p>
* <p>
* This method is functionally equivalent to findIterate() but instead of using an
* iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use
* with Java8 closures.
* </p>
*
* <pre>{@code
*
* ebeanServer.find(Customer.class)
@@ -611,8 +660,7 @@ public interface Query<T> {
*
* }</pre>
*
* @param consumer
* the consumer used to process the queried beans.
* @param consumer the consumer used to process the queried beans.
*/
void findEachWhile(QueryEachWhileConsumer<T> consumer);
@@ -621,7 +669,6 @@ public interface Query<T> {
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
*
* <pre>{@code
*
* List<Customer> customers =
@@ -640,7 +687,6 @@ public interface Query<T> {
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
*
* <pre>{@code
*
* Set<Customer> customers =
@@ -663,24 +709,50 @@ public interface Query<T> {
* You can use setMapKey() so specify the property values to be used as keys
* on the map. If one is not specified then the id property is used.
* </p>
*
* <pre>{@code
*
* Map<?, Product> map =
* Map<String, Product> map =
* ebeanServer.find(Product.class)
* .setMapKey("sku")
* .findMap();
*
* }</pre>
*
*
* @see EbeanServer#findMap(Query, Transaction)
*/
Map<?, T> findMap();
<K> Map<K, T> findMap();
/**
* Return a typed map specifying the key property and type.
* Execute the query returning a list of values for a single property.
*
* <h3>Example 1:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .findSingleAttributeList();
*
* }</pre>
*
* <h3>Example 2:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
* .orderBy().asc("name")
* .setMaxRows(100)
* .findSingleAttributeList();
*
* }</pre>
*
* @return the list of values for the selected property
*/
<K> Map<K, T> findMap(String keyProperty, Class<K> keyType);
<A> List<A> findSingleAttributeList();
/**
* Execute the query returning either a single bean or null (if no matching
@@ -693,7 +765,6 @@ public interface Query<T> {
* This is useful when your predicates dictate that your query should only
* return 0 or 1 results.
* </p>
*
* <pre>{@code
*
* // assuming the sku of products is unique...
@@ -703,16 +774,14 @@ public interface Query<T> {
* .findUnique();
* ...
* }</pre>
*
* <p>
* It is also useful with finding objects by their id when you want to specify
* further join information.
* </p>
*
* <pre>{@code
*
* // Fetch order 1 and additionally fetch join its order details...
* Order order =
* Order order =
* ebeanServer.find(Order.class)
* .setId(1)
* .fetch("details")
@@ -731,13 +800,13 @@ public interface Query<T> {
/**
* Return versions of a @History entity bean.
* <p>
* Note that this query will work against view based history implementations
* but not sql2011 standards based implementations that require a start and
* end timestamp to be specified.
* Note that this query will work against view based history implementations
* but not sql2011 standards based implementations that require a start and
* end timestamp to be specified.
* </p>
* <p>
* Generally this query is expected to be a find by id or unique predicates query.
* It will execute the query against the history returning the versions of the bean.
* Generally this query is expected to be a find by id or unique predicates query.
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
List<Version<T>> findVersions();
@@ -745,8 +814,8 @@ public interface Query<T> {
/**
* Return versions of a @History entity bean between the 2 timestamps.
* <p>
* Generally this query is expected to be a find by id or unique predicates query.
* It will execute the query against the history returning the versions of the bean.
* Generally this query is expected to be a find by id or unique predicates query.
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
@@ -774,7 +843,7 @@ public interface Query<T> {
* This is the number of 'top level' or 'root level' entities.
* </p>
*/
int findRowCount();
int findCount();
/**
* Execute find row count query in a background thread.
@@ -783,10 +852,10 @@ public interface Query<T> {
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
*
* @return a Future object for the row count query
*/
FutureRowCount<T> findFutureRowCount();
FutureRowCount<T> findFutureCount();
/**
* Execute find Id's query in a background thread.
@@ -795,7 +864,7 @@ public interface Query<T> {
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
*
* @return a Future object for the list of Id's
*/
FutureIds<T> findFutureIds();
@@ -821,7 +890,6 @@ public interface Query<T> {
* If maxRows is not set on the query prior to calling findPagedList() then a
* PersistenceException is thrown.
* </p>
*
* <pre>{@code
*
* PagedList<Order> pagedList = Ebean.find(Order.class)
@@ -843,24 +911,21 @@ public interface Query<T> {
/**
* Set a named bind parameter. Named parameters have a colon to prefix the name.
*
* <pre>{@code
*
* // a query with a named parameter
* String oql = "find order where status = :orderStatus";
*
*
* Query<Order> query = ebeanServer.find(Order.class, oql);
*
*
* // bind the named parameter
* query.bind("orderStatus", OrderStatus.NEW);
* List<Order> list = query.findList();
*
* }</pre>
*
* @param name
* the parameter name
* @param value
* the parameter value
*
* @param name the parameter name
* @param value the parameter value
*/
Query<T> setParameter(String name, Object value);
@@ -868,25 +933,22 @@ public interface Query<T> {
* Set an ordered bind parameter according to its position. Note that the
* position starts at 1 to be consistent with JDBC PreparedStatement. You need
* to set a parameter value for each ? you have in the query.
*
* <pre>{@code
*
* // a query with a positioned parameter
* String oql = "where status = ? order by id desc";
*
*
* Query<Order> query = ebeanServer.createQuery(Order.class, oql);
*
*
* // bind the parameter
* query.setParameter(1, OrderStatus.NEW);
*
*
* List<Order> list = query.findList();
*
* }</pre>
*
* @param position
* the parameter bind position starting from 1 (not 0)
* @param value
* the parameter bind value.
*
* @param position the parameter bind position starting from 1 (not 0)
* @param value the parameter bind value.
*/
Query<T> setParameter(int position, Object value);
@@ -896,7 +958,6 @@ public interface Query<T> {
* You can use this to have further control over the query. For example adding
* fetch joins.
* </p>
*
* <pre>{@code
*
* Order order =
@@ -919,10 +980,9 @@ public interface Query<T> {
/**
* Add a single Expression to the where clause returning the query.
*
* <pre>{@code
*
* List<Order> newOrders =
* List<Order> newOrders =
* ebeanServer.find(Order.class)
* .where().eq("status", Order.NEW)
* .findList();
@@ -936,7 +996,6 @@ public interface Query<T> {
* Add Expressions to the where clause with the ability to chain on the
* ExpressionList. You can use this for adding multiple expressions to the
* where clause.
*
* <pre>{@code
*
* List<Order> orders =
@@ -947,9 +1006,9 @@ public interface Query<T> {
* .findList();
*
* }</pre>
*
* @see Expr
*
* @return The ExpressionList for adding expressions to.
* @see Expr
*/
ExpressionList<T> where();
@@ -984,9 +1043,8 @@ public interface Query<T> {
* each customer you only want to get the new orders they placed since last
* week. In this case you can use filterMany() to filter the orders.
* </p>
*
* <pre>{@code
*
*
* List<Customer> list =
* ebeanServer.find(Customer.class)
* // .fetch("orders", new FetchConfig().lazy())
@@ -995,20 +1053,17 @@ public interface Query<T> {
* .where().ilike("name", "rob%")
* .filterMany("orders").eq("status", Order.Status.NEW).gt("orderDate", lastWeek)
* .findList();
*
*
* }</pre>
*
* <p>
* Please note you have to be careful that you add expressions to the correct
* expression list - as there is one for the 'root level' and one for each
* filterMany that you have.
* </p>
*
* @param propertyName
* the name of the many property that you want to have a filter on.
*
*
* @param propertyName the name of the many property that you want to have a filter on.
* @return the expression list that you add filter expressions for the many
* to.
* to.
*/
ExpressionList<T> filterMany(String propertyName);
@@ -1021,9 +1076,9 @@ public interface Query<T> {
* Note that this returns the ExpressionList (so you can add multiple
* expressions to the query in a fluent API way).
* </p>
*
* @see Expr
*
* @return The ExpressionList for adding more expressions to.
* @see Expr
*/
ExpressionList<T> having();
@@ -1037,9 +1092,8 @@ public interface Query<T> {
* than the ExpressionList. This is useful when you want to further specify
* something on the query.
* </p>
*
* @param addExpressionToHaving
* the expression to add to the having clause.
*
* @param addExpressionToHaving the expression to add to the having clause.
* @return the Query object
*/
Query<T> having(Expression addExpressionToHaving);
@@ -1151,9 +1205,8 @@ public interface Query<T> {
/**
* Set the maximum number of rows to return in the query.
*
* @param maxRows
* the maximum number of rows to return in the query.
*
* @param maxRows the maximum number of rows to return in the query.
*/
Query<T> setMaxRows(int maxRows);
@@ -1162,11 +1215,10 @@ public interface Query<T> {
* <p>
* If no property is set then the id property is used.
* </p>
*
* <pre>{@code
*
* // Assuming sku is unique for products...
*
*
* Map<?,Product> productMap =
* ebeanServer.find(Product.class)
* // use sku for keys...
@@ -1174,9 +1226,8 @@ public interface Query<T> {
* .findMap();
*
* }</pre>
*
* @param mapKey
* the property to use as keys for a map.
*
* @param mapKey the property to use as keys for a map.
*/
Query<T> setMapKey(String mapKey);
@@ -1203,7 +1254,7 @@ public interface Query<T> {
/**
* Set to true if this query should execute against the doc store.
* <p>
* When setting this you may also consider disabling lazy loading.
* When setting this you may also consider disabling lazy loading.
* </p>
*/
Query<T> setUseDocStore(boolean useDocStore);
@@ -1226,9 +1277,8 @@ public interface Query<T> {
* preparedStatement. If the timeout occurs an exception will be thrown - this
* will be a SQLException wrapped up in a PersistenceException.
* </p>
*
* @param secs
* the query timeout limit in seconds. Zero means there is no limit.
*
* @param secs the query timeout limit in seconds. Zero means there is no limit.
*/
Query<T> setTimeout(int secs);
@@ -1238,6 +1288,16 @@ public interface Query<T> {
* Gives the JDBC driver a hint as to the number of rows that should be
* fetched from the database when more rows are needed for ResultSet.
* </p>
* <p>
* Note that internally findEach and findEachWhile will set the fetch size
* if it has not already as these queries expect to process a lot of rows.
* If we didn't then Postgres and MySql for example would eagerly pull back
* all the row data and potentially consume a lot of memory in the process.
* </p>
* <p>
* As findEach and findEachWhile automatically set the fetch size we don't have
* to do so generally but we might still wish to for tuning a specific use case.
* </p>
*/
Query<T> setBufferFetchSizeHint(int fetchSize);
@@ -1260,7 +1320,7 @@ public interface Query<T> {
* Return true if this query has forUpdate set.
*/
boolean isForUpdate();
/**
* Set root table alias.
*/
@@ -1274,7 +1334,7 @@ public interface Query<T> {
/**
* Set true if you want to disable lazy loading.
* <p>
* That is, once the object graph is returned further lazy loading is disabled.
* That is, once the object graph is returned further lazy loading is disabled.
* </p>
*/
Query<T> setDisableLazyLoading(boolean disableLazyLoading);
@@ -0,0 +1,67 @@
package com.avaje.ebean;
import java.util.Iterator;
/**
* Used to provide iteration over query results.
* <p>
* This can be used when you want to process a very large number of results and
* means that you don't have to hold all the results in memory at once (unlike
* findList(), findSet() etc where all the beans are held in the List or Set
* etc).
* </p>
* <p>
* Note that findIterate (and findEach and findEachWhile) uses a "per graph"
* persistence context scope and adjusts jdbc fetch buffer size for large
* queries. As such it is better to use findList for small queries.
* </p>
* <p>
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
* when you have finished iterating the results (typically in a finally block).
* </p>
*
* <pre>{@code
*
* Query<Customer> query = server.find(Customer.class)
* .where().gt("id", 0)
* .orderBy("id")
* .setMaxRows(2);
*
* QueryIterator<Customer> it = query.findIterate();
* try {
* while (it.hasNext()) {
* Customer customer = it.next();
* // do something with customer ...
* }
* } finally {
* // close the underlying resources
* it.close();
* }
*
* }</pre>
*
* @param <T>
* the type of entity bean in the iteration
*/
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
/**
* Returns <tt>true</tt> if the iteration has more elements.
*/
boolean hasNext();
/**
* Returns the next element in the iteration.
*/
T next();
/**
* Remove is not allowed.
*/
void remove();
/**
* Close the underlying resources held by this iterator.
*/
void close();
}
+7 -7
View File
@@ -401,7 +401,7 @@ public final class RawSql implements Serializable {
this.parsed = true;
this.propertyMap = null;
this.propertyColumnMap = null;
this.dbColumnMap = new LinkedHashMap<String, Column>();
this.dbColumnMap = new LinkedHashMap<>();
for (int i = 0; i < columns.size(); i++) {
Column c = columns.get(i);
dbColumnMap.put(c.getDbColumnKey(), c);
@@ -416,7 +416,7 @@ public final class RawSql implements Serializable {
this.parsed = false;
this.propertyMap = null;
this.propertyColumnMap = null;
this.dbColumnMap = new LinkedHashMap<String, Column>();
this.dbColumnMap = new LinkedHashMap<>();
}
/**
@@ -426,7 +426,7 @@ public final class RawSql implements Serializable {
this.immutable = false;
this.parsed = false;
this.propertyMap = null;
this.dbColumnMap = new LinkedHashMap<String, Column>();
this.dbColumnMap = new LinkedHashMap<>();
int pos = 0;
for (String prop : propertyNames) {
@@ -443,8 +443,8 @@ public final class RawSql implements Serializable {
this.parsed = parsed;
this.dbColumnMap = dbColumnMap;
HashMap<String, Column> pcMap = new HashMap<String, Column>();
HashMap<String, String> pMap = new HashMap<String, String>();
HashMap<String, Column> pcMap = new HashMap<>();
HashMap<String, String> pMap = new HashMap<>();
for (Column c : dbColumnMap.values()) {
pMap.put(c.getPropertyName(), c.getDbColumn());
@@ -606,9 +606,9 @@ public final class RawSql implements Serializable {
}
}
private static String derivePropertyName(String dbAlias, String dbColumn) {
protected static String derivePropertyName(String dbAlias, String dbColumn) {
if (dbAlias != null) {
return dbAlias;
return CamelCaseHelper.toCamelFromUnderscore(dbAlias);
}
int dotPos = dbColumn.indexOf('.');
if (dotPos > -1) {
@@ -1,167 +0,0 @@
package com.avaje.ebean;
class SimpleTextParser {
private final String oql;
private final char[] chars;
private final int eof;
private int pos;
private String word;
private String lowerWord;
SimpleTextParser(String oql) {
this.oql = oql;
this.chars = oql.toCharArray();
this.eof = oql.length();
}
public int getPos() {
return pos;
}
public String getWord() {
return word;
}
public String peekNextWord() {
int origPos = pos;
String nw = nextWordInternal();
pos = origPos;
return nw;
}
/**
* Match the current and the next word.
*/
public boolean isMatch(String lowerMatch, String nextWordMatch) {
if (isMatch(lowerMatch)) {
String nw = peekNextWord();
if (nw != null) {
nw = nw.toLowerCase();
return nw.equals(nextWordMatch);
}
}
return false;
}
public boolean isFinished() {
return word == null;
}
public int findWordLower(String lowerMatch, int afterPos) {
this.pos = afterPos;
return findWordLower(lowerMatch);
}
public int findWordLower(String lowerMatch) {
do {
if (nextWord() == null) {
return -1;
}
if (lowerMatch.equals(lowerWord)) {
return pos - lowerWord.length();
}
} while (true);
}
/**
* Match the current word.
*/
public boolean isMatch(String lowerMatch) {
return lowerMatch.equals(lowerWord);
}
public String nextWord() {
word = nextWordInternal();
if (word != null) {
lowerWord = word.toLowerCase();
}
return word;
}
private String nextWordInternal() {
trimLeadingWhitespace();
if (pos >= eof) {
return null;
}
int start = pos;
if (chars[pos] == '(') {
moveToClose();
} else {
moveToEndOfWord();
}
return oql.substring(start, pos);
}
private void moveToClose() {
pos++;
int openParenthesisCount = 0;
for (; pos < eof; pos++) {
char c = chars[pos];
if (c == '(') {
// count nested parenthesis
openParenthesisCount++;
} else if (c == ')') {
if (openParenthesisCount > 0) {
// still in nested parenthesis
--openParenthesisCount;
} else {
// we have found the end
pos++;
return;
}
}
}
}
private void moveToEndOfWord() {
char c = chars[pos];
boolean isOperator = isOperator(c);
for (; pos < eof; pos++) {
c = chars[pos];
if (isWordTerminator(c, isOperator)) {
return;
}
}
}
private boolean isWordTerminator(char c, boolean isOperator) {
if (Character.isWhitespace(c)) {
return true;
}
if (isOperator(c)) {
return !isOperator;
}
return c == '(' || isOperator;
}
private boolean isOperator(char c) {
switch (c) {
case '<':
return true;
case '>':
return true;
case '=':
return true;
case '!':
return true;
default:
return false;
}
}
private void trimLeadingWhitespace() {
for (; pos < eof; pos++) {
char c = chars[pos];
if (!Character.isWhitespace(c)) {
break;
}
}
}
}
@@ -2,8 +2,6 @@ package com.avaje.ebean;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Query object for performing native SQL queries that return SqlRow's.
+3 -4
View File
@@ -26,7 +26,7 @@ package com.avaje.ebean;
*
* int modifiedCount = Ebean.execute(update);
*
* String msg = &quot;There where &quot; + modifiedCount + &quot;rows updated&quot;
* String msg = &quot;There were &quot; + modifiedCount + &quot; rows updated&quot;
* </pre>
*
* @see Update
@@ -117,8 +117,7 @@ public interface SqlUpdate {
SqlUpdate setParameter(int position, Object value);
/**
* Set a null parameter via its index position. Exactly the same as
* {@link #setNull(int, int)}.
* Set a null parameter via its index position.
*/
SqlUpdate setNull(int position, int jdbcType);
@@ -143,4 +142,4 @@ public interface SqlUpdate {
*/
SqlUpdate setNullParameter(String name, int jdbcType);
}
}
+51 -3
View File
@@ -54,13 +54,52 @@ public interface Transaction extends Closeable {
*/
void setReadOnly(boolean readOnly);
/**
* Commits the transaction at this point with the expectation that another
* commit (or rollback or end) will occur later to complete the transaction.
* <p>
* This is similar to commit() but leaves the transaction "Active".
* </p>
* <h3>Functions/h3>
* <ul>
* <li>Flush the JDBC batch buffer</li>
* <li>Call commit on the underlying JDBC connection</li>
* <li>Trigger any registered TransactionCallbacks</li>
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
* </ul>
*/
void commitAndContinue() throws RollbackException;
/**
* Commit the transaction.
* <p>
* This performs commit and completes the transaction closing underlying resources and
* marking the transaction as "In active".
* </p>
* <h3>Functions/h3>
* <ul>
* <li>Flush the JDBC batch buffer</li>
* <li>Call commit on the underlying JDBC connection</li>
* <li>Trigger any registered TransactionCallbacks</li>
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
* <li>Mark the transaction as "Inactive"</li>
* </ul>
*/
void commit() throws RollbackException;
/**
* Rollback the transaction.
* <p>
* This performs rollback, closes underlying resources and marks the transaction as "In active".
* </p>
* <h3>Functions/h3>
* <ul>
* <li>Call rollback on the underlying JDBC connection</li>
* <li>Trigger any registered TransactionCallbacks</li>
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
* <li>Mark the transaction as "Inactive"</li>
* </ul>
*/
void rollback() throws PersistenceException;
@@ -74,6 +113,16 @@ public interface Transaction extends Closeable {
*/
void rollback(Throwable e) throws PersistenceException;
/**
* Mark the transaction for rollback only.
*/
void setRollbackOnly();
/**
* Return true if the transaction is marked as rollback only.
*/
boolean isRollbackOnly();
/**
* If the transaction is active then perform rollback. Otherwise do nothing.
*/
@@ -417,9 +466,8 @@ public interface Transaction extends Closeable {
/**
* Add an arbitrary user object to the transaction. The objects added have no
* impact on any internals of ebena and are solely meant as a convenient
* method push user information to e.g. the
* {@link com.avaje.ebean.event.TransactionEventListener}.
* impact on any internals of ebean and are solely meant as a convenient
* method push user information (although somewhat replaced by TransactionCallback).
*/
void putUserObject(String name, Object value);
+43 -26
View File
@@ -16,7 +16,7 @@ import java.util.ArrayList;
* This object is used internally with the enhancement of a method with
* Transactional annotation.
* </p>
*
*
* @see TxCallable
* @see TxRunnable
* @see Ebean#execute(TxScope, TxCallable)
@@ -44,27 +44,6 @@ public final class TxScope {
ArrayList<Class<? extends Throwable>> noRollbackFor;
/**
* Return true if PersistBatch has been set.
*/
public boolean isBatchSet() {
return batch != null && batch != PersistBatch.INHERIT;
}
/**
* Return true if batch on cascade has been set.
*/
public boolean isBatchOnCascadeSet() {
return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
}
/**
* Return true if batch size has been set.
*/
public boolean isBatchSizeSet() {
return batchSize > 0;
}
/**
* Helper method to create a TxScope with REQUIRES.
*/
@@ -130,6 +109,44 @@ public final class TxScope {
+ "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]";
}
/**
* Return true if PersistBatch has been set.
*/
public boolean isBatchSet() {
return batch != null && batch != PersistBatch.INHERIT;
}
/**
* Return true if batch on cascade has been set.
*/
public boolean isBatchOnCascadeSet() {
return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
}
/**
* Return true if batch size has been set.
*/
public boolean isBatchSizeSet() {
return batchSize > 0;
}
/**
* Check for batchSize being set without batch mode and use this to imply PersistBatch.ALL.
*/
public void checkBatchMode() {
if (batchSize > 0 && notSet(batch) && notSet(batchOnCascade)) {
// Use setting the batchSize as implying PersistBatch.ALL for @Transactional
batch = PersistBatch.ALL;
}
}
/**
* Return true if the mode is considered not set.
*/
private boolean notSet(PersistBatch batchMode) {
return batchMode == null || batchMode == PersistBatch.INHERIT;
}
/**
* Return the transaction type.
*/
@@ -265,7 +282,7 @@ public final class TxScope {
*/
public TxScope setRollbackFor(Class<? extends Throwable> rollbackThrowable) {
if (rollbackFor == null) {
rollbackFor = new ArrayList<Class<? extends Throwable>>(2);
rollbackFor = new ArrayList<>(2);
}
rollbackFor.add(rollbackThrowable);
return this;
@@ -277,7 +294,7 @@ public final class TxScope {
@SuppressWarnings("unchecked")
public TxScope setRollbackFor(Class<?>[] rollbackThrowables) {
if (rollbackFor == null) {
rollbackFor = new ArrayList<Class<? extends Throwable>>(rollbackThrowables.length);
rollbackFor = new ArrayList<>(rollbackThrowables.length);
}
for (int i = 0; i < rollbackThrowables.length; i++) {
rollbackFor.add((Class<? extends Throwable>) rollbackThrowables[i]);
@@ -299,7 +316,7 @@ public final class TxScope {
*/
public TxScope setNoRollbackFor(Class<? extends Throwable> noRollback) {
if (noRollbackFor == null) {
noRollbackFor = new ArrayList<Class<? extends Throwable>>(2);
noRollbackFor = new ArrayList<>(2);
}
this.noRollbackFor.add(noRollback);
return this;
@@ -311,7 +328,7 @@ public final class TxScope {
@SuppressWarnings("unchecked")
public TxScope setNoRollbackFor(Class<?>[] noRollbacks) {
if (noRollbackFor == null) {
noRollbackFor = new ArrayList<Class<? extends Throwable>>(noRollbacks.length);
noRollbackFor = new ArrayList<>(noRollbacks.length);
}
for (int i = 0; i < noRollbacks.length; i++) {
noRollbackFor.add((Class<? extends Throwable>) noRollbacks[i]);
@@ -57,7 +57,7 @@ package com.avaje.ebean;
* where id in (
* select t0.id c0
* from o_customer t0
* left outer join o_address t1 on t1.id = t0.billing_address_id
* left join o_address t1 on t1.id = t0.billing_address_id
* where t0.status = ?
* and t1.country_code = ?
* and t0.id > ? )
@@ -0,0 +1,50 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify a property to be an aggregation formula.
* <p>
* The aggregation formula should be a sum, count, avg, min or max.
* By default aggregation properties are treated as transient and not
* included in a query. To populate the aggregation property it must be
* explicitly included in the select().
* </p>
*
* <h3>Example:</h3>
* <pre>{@code
*
* @Aggregation("count(details)")
* Long totalCount;
*
* @Aggregation("sum(details.quantity*details.unitPrice)")
* Long totalAmount;
*
* }</pre>
*
* <h3>Example query</h3>
* <pre>{@code
*
* List<TEventOne> list = Ebean.find(TEventOne.class)
* .select("name, totalCount, totalUnits, totalAmount")
* .where()
* .startsWith("logs.description", "a")
* .having()
* .ge("count", 1)
* .orderBy().asc("name")
* .findList();
*
* }</pre>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Aggregation {
/**
* Aggregation formula using sum, count, avg, min, max.
*/
String value();
}
@@ -82,7 +82,7 @@ public @interface Formula {
* as count, sum etc.
* </p>
* <p>
* The join string should start with either "left outer join" or "join".
* The join string should start with either "left join" or "join".
* </p>
*
* <p>
@@ -1,17 +1,19 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* An annotation for declaring an index on a single column.
* An annotation for declaring an index.
*
* @author rvbiljouw
*/
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Indices.class)
public @interface Index {
/**
@@ -27,6 +29,9 @@ public @interface Index {
/**
* When placed on the class (rather than field) you can specify the columns
* to include in the index in order.
*
* Wnen placed on a field, and columnNames are specified, the field-column has to be included.
* You can use "${fa}" for alias
*/
String[] columnNames() default {};
@@ -0,0 +1,20 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* An annotation for declaring multiple indices at class or field level.
*
* @author Roland Praml, FOCONIS AG
*/
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Indices {
/**
* Array with {@link Index} definitions.
*/
Index[] value() default {};
}
@@ -31,6 +31,11 @@ public interface BeanCollection<E> extends Serializable {
ALL
}
/**
* Set the disableLazyLoad state.
*/
void setDisableLazyLoad(boolean disableLazyLoad);
/**
* Load bean from another collection.
*/
@@ -39,6 +39,8 @@ public final class EntityBeanIntercept implements Serializable {
private transient BeanLoader beanLoader;
private transient PreGetterCallback preGetterCallback;
private String ebeanServerName;
/**
@@ -186,6 +188,21 @@ public final class EntityBeanIntercept implements Serializable {
return embeddedOwnerIndex;
}
/**
* Clear the getter callback.
*/
public void clearGetterCallback() {
this.preGetterCallback = null;
}
/**
* Register the callback to be triggered when getter is called.
* This is used primarily to automatically flush the JDBC batch.
*/
public void registerGetterCallback(PreGetterCallback getterCallback) {
this.preGetterCallback = getterCallback;
}
/**
* Set the embedded beans owning bean.
*/
@@ -325,6 +342,13 @@ public final class EntityBeanIntercept implements Serializable {
return state == STATE_LOADED;
}
/**
* Set the bean into NEW state.
*/
public void setNew() {
this.state = STATE_NEW;
}
/**
* Set the loaded state to true.
* <p>
@@ -563,7 +587,7 @@ public final class EntityBeanIntercept implements Serializable {
if (fullyLoadedBean) {
return null;
}
Set<String> props = new LinkedHashSet<String>();
Set<String> props = new LinkedHashSet<>();
for (int i=0; i<loadedProps.length; i++) {
if (loadedProps[i]) {
props.add(getProperty(i));
@@ -593,7 +617,7 @@ public final class EntityBeanIntercept implements Serializable {
* Return the set of dirty properties.
*/
public Set<String> getDirtyPropertyNames() {
Set<String> props = new LinkedHashSet<String>();
Set<String> props = new LinkedHashSet<>();
addDirtyPropertyNames(props, null);
return props;
}
@@ -642,7 +666,7 @@ public final class EntityBeanIntercept implements Serializable {
* Return a map of dirty properties with their new and old values.
*/
public Map<String,ValuePair> getDirtyValues() {
Map<String,ValuePair> dirtyValues = new LinkedHashMap<String, ValuePair>();
Map<String,ValuePair> dirtyValues = new LinkedHashMap<>();
addDirtyPropertyValues(dirtyValues, null);
return dirtyValues;
}
@@ -832,19 +856,31 @@ public final class EntityBeanIntercept implements Serializable {
public void initialisedMany(int propertyIndex) {
loadedProps[propertyIndex] = true;
}
private final void preGetterCallback() {
if (preGetterCallback != null) {
preGetterCallback.preGetterTrigger();
}
}
/**
* Called prior to Id property getter.
*/
public void preGetId() {
preGetterCallback();
}
/**
* Method that is called prior to a getter method on the actual entity.
*/
public void preGetter(int propertyIndex) {
preGetterCallback();
if (state == STATE_NEW || disableLazyLoad) {
return;
}
if (!isLoadedProperty(propertyIndex)) {
loadBean(propertyIndex);
}
if (nodeUsageCollector != null) {
nodeUsageCollector.addUsed(getProperty(propertyIndex));
}
@@ -29,7 +29,7 @@ public final class NodeUsageCollector {
/**
* The properties used at this profile point.
*/
private final Set<String> used = new LinkedHashSet<String>();
private final Set<String> used = new LinkedHashSet<>();
/**
* set to true if the bean is modified (setter called)
@@ -0,0 +1,13 @@
package com.avaje.ebean.bean;
/**
* A callback that can be registered to fire on getter method calls.
* It's primary purpose is to automatically flush JDBC batch buffer.
*/
public interface PreGetterCallback {
/**
* Trigger the callback.
*/
void preGetterTrigger();
}
@@ -20,6 +20,8 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
protected boolean readOnly;
protected boolean disableLazyLoad;
/**
* The EbeanServer this is associated with. (used for lazy fetch).
*/
@@ -84,6 +86,11 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
this.filterMany = filterMany;
}
@Override
public void setDisableLazyLoad(boolean disableLazyLoad) {
this.disableLazyLoad = disableLazyLoad;
}
protected void lazyLoadCollection(boolean onlyIds) {
if (loader == null) {
loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
@@ -152,7 +159,7 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
protected ModifyHolder<E> getModifyHolder() {
if (modifyHolder == null) {
modifyHolder = new ModifyHolder<E>();
modifyHolder = new ModifyHolder<>();
}
return modifyHolder;
}
@@ -37,7 +37,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
* Uses an ArrayList as the underlying List implementation.
*/
public BeanList() {
this(new ArrayList<E>());
this(new ArrayList<>());
}
/**
@@ -68,7 +68,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
@SuppressWarnings("unchecked")
public void loadFrom(BeanCollection<?> other) {
if (list == null) {
list = new ArrayList<E>();
list = new ArrayList<>();
}
list.addAll((Collection<? extends E>) other.getActualDetails());
}
@@ -76,7 +76,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
@SuppressWarnings("unchecked")
public void internalAdd(Object bean) {
if (list == null) {
list = new ArrayList<E>();
list = new ArrayList<>();
}
if (bean != null) {
list.add((E) bean);
@@ -92,7 +92,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public boolean checkEmptyLazyLoad() {
if (list == null) {
list = new ArrayList<E>();
list = new ArrayList<>();
return true;
} else {
return false;
@@ -102,10 +102,10 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
private void initClear() {
synchronized (this) {
if (list == null) {
if (modifyListening) {
if (!disableLazyLoad && modifyListening) {
lazyLoadCollection(true);
} else {
list = new ArrayList<E>();
list = new ArrayList<>();
}
}
}
@@ -114,7 +114,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
private void init() {
synchronized (this) {
if (list == null) {
lazyLoadCollection(false);
if (disableLazyLoad) {
list = new ArrayList<>();
} else {
lazyLoadCollection(false);
}
}
}
}
@@ -292,11 +296,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public Iterator<E> iterator() {
init();
if (isReadOnly()) {
return new ReadOnlyListIterator<E>(list.listIterator());
return new ReadOnlyListIterator<>(list.listIterator());
}
if (modifyListening) {
Iterator<E> it = list.iterator();
return new ModifyIterator<E>(this, it);
return new ModifyIterator<>(this, it);
}
return list.iterator();
}
@@ -309,11 +313,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public ListIterator<E> listIterator() {
init();
if (isReadOnly()) {
return new ReadOnlyListIterator<E>(list.listIterator());
return new ReadOnlyListIterator<>(list.listIterator());
}
if (modifyListening) {
ListIterator<E> it = list.listIterator();
return new ModifyListIterator<E>(this, it);
return new ModifyListIterator<>(this, it);
}
return list.listIterator();
}
@@ -321,11 +325,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public ListIterator<E> listIterator(int index) {
init();
if (isReadOnly()) {
return new ReadOnlyListIterator<E>(list.listIterator(index));
return new ReadOnlyListIterator<>(list.listIterator(index));
}
if (modifyListening) {
ListIterator<E> it = list.listIterator(index);
return new ModifyListIterator<E>(this, it);
return new ModifyListIterator<>(this, it);
}
return list.listIterator(index);
}
@@ -421,7 +425,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return Collections.unmodifiableList(list.subList(fromIndex, toIndex));
}
if (modifyListening) {
return new ModifyList<E>(this, list.subList(fromIndex, toIndex));
return new ModifyList<>(this, list.subList(fromIndex, toIndex));
}
return list.subList(fromIndex, toIndex);
}
@@ -33,7 +33,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
* Create using a underlying LinkedHashMap.
*/
public BeanMap() {
this(new LinkedHashMap<K, E>());
this(new LinkedHashMap<>());
}
public BeanMap(BeanCollectionLoader ebeanServer, EntityBean ownerBean, String propertyName) {
@@ -61,14 +61,14 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
public void internalPutNull() {
if (map == null) {
map = new LinkedHashMap<K, E>();
map = new LinkedHashMap<>();
}
}
@SuppressWarnings("unchecked")
public void internalPut(Object key, Object bean) {
if (map == null) {
map = new LinkedHashMap<K, E>();
map = new LinkedHashMap<>();
}
if (key != null) {
map.put((K) key, (E) bean);
@@ -108,7 +108,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
public boolean checkEmptyLazyLoad() {
if (map == null) {
map = new LinkedHashMap<K, E>();
map = new LinkedHashMap<>();
return true;
} else {
return false;
@@ -121,7 +121,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
if (modifyListening) {
lazyLoadCollection(true);
} else {
map = new LinkedHashMap<K, E>();
map = new LinkedHashMap<>();
}
}
}
@@ -265,7 +265,6 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
return map.put(key, value);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public void putAll(Map<? extends K, ? extends E> puts) {
checkReadOnly();
init();
@@ -314,7 +313,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
}
if (modifyListening) {
Collection<E> c = map.values();
return new ModifyCollection<E>(this, c);
return new ModifyCollection<>(this, c);
}
return map.values();
}
@@ -34,7 +34,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
* Create using an underlying LinkedHashSet.
*/
public BeanSet() {
this(new LinkedHashSet<E>());
this(new LinkedHashSet<>());
}
public BeanSet(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
@@ -61,7 +61,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
@SuppressWarnings("unchecked")
public void loadFrom(BeanCollection<?> other) {
if (set == null) {
set = new LinkedHashSet<E>();
set = new LinkedHashSet<>();
}
set.addAll((Collection<? extends E>) other.getActualDetails());
}
@@ -76,7 +76,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
@SuppressWarnings("unchecked")
public void internalAdd(Object bean) {
if (set == null) {
set = new LinkedHashSet<E>();
set = new LinkedHashSet<>();
}
if (bean != null) {
set.add((E) bean);
@@ -100,7 +100,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public boolean checkEmptyLazyLoad() {
if (set == null) {
set = new LinkedHashSet<E>();
set = new LinkedHashSet<>();
return true;
} else {
return false;
@@ -113,7 +113,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
if (modifyListening) {
lazyLoadCollection(true);
} else {
set = new LinkedHashSet<E>();
set = new LinkedHashSet<>();
}
}
}
@@ -256,10 +256,10 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public Iterator<E> iterator() {
init();
if (isReadOnly()) {
return new ReadOnlyIterator<E>(set.iterator());
return new ReadOnlyIterator<>(set.iterator());
}
if (modifyListening) {
return new ModifyIterator<E>(this, set.iterator());
return new ModifyIterator<>(this, set.iterator());
}
return set.iterator();
}
@@ -72,7 +72,7 @@ class ModifyCollection<E> implements Collection<E> {
@Override
public Iterator<E> iterator() {
Iterator<E> it = c.iterator();
return new ModifyIterator<E>(owner, it);
return new ModifyIterator<>(owner, it);
}
@Override
@@ -21,16 +21,16 @@ class ModifyHolder<E> implements Serializable {
/**
* Deletions list for manyToMany persistence.
*/
private Set<E> modifyDeletions = new LinkedHashSet<E>();
private Set<E> modifyDeletions = new LinkedHashSet<>();
/**
* Additions list for manyToMany persistence.
*/
private Set<E> modifyAdditions = new LinkedHashSet<E>();
private Set<E> modifyAdditions = new LinkedHashSet<>();
void reset() {
modifyDeletions = new LinkedHashSet<E>();
modifyAdditions = new LinkedHashSet<E>();
modifyDeletions = new LinkedHashSet<>();
modifyAdditions = new LinkedHashSet<>();
}
/**
@@ -61,11 +61,11 @@ class ModifyList<E> extends ModifyCollection<E> implements List<E> {
}
public ListIterator<E> listIterator() {
return new ModifyListIterator<E>(owner, list.listIterator());
return new ModifyListIterator<>(owner, list.listIterator());
}
public ListIterator<E> listIterator(int index) {
return new ModifyListIterator<E>(owner, list.listIterator(index));
return new ModifyListIterator<>(owner, list.listIterator(index));
}
public E remove(int index) {
@@ -82,7 +82,7 @@ class ModifyList<E> extends ModifyCollection<E> implements List<E> {
}
public List<E> subList(int fromIndex, int toIndex) {
return new ModifyList<E>(owner, list.subList(fromIndex, toIndex));
return new ModifyList<>(owner, list.subList(fromIndex, toIndex));
}
}
@@ -91,7 +91,7 @@ public class ClassLoadConfig {
/**
* Return true if the given class is present.
*/
protected boolean isPresent(String className) {
public boolean isPresent(String className) {
try {
forName(className);
return true;
@@ -0,0 +1,54 @@
package com.avaje.ebean.config;
import com.avaje.ebean.config.dbplatform.DbType;
/**
* Custom mappings for DB types that override the default.
*
* @see ServerConfig#addCustomMapping(DbType, String)
*/
public class CustomDbTypeMapping {
protected final DbType type;
protected final String columnDefinition;
protected final Platform platform;
/**
* Create a mapping.
*/
public CustomDbTypeMapping(DbType type, String columnDefinition, Platform platform) {
this.type = type;
this.columnDefinition = columnDefinition;
this.platform = platform;
}
/**
* Create a mapping that should apply to all the database platforms.
*/
public CustomDbTypeMapping(DbType type, String columnDefinition) {
this(type, columnDefinition, null);
}
/**
* Return the DB type the mapping applies to.
*/
public DbType getType() {
return type;
}
/**
* Return the DB column definition to use.
*/
public String getColumnDefinition() {
return columnDefinition;
}
/**
* Return the platform this mapping should apply to. Null means it applied to all platforms.
*/
public Platform getPlatform() {
return platform;
}
}
@@ -1,7 +1,6 @@
package com.avaje.ebean.config;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.config.dbplatform.DbPlatformName;
import com.avaje.ebean.dbmigration.DbMigration;
import org.avaje.dbmigration.MigrationConfig;
import org.avaje.dbmigration.MigrationRunner;
@@ -20,7 +19,7 @@ public class DbMigrationConfig {
/**
* The database platform to generate migration DDL for.
*/
protected DbPlatformName platform;
protected Platform platform;
/**
* Set to true if the DB migration should be generated on server start.
@@ -112,14 +111,14 @@ public class DbMigrationConfig {
* We typically need to explicitly specify this as migration can often be generated
* when running against H2.
*/
public DbPlatformName getPlatform() {
public Platform getPlatform() {
return platform;
}
/**
* Set the DB platform to generate migration DDL for.
*/
public void setPlatform(DbPlatformName platform) {
public void setPlatform(Platform platform) {
this.platform = platform;
}
@@ -366,7 +365,7 @@ public class DbMigrationConfig {
includeGeneratedFileComment = properties.getBoolean("migration.includeGeneratedFileComment", includeGeneratedFileComment);
generatePendingDrop = properties.get("migration.generatePendingDrop", generatePendingDrop);
platform = properties.getEnum(DbPlatformName.class, "migration.platform", platform);
platform = properties.getEnum(Platform.class, "migration.platform", platform);
generate = properties.getBoolean("migration.generate", generate);
version = properties.get("migration.version", version);
@@ -1,9 +1,9 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config;
/**
* Built in supported platforms.
*/
public enum DbPlatformName {
public enum Platform {
/**
* Generic base platform configured via properties or code.
@@ -16,7 +16,7 @@ public final class PropertyMap implements Serializable {
private static final long serialVersionUID = 1L;
private final LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
private final LinkedHashMap<String, String> map = new LinkedHashMap<>();
/**
* Return properties loaded from test-ebean.properties.
@@ -7,14 +7,15 @@ import com.avaje.ebean.cache.ServerCacheManager;
import com.avaje.ebean.cache.ServerCachePlugin;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbEncrypt;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.event.BeanFindController;
import com.avaje.ebean.event.BeanPersistController;
import com.avaje.ebean.event.BeanPersistListener;
import com.avaje.ebean.event.BeanPostConstructListener;
import com.avaje.ebean.event.BeanPostLoad;
import com.avaje.ebean.event.BeanQueryAdapter;
import com.avaje.ebean.event.BulkTableEventListener;
import com.avaje.ebean.event.ServerConfigStartup;
import com.avaje.ebean.event.TransactionEventListener;
import com.avaje.ebean.event.changelog.ChangeLogListener;
import com.avaje.ebean.event.changelog.ChangeLogPrepare;
import com.avaje.ebean.event.changelog.ChangeLogRegister;
@@ -74,16 +75,24 @@ public class ServerConfig {
/**
* The EbeanServer name.
*/
private String name;
private String name = "db";
/**
* When false (default) H2 automatically uses DDL generate and run
* (i.e. assumes we are running tests using in memory h2).
*/
private boolean h2ProductionMode;
/**
* Typically configuration type objects that are passed by this ServerConfig
* to plugins. For example - IgniteConfiguration passed to Ignite plugin.
*/
private Map<String, Object> serviceObject = new HashMap<String, Object>();
private Map<String, Object> serviceObject = new HashMap<>();
private ContainerConfig containerConfig;
private List<CustomDbTypeMapping> customDbTypeMappings = new ArrayList<>();
/**
* The underlying properties that were used during configuration.
*/
@@ -102,24 +111,29 @@ public class ServerConfig {
/**
* Set to true if this is the default/primary server.
*/
private boolean defaultServer;
private boolean defaultServer = true;
/**
* Set this to true to disable class path search.
*/
private boolean disableClasspathSearch;
/**
* The Geometry SRID value (default 4326).
*/
private int geometrySRID = 4326;
/**
* List of interesting classes such as entities, embedded, ScalarTypes,
* Listeners, Finders, Controllers etc.
*/
private List<Class<?>> classes = new ArrayList<Class<?>>();
private List<Class<?>> classes = new ArrayList<>();
/**
* The packages that are searched for interesting classes. Only used when
* classes is empty/not explicitly specified.
*/
private List<String> packages = new ArrayList<String>();
private List<String> packages = new ArrayList<>();
/**
* Configuration for the ElasticSearch integration.
@@ -163,6 +177,17 @@ public class ServerConfig {
*/
private int databaseSequenceBatchSize = 20;
/**
* JDBC fetchSize hint when using findList. Defaults to 0 leaving it up to the JDBC driver.
*/
private int jdbcFetchSizeFindList;
/**
* JDBC fetchSize hint when using findEach/findEachWhile. Defaults to 100. Note that this does
* not apply to MySql as that gets special treatment (forward only etc).
*/
private int jdbcFetchSizeFindEach = 100;
/**
* Suffix appended to the base table to derive the view that contains the union
* of the base table and the history table in order to support asOf queries.
@@ -187,9 +212,11 @@ public class ServerConfig {
private PersistBatch persistBatch = PersistBatch.NONE;
/**
* Use for per request batch mode.
* Use for cascade persist JDBC batch mode. INHERIT means use the platform default
* which is ALL except for SQL Server where it is NONE (as getGeneratedKeys isn't
* supported on SQL Server with JDBC batch).
*/
private PersistBatch persistBatchOnCascade = PersistBatch.NONE;
private PersistBatch persistBatchOnCascade = PersistBatch.INHERIT;
private int persistBatchSize = 20;
@@ -307,18 +334,18 @@ public class ServerConfig {
/**
* Setting to indicate if UUID should be stored as binary(16) or varchar(40) or native DB type (for H2 and Postgres).
*/
private DbUuid dbUuid = DbUuid.AUTO;
private DbUuid dbUuid = DbUuid.AUTO_VARCHAR;
private List<IdGenerator> idGenerators = new ArrayList<IdGenerator>();
private List<BeanFindController> findControllers = new ArrayList<BeanFindController>();
private List<BeanPersistController> persistControllers = new ArrayList<BeanPersistController>();
private List<BeanPostLoad> postLoaders = new ArrayList<BeanPostLoad>();
private List<BeanPersistListener> persistListeners = new ArrayList<BeanPersistListener>();
private List<BeanQueryAdapter> queryAdapters = new ArrayList<BeanQueryAdapter>();
private List<BulkTableEventListener> bulkTableEventListeners = new ArrayList<BulkTableEventListener>();
private List<ServerConfigStartup> configStartupListeners = new ArrayList<ServerConfigStartup>();
private List<TransactionEventListener> transactionEventListeners = new ArrayList<TransactionEventListener>();
private List<IdGenerator> idGenerators = new ArrayList<>();
private List<BeanFindController> findControllers = new ArrayList<>();
private List<BeanPersistController> persistControllers = new ArrayList<>();
private List<BeanPostLoad> postLoaders = new ArrayList<>();
private List<BeanPostConstructListener> postConstructListeners = new ArrayList<>();
private List<BeanPersistListener> persistListeners = new ArrayList<>();
private List<BeanQueryAdapter> queryAdapters = new ArrayList<>();
private List<BulkTableEventListener> bulkTableEventListeners = new ArrayList<>();
private List<ServerConfigStartup> configStartupListeners = new ArrayList<>();
/**
* By default inserts are included in the change log.
@@ -366,19 +393,13 @@ public class ServerConfig {
private boolean transactionRollbackOnChecked = true;
private boolean registerJmxMBeans = true;
// configuration for the background executor service (thread pool)
private int backgroundExecutorSchedulePoolSize = 1;
private int backgroundExecutorCorePoolSize = 1;
private int backgroundExecutorMaxPoolSize = 8;
private int backgroundExecutorIdleSecs = 60;
private int backgroundExecutorShutdownSecs = 30;
// defaults for the L2 bean caching
private int cacheWarmingDelay = 30;
private int cacheMaxSize = 10000;
private int cacheMaxIdleTime = 600;
private int cacheMaxTimeToLive = 60 * 60 * 6;
@@ -396,7 +417,7 @@ public class ServerConfig {
private boolean expressionEqualsWithNullAsNoop;
/**
* Set to true to use native ILIKE expression (if support by datasbase platform / like Postgres).
* Set to true to use native ILIKE expression (if support by database platform / like Postgres).
*/
private boolean expressionNativeIlike;
@@ -494,6 +515,27 @@ public class ServerConfig {
this.name = name;
}
/**
* Return true if H2 should be used in production mode.
* <p>
* Otherwise it is assumed we are using H2 for testing and DDL generate and run is turned on.
* </p>
*/
public boolean isH2ProductionMode() {
return h2ProductionMode;
}
/**
* Set to true for H2 to be used in production mode.
* <p>
* Do this when we want to use H2 and not have the DDL generation and run automatically turned on.
* Otherwise it is assumed we are using H2 for testing purposes.
* </p>
*/
public void setH2ProductionMode(boolean h2ProductionMode) {
this.h2ProductionMode = h2ProductionMode;
}
/**
* Return the container / clustering configuration.
* <p/>
@@ -548,7 +590,7 @@ public class ServerConfig {
}
/**
* Set true if this EbeanServer should be registered as the "default" server
* Set false if you do not want this EbeanServer to be registered as the "default" server
* with the Ebean singleton.
* <p>
* This is only used when {@link #setRegister(boolean)} is also true.
@@ -719,6 +761,34 @@ public class ServerConfig {
this.databaseSequenceBatchSize = databaseSequenceBatchSize;
}
/**
* Return the default JDBC fetchSize hint for findList queries.
*/
public int getJdbcFetchSizeFindList() {
return jdbcFetchSizeFindList;
}
/**
* Set the default JDBC fetchSize hint for findList queries.
*/
public void setJdbcFetchSizeFindList(int jdbcFetchSizeFindList) {
this.jdbcFetchSizeFindList = jdbcFetchSizeFindList;
}
/**
* Return the default JDBC fetchSize hint for findEach/findEachWhile queries.
*/
public int getJdbcFetchSizeFindEach() {
return jdbcFetchSizeFindEach;
}
/**
* Set the default JDBC fetchSize hint for findEach/findEachWhile queries.
*/
public void setJdbcFetchSizeFindEach(int jdbcFetchSizeFindEach) {
this.jdbcFetchSizeFindEach = jdbcFetchSizeFindEach;
}
/**
* Return the ChangeLogPrepare.
* <p>
@@ -838,6 +908,20 @@ public class ServerConfig {
this.migrationConfig = migrationConfig;
}
/**
* Return the Geometry SRID.
*/
public int getGeometrySRID() {
return geometrySRID;
}
/**
* Set the Geometry SRID.
*/
public void setGeometrySRID(int geometrySRID) {
this.geometrySRID = geometrySRID;
}
/**
* Return the time zone to use when reading/writing Timestamps via JDBC.
* <p>
@@ -1001,20 +1085,6 @@ public class ServerConfig {
this.transactionRollbackOnChecked = transactionRollbackOnChecked;
}
/**
* Return true if the server should register JMX MBeans.
*/
public boolean isRegisterJmxMBeans() {
return registerJmxMBeans;
}
/**
* Set if the server should register JMX MBeans.
*/
public void setRegisterJmxMBeans(boolean registerJmxMBeans) {
this.registerJmxMBeans = registerJmxMBeans;
}
/**
* Return the Background executor schedule pool size. Defaults to 1.
*/
@@ -1029,48 +1099,6 @@ public class ServerConfig {
this.backgroundExecutorSchedulePoolSize = backgroundExecutorSchedulePoolSize;
}
/**
* Return the Background executor core pool size.
*/
public int getBackgroundExecutorCorePoolSize() {
return backgroundExecutorCorePoolSize;
}
/**
* Set the Background executor core pool size.
*/
public void setBackgroundExecutorCorePoolSize(int backgroundExecutorCorePoolSize) {
this.backgroundExecutorCorePoolSize = backgroundExecutorCorePoolSize;
}
/**
* Return the Background executor max pool size.
*/
public int getBackgroundExecutorMaxPoolSize() {
return backgroundExecutorMaxPoolSize;
}
/**
* Set the Background executor max pool size.
*/
public void setBackgroundExecutorMaxPoolSize(int backgroundExecutorMaxPoolSize) {
this.backgroundExecutorMaxPoolSize = backgroundExecutorMaxPoolSize;
}
/**
* Return the Background executor idle seconds.
*/
public int getBackgroundExecutorIdleSecs() {
return backgroundExecutorIdleSecs;
}
/**
* Set the Background executor idle seconds.
*/
public void setBackgroundExecutorIdleSecs(int backgroundExecutorIdleSecs) {
this.backgroundExecutorIdleSecs = backgroundExecutorIdleSecs;
}
/**
* Return the Background executor shutdown seconds. This is the time allowed for the pool to shutdown nicely
* before it is forced shutdown.
@@ -1087,20 +1115,6 @@ public class ServerConfig {
this.backgroundExecutorShutdownSecs = backgroundExecutorShutdownSecs;
}
/**
* Return the cache warming delay in seconds.
*/
public int getCacheWarmingDelay() {
return cacheWarmingDelay;
}
/**
* Set the cache warming delay in seconds.
*/
public void setCacheWarmingDelay(int cacheWarmingDelay) {
this.cacheWarmingDelay = cacheWarmingDelay;
}
/**
* Return the L2 cache default max size.
*/
@@ -1457,6 +1471,11 @@ public class ServerConfig {
*/
public void setDatabasePlatform(DatabasePlatform databasePlatform) {
this.databasePlatform = databasePlatform;
if (!h2ProductionMode && databasePlatform != null && databasePlatform.isPlatform(Platform.H2)) {
// we are using H2 to run tests so turn on DDL generation and run
this.ddlGenerate = true;
this.ddlRun = true;
}
}
/**
@@ -1474,7 +1493,7 @@ public class ServerConfig {
* <p>
* You can also set this in ebean.proprerties:
* </p>
*
* <p>
* <pre>{@code
* # set via ebean.properties
* ebean.encryptKeyManager=com.avaje.tests.basic.encrypt.BasicEncyptKeyManager
@@ -1739,7 +1758,7 @@ public class ServerConfig {
*/
public void addClass(Class<?> cls) {
if (classes == null) {
classes = new ArrayList<Class<?>>();
classes = new ArrayList<>();
}
classes.add(cls);
}
@@ -1752,7 +1771,7 @@ public class ServerConfig {
*/
public void addPackage(String packageName) {
if (packages == null) {
packages = new ArrayList<String>();
packages = new ArrayList<>();
}
packages.add(packageName);
}
@@ -1807,7 +1826,7 @@ public class ServerConfig {
* queries that normally hit L2 bean cache automatically will not do so after a write/persist
* on the transaction.
* </p>
*
* <p>
* <pre>{@code
*
* // assume Customer has L2 bean caching enabled ...
@@ -1969,6 +1988,54 @@ public class ServerConfig {
this.resourceDirectory = resourceDirectory;
}
/**
* Add a custom type mapping.
* <p>
* <pre>{@code
*
* // set the default mapping for BigDecimal.class/decimal
* serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
*
* // set the default mapping for String.class/varchar but only for Postgres
* serverConfig.addCustomMapping(DbType.VARCHAR, "text", Platform.POSTGRES);
*
* }</pre>
*
* @param type The DB type this mapping should apply to
* @param columnDefinition The column definition that should be used
* @param platform Optionally specify the platform this mapping should apply to.
*/
public void addCustomMapping(DbType type, String columnDefinition, Platform platform) {
customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition, platform));
}
/**
* Add a custom type mapping that applies to all platforms.
* <p>
* <pre>{@code
*
* // set the default mapping for BigDecimal/decimal
* serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
*
* // set the default mapping for String/varchar
* serverConfig.addCustomMapping(DbType.VARCHAR, "text");
*
* }</pre>
*
* @param type The DB type this mapping should apply to
* @param columnDefinition The column definition that should be used
*/
public void addCustomMapping(DbType type, String columnDefinition) {
customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition));
}
/**
* Return the list of custom type mappings.
*/
public List<CustomDbTypeMapping> getCustomTypeMappings() {
return customDbTypeMappings;
}
/**
* Register a BeanQueryAdapter instance.
* <p>
@@ -2041,6 +2108,16 @@ public class ServerConfig {
postLoaders.add(postLoad);
}
/**
* Register a BeanPostConstructListener instance.
* <p>
* Note alternatively you can use {@link #setPostConstructListeners(List)} to set
* all the BeanPostConstructListener instances.
* </p>
*/
public void add(BeanPostConstructListener listener) {
postConstructListeners.add(listener);
}
/**
* Return the list of BeanFindController instances.
*/
@@ -2069,6 +2146,19 @@ public class ServerConfig {
this.postLoaders = postLoaders;
}
/**
* Return the list of BeanPostLoader instances.
*/
public List<BeanPostConstructListener> getPostConstructListeners() {
return postConstructListeners;
}
/**
* Set the list of BeanPostLoader instances.
*/
public void setPostConstructListeners(List<BeanPostConstructListener> listeners) {
this.postConstructListeners = listeners;
}
/**
* Return the BeanPersistController instances.
*/
@@ -2087,35 +2177,6 @@ public class ServerConfig {
this.persistControllers = persistControllers;
}
/**
* Register a TransactionEventListener instance
* <p>
* Note alternatively you can use {@link #setTransactionEventListeners(List)}
* to set all the TransactionEventListener instances.
* </p>
*/
public void add(TransactionEventListener listener) {
transactionEventListeners.add(listener);
}
/**
* Return the TransactionEventListener instances.
*/
public List<TransactionEventListener> getTransactionEventListeners() {
return transactionEventListeners;
}
/**
* Register all the TransactionEventListener instances.
* <p>
* Note alternatively you can use {@link #add(TransactionEventListener)} to
* add TransactionEventListener instances one at a time.
* </p>
*/
public void setTransactionEventListeners(List<TransactionEventListener> transactionEventListeners) {
this.transactionEventListeners = transactionEventListeners;
}
/**
* Register a BeanPersistListener instance.
* <p>
@@ -2282,7 +2343,6 @@ public class ServerConfig {
* @param key properties key
* @param instance existing instance
*/
@SuppressWarnings("unchecked")
protected <T> T createInstance(PropertiesWrapper properties, Class<T> pluginType, String key, T instance) {
if (instance != null) {
@@ -2298,6 +2358,7 @@ public class ServerConfig {
* @param pluginType the type of plugin
* @param classname the implementation class as per properties
*/
@SuppressWarnings("unchecked")
protected <T> T createInstance(Class<T> pluginType, String classname) {
return classname == null ? null : (T) classLoadConfig.newInstance(classname);
}
@@ -2353,11 +2414,14 @@ public class ServerConfig {
}
loadDocStoreSettings(p);
geometrySRID = p.getInt("geometrySRID", geometrySRID);
disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache);
explicitTransactionBeginMode = p.getBoolean("explicitTransactionBeginMode", explicitTransactionBeginMode);
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager);
backgroundExecutorSchedulePoolSize = p.getInt("backgroundExecutorSchedulePoolSize", backgroundExecutorSchedulePoolSize);
backgroundExecutorShutdownSecs = p.getInt("backgroundExecutorShutdownSecs", backgroundExecutorShutdownSecs);
disableClasspathSearch = p.getBoolean("disableClasspathSearch", disableClasspathSearch);
currentUserProvider = createInstance(p, CurrentUserProvider.class, "currentUserProvider", currentUserProvider);
databasePlatform = createInstance(p, DatabasePlatform.class, "databasePlatform", databasePlatform);
@@ -2367,7 +2431,6 @@ public class ServerConfig {
dbEncrypt = createInstance(p, DbEncrypt.class, "dbEncrypt", dbEncrypt);
serverCachePlugin = createInstance(p, ServerCachePlugin.class, "serverCachePlugin", serverCachePlugin);
serverCacheManager = createInstance(p, ServerCacheManager.class, "serverCacheManager", serverCacheManager);
cacheWarmingDelay = p.getInt("cacheWarmingDelay", cacheWarmingDelay);
if (packages != null) {
String packagesProp = p.get("search.packages", p.get("packages", null));
@@ -2405,6 +2468,8 @@ public class ServerConfig {
asOfSysPeriod = p.get("asOfSysPeriod", asOfSysPeriod);
historyTableSuffix = p.get("historyTableSuffix", historyTableSuffix);
dataSourceJndiName = p.get("dataSourceJndiName", dataSourceJndiName);
jdbcFetchSizeFindEach = p.getInt("jdbcFetchSizeFindEach", jdbcFetchSizeFindEach);
jdbcFetchSizeFindList = p.getInt("jdbcFetchSizeFindList", jdbcFetchSizeFindList);
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
@@ -2427,6 +2492,7 @@ public class ServerConfig {
jsonDateTime = JsonConfig.DateTime.MILLIS;
}
h2ProductionMode = p.getBoolean("h2ProductionMode", h2ProductionMode);
ddlGenerate = p.getBoolean("ddl.generate", ddlGenerate);
ddlRun = p.getBoolean("ddl.run", ddlRun);
ddlCreateOnly = p.getBoolean("ddl.createOnly", ddlCreateOnly);
@@ -2455,7 +2521,7 @@ public class ServerConfig {
return classes;
}
List<Class<?>> classes = new ArrayList<Class<?>>();
List<Class<?>> classes = new ArrayList<>();
String[] split = classNames.split("[ ,;]");
for (int i = 0; i < split.length; i++) {
@@ -2474,7 +2540,7 @@ public class ServerConfig {
private List<String> getSearchJarsPackages(String searchPackages) {
List<String> hitList = new ArrayList<String>();
List<String> hitList = new ArrayList<>();
if (searchPackages != null) {
@@ -2489,13 +2555,14 @@ public class ServerConfig {
/**
* Return the PersistBatch mode to use for 'batchOnCascade' taking into account if the database
* platform supports getGeneratedKeys in batch mode.
* <p>
* Used to effectively turn off batchOnCascade for SQL Server - still allows explicit batch mode.
* </p>
*/
public PersistBatch appliedPersistBatchOnCascade() {
return databasePlatform.isDisallowBatchOnCascade() ? PersistBatch.NONE : persistBatchOnCascade;
if (persistBatchOnCascade == PersistBatch.INHERIT) {
// use the platform default (ALL except SQL Server which has NONE)
return databasePlatform.getPersistBatchOnCascade();
}
return persistBatchOnCascade;
}
/**
@@ -2571,18 +2638,45 @@ public class ServerConfig {
public enum DbUuid {
/**
* Store using native UUID in H2 and Postgres.
* Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40).
*/
AUTO,
AUTO_VARCHAR(true, false),
/**
* Store using DB VARCHAR.
* Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16).
*/
VARCHAR,
AUTO_BINARY(true, true),
/**
* Store using DB BINARY.
* Store using DB VARCHAR(40).
*/
BINARY
VARCHAR(false, false),
/**
* Store using DB BINARY(16).
*/
BINARY(false, true);
boolean nativeType;
boolean binary;
DbUuid(boolean nativeType, boolean binary) {
this.nativeType = nativeType;
this.binary = binary;
}
/**
* Return true if native UUID type is preferred.
*/
public boolean useNativeType() {
return nativeType;
}
/**
* Return true if BINARY(16) storage is preferred over VARCHAR(40).
*/
public boolean useBinary() {
return binary;
}
}
}
@@ -24,9 +24,9 @@ public class DB2Platform extends DatabasePlatform {
this.dbIdentity.setSupportsSequence(true);
booleanDbType = Types.BOOLEAN;
dbTypeMap.put(Types.REAL, new DbType("real"));
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 15));
dbTypeMap.put(DbType.REAL, new DbPlatformType("real"));
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 15));
}
/**
@@ -2,6 +2,9 @@ package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.Query;
import com.avaje.ebean.config.CustomDbTypeMapping;
import com.avaje.ebean.config.PersistBatch;
import com.avaje.ebean.config.Platform;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
@@ -14,7 +17,6 @@ import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Properties;
/**
* Database platform specific settings.
@@ -33,12 +35,6 @@ public class DatabasePlatform {
*/
ROLLBACK,
/**
* Just close the transaction. Valid at READ_COMMITTED isolation and preferred on some Databases
* as a performance optimisation.
*/
CLOSE,
/**
* Commit the transaction
*/
@@ -79,7 +75,7 @@ public class DatabasePlatform {
/**
* Mapping of JDBC to Database types.
*/
protected DbTypeMap dbTypeMap = new DbTypeMap();
protected DbPlatformTypeMapping dbTypeMap = new DbPlatformTypeMapping();
/**
* Default values for DB columns.
@@ -155,11 +151,9 @@ public class DatabasePlatform {
protected boolean forwardOnlyHintOnFindIterate;
/**
* Flag set for SQL Server due to lack of support of getGeneratedKeys in
* batch mode (meaning for batch inserts you should explicitly turn off
* getGeneratedKeys - joy).
* By default we use JDBC batch when cascading (except for SQL Server).
*/
protected boolean disallowBatchOnCascade;
protected PersistBatch persistBatchOnCascade = PersistBatch.ALL;
protected PlatformDdl platformDdl;
@@ -183,8 +177,31 @@ public class DatabasePlatform {
public DatabasePlatform() {
}
public void configure(Properties properties) {
// by default do nothing
/**
* Configure UUID Storage etc based on ServerConfig settings.
*/
public void configure(ServerConfig serverConfig) {
dbTypeMap.config(nativeUuidType, serverConfig.getDbUuid());
for (CustomDbTypeMapping mapping : serverConfig.getCustomTypeMappings()) {
if (platformMatch(mapping.getPlatform())) {
dbTypeMap.put(mapping.getType(), parse(mapping.getColumnDefinition()));
}
}
}
private DbPlatformType parse(String columnDefinition) {
return DbPlatformType.parse(columnDefinition);
}
private boolean platformMatch(Platform platform) {
return platform == null || platform.name().equalsIgnoreCase(name);
}
/**
* Return true if this matches the given platform.
*/
public boolean isPlatform(Platform platform) {
return platform.name().equalsIgnoreCase(name);
}
/**
@@ -314,7 +331,7 @@ public class DatabasePlatform {
*
* @return the db type map
*/
public DbTypeMap getDbTypeMap() {
public DbPlatformTypeMapping getDbTypeMap() {
return dbTypeMap;
}
@@ -542,14 +559,10 @@ public class DatabasePlatform {
}
/**
* Return true if the persistBatchOnCascade setting should be ignored.
* <p>
* This is primarily for SQL Server which does not support getGeneratedKeys with jdbc batch mode
* so can't really be transparently used.
* </p>
* Return the platform default JDBC batch mode for persist cascade.
*/
public boolean isDisallowBatchOnCascade() {
return disallowBatchOnCascade;
public PersistBatch getPersistBatchOnCascade() {
return persistBatchOnCascade;
}
/**
@@ -23,7 +23,7 @@ public class DbDefaultValue {
*/
public static final String NOW = "now";
protected Map<String,String> map = new LinkedHashMap<String,String>();
protected Map<String,String> map = new LinkedHashMap<>();
/**
* Set the DB now function.
@@ -135,9 +135,9 @@ public class DbIdentity {
return supportsSequence ? IdType.SEQUENCE : idType;
case IDENTITY:
return supportsIdentity ? IdType.IDENTITY : idType;
default:
return idType;
}
// use the default
return idType;
}
}
@@ -0,0 +1,158 @@
package com.avaje.ebean.config.dbplatform;
/**
* Represents a DB type with name, length, precision, and scale.
* <p>
* The length is for VARCHAR types and precision/scale for DECIMAL types.
* </p>
*/
public class DbPlatformType implements ExtraDbTypes {
/**
* The data type name (VARCHAR, INTEGER ...)
*/
private final String name;
/**
* The default length or precision.
*/
private final int defaultLength;
/**
* The default scale (decimal).
*/
private final int defaultScale;
/**
* Set to true if the type should never have a length or scale.
*/
private final boolean canHaveLength;
/**
* Parse a type definition into a DbPlatformType.
* <p>
* e.g. "decimal(18,6)"
* e.g. "text"
* </p>
*/
public static DbPlatformType parse(String columnDefinition) {
return DbPlatformTypeParser.parse(columnDefinition);
}
/**
* Construct with no length or scale.
*/
public DbPlatformType(String name) {
this(name, 0, 0);
}
/**
* Construct with a given length.
*/
public DbPlatformType(String name, int defaultLength) {
this(name, defaultLength, 0);
}
/**
* Construct for Decimal with precision and scale.
*/
public DbPlatformType(String name, int defaultPrecision, int defaultScale) {
this.name = name;
this.defaultLength = defaultPrecision;
this.defaultScale = defaultScale;
this.canHaveLength = true;
}
/**
* Use with canHaveLength=false for types that should never have a length.
*
* @param name
* the type name
* @param canHaveLength
* set this to false for type that should never have a length
*/
public DbPlatformType(String name, boolean canHaveLength) {
this.name = name;
this.defaultLength = 0;
this.defaultScale = 0;
this.canHaveLength = canHaveLength;
}
/**
* Return the type name.
*/
public String getName() {
return name;
}
/**
* Return the default length/precision.
*/
public int getDefaultLength() {
return defaultLength;
}
/**
* Return the default scale.
*/
public int getDefaultScale() {
return defaultScale;
}
/**
* Return the type for a specific property that incorporates the name, length,
* precision and scale.
* <p>
* The deployLength and deployScale are for the property we are rendering the
* DB type for.
* </p>
*
* @param deployLength
* the length or precision defined by deployment on a specific
* property.
* @param deployScale
* the scale defined by deployment on a specific property.
*/
public String renderType(int deployLength, int deployScale) {
return renderType(deployLength, deployScale, true);
}
/**
* Render the type defining strict mode.
* <p>
* If strict mode if OFF then this will render with a scale value even if
* that is not strictly supported. The reason for supporting this is to enable
* use to use types like jsonb(200) as a "logical" type that maps to JSONB for
* Postgres and VARCHAR(200) for other databases.
* </p>
*/
public String renderType(int deployLength, int deployScale, boolean strict) {
StringBuilder sb = new StringBuilder();
sb.append(name);
if (canHaveLength || !strict) {
// see if there is a precision/scale to add (or not)
int len = deployLength != 0 ? deployLength : defaultLength;
if (len > 0) {
sb.append("(");
sb.append(len);
int scale = deployScale != 0 ? deployScale : defaultScale;
if (scale > 0) {
sb.append(",");
sb.append(scale);
}
sb.append(")");
}
}
return sb.toString();
}
/**
* Create a copy of the type with a new default length.
*/
public DbPlatformType withLength(int defaultLength) {
return new DbPlatformType(name, defaultLength);
}
}
@@ -0,0 +1,53 @@
package com.avaje.ebean.config.dbplatform;
import java.util.HashMap;
import java.util.Map;
/**
* Helper to reverse lookup a DbType given the name or JDBC int value.
*/
class DbPlatformTypeLookup {
/**
* A map to lookup the type by name.
*/
private Map<String, DbType> nameLookup = new HashMap<>();
/**
* A map to lookup the type by JDBC int value.
*/
private Map<Integer, DbType> idLookup = new HashMap<>();
DbPlatformTypeLookup() {
addAll();
}
/**
* Return the DbType for the given name.
*/
DbType byName(String name) {
return nameLookup.get(name.trim().toUpperCase());
}
/**
* Return the DbType for the given name.
*/
DbType byId(int jdbcId) {
return idLookup.get(jdbcId);
}
private void addAll() {
// Extra mapping for Float and Varchar2
add("FLOAT", DbType.REAL);
add("VARCHAR2", DbType.VARCHAR);
for (DbType type : DbType.values()) {
add(type.name(), type);
}
}
private void add(String name, DbType dbType) {
nameLookup.put(name, dbType);
idLookup.put(dbType.id(), dbType);
}
}
@@ -0,0 +1,193 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.ServerConfig;
import java.util.HashMap;
import java.util.Map;
/**
* Used to map bean property types to DB specific types for DDL generation.
*/
public class DbPlatformTypeMapping {
private static DbPlatformTypeLookup lookup = new DbPlatformTypeLookup();
private static final DbPlatformType UUID_NATIVE = new DbPlatformType("uuid", false);
private static final DbPlatformType UUID_PLACEHOLDER = new DbPlatformType("uuidPlaceholder");
private static final DbPlatformType JSON_CLOB_PLACEHOLDER = new DbPlatformType("jsonClobPlaceholder");
private static final DbPlatformType JSON_BLOB_PLACEHOLDER = new DbPlatformType("jsonBlobPlaceholder");
private static final DbPlatformType JSON_VARCHAR_PLACEHOLDER = new DbPlatformType("jsonVarcharPlaceholder");
private static final DbPlatformType POINT = new DbPlatformType("point");
private static final DbPlatformType POLYGON = new DbPlatformType("polygon");
private static final DbPlatformType LINESTRING = new DbPlatformType("linestring");
private static final DbPlatformType MULTIPOINT = new DbPlatformType("multipoint");
private static final DbPlatformType MULTILINESTRING = new DbPlatformType("multilinestring");
private static final DbPlatformType MULTIPOLYGON = new DbPlatformType("multipolygon");
private final Map<DbType, DbPlatformType> typeMap = new HashMap<>();
/**
* Return the DbTypeMap with standard (not platform specific) types.
* <p>
* This has some extended JSON types (JSON, JSONB, JSONVarchar, JSONClob, JSONBlob).
* These types get translated to specific database platform types during DDL generation.
*/
public static DbPlatformTypeMapping logicalTypes() {
return new DbPlatformTypeMapping(true);
}
public DbPlatformTypeMapping() {
loadDefaults(false);
}
private DbPlatformTypeMapping(boolean logicalTypes) {
loadDefaults(logicalTypes);
}
/**
* Load the standard types. These can be overridden by DB specific platform.
*/
private void loadDefaults(boolean logicalTypes) {
put(DbType.BOOLEAN);
put(DbType.BIT);
put(DbType.INTEGER);
put(DbType.BIGINT);
put(DbType.DOUBLE);
put(DbType.SMALLINT);
put(DbType.TINYINT);
put(DbType.BLOB);
put(DbType.CLOB);
put(DbType.ARRAY);
put(DbType.DATE);
put(DbType.TIME);
put(DbType.TIMESTAMP);
put(DbType.LONGVARBINARY);
put(DbType.LONGVARCHAR);
// most commonly real maps to db float
put(DbType.REAL, new DbPlatformType("float"));
put(DbType.POINT, POINT);
put(DbType.POLYGON, POLYGON);
put(DbType.LINESTRING, LINESTRING);
put(DbType.MULTIPOINT, MULTIPOINT);
put(DbType.MULTILINESTRING, MULTILINESTRING);
put(DbType.MULTIPOLYGON, MULTIPOLYGON);
if (logicalTypes) {
// keep it logical for 2 layer DDL generation
put(DbType.VARCHAR, new DbPlatformType("varchar"));
put(DbType.DECIMAL, new DbPlatformType("decimal"));
put(DbType.VARBINARY, new DbPlatformType("varbinary"));
put(DbType.BINARY, new DbPlatformType("binary"));
put(DbType.CHAR, new DbPlatformType("char"));
put(DbType.HSTORE, new DbPlatformType("hstore", false));
put(DbType.JSON, new DbPlatformType("json", false));
put(DbType.JSONB, new DbPlatformType("jsonb", false));
put(DbType.JSONCLOB, new DbPlatformType("jsonclob"));
put(DbType.JSONBLOB, new DbPlatformType("jsonblob"));
put(DbType.JSONVARCHAR, new DbPlatformType("jsonvarchar", 1000));
put(DbType.UUID, UUID_NATIVE);
} else {
put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
put(DbType.DECIMAL, new DbPlatformType("decimal", 38));
put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
put(DbType.BINARY, new DbPlatformType("binary", 255));
put(DbType.CHAR, new DbPlatformType("char", 1));
put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON
put(DbType.JSONB, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSONB
put(DbType.JSONCLOB, JSON_CLOB_PLACEHOLDER);
put(DbType.JSONBLOB, JSON_BLOB_PLACEHOLDER);
put(DbType.JSONVARCHAR, JSON_VARCHAR_PLACEHOLDER);
put(DbType.UUID, UUID_PLACEHOLDER);
}
}
/**
* Lookup the platform specific DbType given the standard sql type name.
*/
public DbPlatformType lookup(String name, boolean withScale) {
DbType type = lookup.byName(name);
if (type == null) {
throw new IllegalArgumentException("Unknown type [" + name + "] - not standard sql type");
}
// handle JSON types mapped to clob, blob and varchar
switch (type) {
case JSONBLOB:
return get(DbType.BLOB);
case JSONCLOB:
return get(DbType.CLOB);
case JSONVARCHAR:
return get(DbType.VARCHAR);
case JSON:
return getJsonType(DbType.JSON, withScale);
case JSONB:
return getJsonType(DbType.JSONB, withScale);
default:
return get(type);
}
}
private DbPlatformType getJsonType(DbType type, boolean withScale) {
DbPlatformType dbType = get(type);
if (dbType == JSON_CLOB_PLACEHOLDER) {
// if we have scale that implies this maps to varchar
return withScale ? get(DbType.VARCHAR) : get(DbType.CLOB);
}
if (dbType == JSON_BLOB_PLACEHOLDER) {
return get(DbType.BLOB);
}
if (dbType == JSON_VARCHAR_PLACEHOLDER) {
return get(DbType.VARCHAR);
}
// Postgres has specific type
return get(type);
}
/**
* Override the type for a given JDBC type.
*/
private void put(DbType type) {
typeMap.put(type, type.createPlatformType());
}
/**
* Override the type for a given JDBC type.
*/
public void put(DbType type, DbPlatformType platformType) {
typeMap.put(type, platformType);
}
/**
* Return the type for a given jdbc type.
*/
public DbPlatformType get(int jdbcType) {
return get(lookup.byId(jdbcType));
}
/**
* Return the type for a given jdbc type.
*/
public DbPlatformType get(DbType dbType) {
return typeMap.get(dbType);
}
/**
* Map the UUID appropriately based on native DB support and ServerConfig.DbUuid.
*/
public void config(boolean nativeUuidType, ServerConfig.DbUuid dbUuid) {
if (nativeUuidType && dbUuid.useNativeType()) {
put(DbType.UUID, UUID_NATIVE);
} else if (dbUuid.useBinary()) {
put(DbType.UUID, get(DbType.BINARY).withLength(16));
} else {
put(DbType.UUID, get(DbType.VARCHAR).withLength(40));
}
}
}
@@ -0,0 +1,40 @@
package com.avaje.ebean.config.dbplatform;
/**
* Parse raw column definitions into DbPlatformType like "decimal(18,6)" and "varchar(20) and "json".
*/
class DbPlatformTypeParser {
/**
* Parse the column definition and return the DbPlatformType.
*/
static DbPlatformType parse(String columnDefinition) {
columnDefinition = columnDefinition.trim();
int openPos = columnDefinition.indexOf('(');
if (openPos == -1) {
return new DbPlatformType(columnDefinition, false);
}
int closePos = columnDefinition.indexOf(')', openPos);
if (closePos == -1) {
return new DbPlatformType(columnDefinition, false);
}
try {
int commaPos = columnDefinition.indexOf(',', openPos);
if (commaPos > -1) {
String type = columnDefinition.substring(0, openPos);
int scale = Integer.parseInt(columnDefinition.substring(openPos + 1, commaPos));
int precision = Integer.parseInt(columnDefinition.substring(commaPos + 1, closePos));
return new DbPlatformType(type, scale, precision);
} else {
String type = columnDefinition.substring(0, openPos);
int scale = Integer.parseInt(columnDefinition.substring(openPos + 1, closePos));
return new DbPlatformType(type, scale);
}
} catch (RuntimeException e) {
return new DbPlatformType(columnDefinition, false);
}
}
}
@@ -1,155 +1,72 @@
package com.avaje.ebean.config.dbplatform;
import java.sql.Types;
/**
* Represents a DB type with name, length, precision, and scale.
* The known DB types that are mapped.
* <p>
* The length is for VARCHAR types and precision/scale for DECIMAL types.
* This includes extra types such as UUID, JSON, JSONB and HSTORE.
* </p>
*/
public class DbType {
public enum DbType {
/**
* DB native UUID type (H2 and Postgres).
*/
public static final int UUID = 5010;
BOOLEAN(Types.BOOLEAN),
BIT(Types.BIT),
INTEGER(Types.INTEGER),
BIGINT(Types.BIGINT),
SMALLINT(Types.SMALLINT),
TINYINT(Types.TINYINT),
REAL(Types.REAL),
//FLOAT(Types.FLOAT),
DOUBLE(Types.DOUBLE),
DECIMAL(Types.DECIMAL),
VARCHAR(Types.VARCHAR),
CHAR(Types.CHAR),
BLOB(Types.BLOB),
CLOB(Types.CLOB),
LONGVARBINARY(Types.LONGVARBINARY),
LONGVARCHAR(Types.LONGVARCHAR),
VARBINARY(Types.VARBINARY),
BINARY(Types.BINARY),
DATE(Types.DATE),
TIME(Types.TIME),
TIMESTAMP(Types.TIMESTAMP),
/**
* Type to map Map content to Postgres HSTORE.
*/
public static final int HSTORE = 5000;
ARRAY(Types.ARRAY),
/**
* Type to map JSON content to Clob or Postgres JSON type.
*/
public static final int JSON = 5001;
UUID(ExtraDbTypes.UUID),
/**
* Type to map JSON content to Clob or Postgres JSONB type.
*/
public static final int JSONB = 5002;
POINT(ExtraDbTypes.POINT),
POLYGON(ExtraDbTypes.POLYGON),
LINESTRING(ExtraDbTypes.LINESTRING),
MULTIPOINT(ExtraDbTypes.MULTIPOINT),
MULTILINESTRING(ExtraDbTypes.MULTILINESTRING),
MULTIPOLYGON(ExtraDbTypes.MULTIPOLYGON),
/**
* Type to map JSON content to VARCHAR.
*/
public static final int JSONVarchar = 5003;
HSTORE(ExtraDbTypes.HSTORE),
JSON(ExtraDbTypes.JSON),
JSONB(ExtraDbTypes.JSONB),
JSONCLOB(ExtraDbTypes.JSONClob),
JSONBLOB(ExtraDbTypes.JSONBlob),
JSONVARCHAR(ExtraDbTypes.JSONVarchar);
/**
* Type to map JSON content to Clob.
*/
public static final int JSONClob = 5004;
private final int id;
/**
* Type to map JSON content to Blob.
*/
public static final int JSONBlob = 5005;
/**
* The data type name (VARCHAR, INTEGER ...)
*/
private final String name;
/**
* The default length or precision.
*/
private final int defaultLength;
/**
* The default scale (decimal).
*/
private final int defaultScale;
/**
* Set to true if the type should never have a length or scale.
*/
private final boolean canHaveLength;
/**
* Construct with no length or scale.
*/
public DbType(String name) {
this(name, 0, 0);
DbType(int id) {
this.id = id;
}
/**
* Construct with a given length.
* Return the JDBC java.sql.Types value.
*/
public DbType(String name, int defaultLength) {
this(name, defaultLength, 0);
public int id() {
return id;
}
/**
* Construct for Decimal with precision and scale.
* Create a platform type without scale or precision.
*/
public DbType(String name, int defaultPrecision, int defaultScale) {
this.name = name;
this.defaultLength = defaultPrecision;
this.defaultScale = defaultScale;
this.canHaveLength = true;
public DbPlatformType createPlatformType() {
return new DbPlatformType(name().toLowerCase());
}
/**
* Use with canHaveLength=false for types that should never have a length.
*
* @param name
* the type name
* @param canHaveLength
* set this to false for type that should never have a length
*/
public DbType(String name, boolean canHaveLength) {
this.name = name;
this.defaultLength = 0;
this.defaultScale = 0;
this.canHaveLength = canHaveLength;
}
/**
* Return the type for a specific property that incorporates the name, length,
* precision and scale.
* <p>
* The deployLength and deployScale are for the property we are rendering the
* DB type for.
* </p>
*
* @param deployLength
* the length or precision defined by deployment on a specific
* property.
* @param deployScale
* the scale defined by deployment on a specific property.
*/
public String renderType(int deployLength, int deployScale) {
return renderType(deployLength, deployScale, true);
}
/**
* Render the type defining strict mode.
* <p>
* If strict mode if OFF then this will render with a scale value even if
* that is not strictly supported. The reason for supporting this is to enable
* use to use types like jsonb(200) as a "logical" type that maps to JSONB for
* Postgres and VARCHAR(200) for other databases.
* </p>
*/
public String renderType(int deployLength, int deployScale, boolean strict) {
StringBuilder sb = new StringBuilder();
sb.append(name);
if (canHaveLength || !strict) {
// see if there is a precision/scale to add (or not)
int len = deployLength != 0 ? deployLength : defaultLength;
if (len > 0) {
sb.append("(");
sb.append(len);
int scale = deployScale != 0 ? deployScale : defaultScale;
if (scale > 0) {
sb.append(",");
sb.append(scale);
}
sb.append(")");
}
}
return sb.toString();
}
}
@@ -1,194 +0,0 @@
package com.avaje.ebean.config.dbplatform;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;
/**
* Used to map bean property types to DB specific types for DDL generation.
*/
public class DbTypeMap {
private static final DbType JSON_CLOB_PLACEHOLDER = new DbType("jsonClobPlaceholder");
private static final DbType JSON_BLOB_PLACEHOLDER = new DbType("jsonBlobPlaceholder");
private static final DbType JSON_VARCHAR_PLACEHOLDER = new DbType("jsonVarcharPlaceholder");
/**
* A map to reverse lookup the type by name.
* <p>
* Used when converting from logical types to platform types which we
* want to do with 2 phase DDL generation.
*/
static Map<String, Integer> lookup = new HashMap<String, Integer>();
static {
lookup.put("BOOLEAN", Types.BOOLEAN);
lookup.put("BIT", Types.BIT);
lookup.put("INTEGER", Types.INTEGER);
lookup.put("BIGINT", Types.BIGINT);
lookup.put("REAL", Types.REAL);
// Float is most common REAL mapping to have that as well
lookup.put("FLOAT", Types.REAL);
lookup.put("DOUBLE", Types.DOUBLE);
lookup.put("SMALLINT", Types.SMALLINT);
lookup.put("TINYINT", Types.TINYINT);
lookup.put("DECIMAL", Types.DECIMAL);
lookup.put("VARCHAR", Types.VARCHAR);
// VARCHAR2 - extra for Oracle specific column definition
lookup.put("VARCHAR2", Types.VARCHAR);
lookup.put("CHAR", Types.CHAR);
lookup.put("BLOB", Types.BLOB);
lookup.put("CLOB", Types.CLOB);
lookup.put("LONGVARBINARY", Types.LONGVARBINARY);
lookup.put("LONGVARCHAR", Types.LONGVARCHAR);
lookup.put("VARBINARY", Types.VARBINARY);
lookup.put("BINARY", Types.BINARY);
lookup.put("DATE", Types.DATE);
lookup.put("TIME", Types.TIME);
lookup.put("TIMESTAMP", Types.TIMESTAMP);
lookup.put("ARRAY", Types.ARRAY);
lookup.put("UUID", DbType.UUID);
// Not standard java.sql.Types
// logical JSON storage types
lookup.put("JSON", DbType.JSON);
lookup.put("JSONB", DbType.JSONB);
lookup.put("JSONCLOB", DbType.JSONClob);
lookup.put("JSONBLOB", DbType.JSONBlob);
lookup.put("JSONVARCHAR", DbType.JSONVarchar);
}
private final Map<Integer, DbType> typeMap = new HashMap<Integer, DbType>();
/**
* Return the DbTypeMap with standard (not platform specific) types.
*
* This has some extended JSON types (JSON, JSONB, JSONVarchar, JSONClob, JSONBlob).
* These types get translated to specific database platform types during DDL generation.
*/
public static DbTypeMap logicalTypes() {
return new DbTypeMap(true);
}
public DbTypeMap() {
loadDefaults(false);
}
private DbTypeMap(boolean logicalTypes) {
loadDefaults(logicalTypes);
}
/**
* Load the standard types. These can be overridden by DB specific platform.
*/
private void loadDefaults(boolean logicalTypes) {
put(Types.BOOLEAN, new DbType("boolean"));
put(Types.BIT, new DbType("bit"));
put(Types.INTEGER, new DbType("integer"));
put(Types.BIGINT, new DbType("bigint"));
put(Types.REAL, new DbType("float"));
put(Types.DOUBLE, new DbType("double"));
put(Types.SMALLINT, new DbType("smallint"));
put(Types.TINYINT, new DbType("tinyint"));
put(Types.DECIMAL, new DbType("decimal", 38));
put(Types.VARCHAR, new DbType("varchar", 255));
put(Types.CHAR, new DbType("char", 1));
put(Types.BLOB, new DbType("blob"));
put(Types.CLOB, new DbType("clob"));
// DB native UUID support (H2 and Postgres)
put(DbType.UUID, new DbType("uuid"));
put(Types.ARRAY, new DbType("array"));
if (logicalTypes) {
// keep it logical for 2 layer DDL generation
put(DbType.HSTORE, new DbType("hstore", false));
put(DbType.JSON, new DbType("json", false));
put(DbType.JSONB, new DbType("jsonb", false));
put(DbType.JSONClob, new DbType("jsonclob"));
put(DbType.JSONBlob, new DbType("jsonblob"));
put(DbType.JSONVarchar, new DbType("jsonvarchar", 1000));
} else {
put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON
put(DbType.JSONB, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSONB
put(DbType.JSONClob, JSON_CLOB_PLACEHOLDER);
put(DbType.JSONBlob, JSON_BLOB_PLACEHOLDER);
put(DbType.JSONVarchar, JSON_VARCHAR_PLACEHOLDER);
}
put(Types.LONGVARBINARY, new DbType("longvarbinary"));
put(Types.LONGVARCHAR, new DbType("lonvarchar"));
put(Types.VARBINARY, new DbType("varbinary", 255));
put(Types.BINARY, new DbType("binary", 255));
put(Types.DATE, new DbType("date"));
put(Types.TIME, new DbType("time"));
put(Types.TIMESTAMP, new DbType("timestamp"));
}
/**
* Lookup the platform specific DbType given the standard sql type name.
*/
public DbType lookup(String name, boolean withScale) {
name = name.trim().toUpperCase();
Integer typeKey = lookup.get(name);
if (typeKey == null) {
throw new IllegalArgumentException("Unknown type [" + name + "] - not standard sql type");
}
// handle JSON types mapped to clob, blob and varchar
switch (typeKey) {
case DbType.JSONBlob:
return get(Types.BLOB);
case DbType.JSONClob:
return get(Types.CLOB);
case DbType.JSONVarchar:
return get(Types.VARCHAR);
case DbType.JSON:
return getJsonType(DbType.JSON, withScale);
case DbType.JSONB:
return getJsonType(DbType.JSONB, withScale);
default:
return get(typeKey);
}
}
private DbType getJsonType(int type, boolean withScale) {
DbType dbType = get(type);
if (dbType == JSON_CLOB_PLACEHOLDER) {
// if we have scale that implies this maps to varchar
return withScale ? get(Types.VARCHAR) : get(Types.CLOB);
}
if (dbType == JSON_BLOB_PLACEHOLDER) {
return get(Types.BLOB);
}
if (dbType == JSON_VARCHAR_PLACEHOLDER) {
return get(Types.VARCHAR);
}
// Postgres has specific type
return get(type);
}
/**
* Override the type for a given JDBC type.
*/
public void put(int jdbcType, DbType dbType) {
typeMap.put(jdbcType, dbType);
}
/**
* Return the type for a given jdbc type.
*/
public DbType get(int jdbcType) {
return typeMap.get(jdbcType);
}
}
@@ -0,0 +1,73 @@
package com.avaje.ebean.config.dbplatform;
/**
* Integer codes for the extra types beyond java.sql.Types.
*/
public interface ExtraDbTypes {
/**
* DB native UUID type (H2 and Postgres).
*/
int UUID = 5010;
/**
* Type to map Map content to Postgres HSTORE.
*/
int HSTORE = 5000;
/**
* Type to map JSON content to Clob or Postgres JSON type.
*/
int JSON = 5001;
/**
* Type to map JSON content to Clob or Postgres JSONB type.
*/
int JSONB = 5002;
/**
* Type to map JSON content to VARCHAR.
*/
int JSONVarchar = 5003;
/**
* Type to map JSON content to Clob.
*/
int JSONClob = 5004;
/**
* Type to map JSON content to Blob.
*/
int JSONBlob = 5005;
/**
* Geo Point
*/
int POINT = 6000;
/**
* Geo Polygon
*/
int POLYGON = 6001;
/**
* Geo Point
*/
int LINESTRING = 6002;
/**
* Geo MultiPolygon
*/
int MULTIPOINT = 6005;
/**
* Geo MultiPolygon
*/
int MULTIPOLYGON = 6006;
/**
* Geo MultiPolygon
*/
int MULTILINESTRING = 6007;
}
@@ -9,9 +9,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* H2 database trigger used to populate history tables to support the @History feature.
@@ -54,7 +52,6 @@ public class H2HistoryTrigger implements Trigger {
insertSql.append("insert into ").append(tableName).append(HISTORY_SUFFIX).append(" (");
int count = 0;
List<String> columns = new ArrayList<String>();
while (rs.next()) {
if (++count > 1) {
insertSql.append(",");
@@ -66,7 +63,6 @@ public class H2HistoryTrigger implements Trigger {
this.effectEndPosition = count - 1;
}
insertSql.append(columnName);
columns.add(columnName);
}
insertSql.append(") values (");
for (int i = 0; i < count; i++) {
@@ -1,9 +1,11 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.H2Ddl;
import javax.sql.DataSource;
import java.util.Properties;
/**
* H2 specific platform.
@@ -19,9 +21,7 @@ public class H2Platform extends DatabasePlatform {
this.nativeUuidType = true;
this.dbDefaultValue.setNow("now()");
// only support getGeneratedKeys with non-batch JDBC
// so generally use SEQUENCE instead of IDENTITY for H2
this.dbIdentity.setIdType(IdType.SEQUENCE);
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsSequence(true);
this.dbIdentity.setSupportsIdentity(true);
@@ -34,6 +34,18 @@ public class H2Platform extends DatabasePlatform {
// so no changes to dbTypeMap required
}
@Override
public void configure(ServerConfig serverConfig) {
super.configure(serverConfig);
Properties properties = serverConfig.getProperties();
if (properties != null) {
String idType = properties.getProperty("ebean.h2.idtype");
if (idType != null) {
this.dbIdentity.setIdType(IdType.valueOf(idType));
}
}
}
/**
* Return a H2 specific sequence IdGenerator that supports batch fetching
* sequence values.
@@ -4,7 +4,6 @@ import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.HsqldbDdl;
import javax.sql.DataSource;
import java.sql.Types;
/**
* H2 specific platform.
@@ -22,7 +21,7 @@ public class HsqldbPlatform extends DatabasePlatform {
this.dbIdentity.setSupportsSequence(true);
this.dbIdentity.setSupportsIdentity(true);
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
}
@Override
@@ -1,6 +1,6 @@
package com.avaje.ebean.config.dbplatform;
import java.sql.Types;
import com.avaje.ebean.config.PersistBatch;
/**
* Microsoft SQL Server 2000 specific platform.
@@ -18,6 +18,7 @@ public class MsSqlServer2000Platform extends DatabasePlatform {
public MsSqlServer2000Platform() {
super();
this.name = "mssqlserver2000";
this.persistBatchOnCascade = PersistBatch.NONE;
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(false);
this.dbIdentity.setSelectLastInsertedIdTemplate("select @@IDENTITY as X");
@@ -26,22 +27,22 @@ public class MsSqlServer2000Platform extends DatabasePlatform {
this.openQuote = "[";
this.closeQuote = "]";
dbTypeMap.put(Types.BOOLEAN, new DbType("bit default 0"));
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0"));
dbTypeMap.put(Types.BIGINT, new DbType("numeric", 19));
dbTypeMap.put(Types.REAL, new DbType("float(16)"));
dbTypeMap.put(Types.DOUBLE, new DbType("float(32)"));
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
dbTypeMap.put(Types.DECIMAL, new DbType("numeric", 28));
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("numeric", 19));
dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)"));
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float(32)"));
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28));
dbTypeMap.put(Types.BLOB, new DbType("image"));
dbTypeMap.put(Types.CLOB, new DbType("text"));
dbTypeMap.put(Types.LONGVARBINARY, new DbType("image"));
dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
dbTypeMap.put(DbType.BLOB, new DbPlatformType("image"));
dbTypeMap.put(DbType.CLOB, new DbPlatformType("text"));
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("image"));
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("text"));
dbTypeMap.put(Types.DATE, new DbType("datetime"));
dbTypeMap.put(Types.TIME, new DbType("datetime"));
dbTypeMap.put(Types.TIMESTAMP, new DbType("datetime"));
dbTypeMap.put(DbType.DATE, new DbPlatformType("datetime"));
dbTypeMap.put(DbType.TIME, new DbPlatformType("datetime"));
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime"));
}
@@ -1,9 +1,8 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.PersistBatch;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.MsSqlServerDdl;
import java.sql.Types;
/**
* Microsoft SQL Server 2005 specific platform.
* <p>
@@ -21,7 +20,7 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
this.name = "mssqlserver2005";
// effectively disable persistBatchOnCascade mode for SQL Server
// due to lack of support for getGeneratedKeys in batch mode
this.disallowBatchOnCascade = true;
this.persistBatchOnCascade = PersistBatch.NONE;
this.idInExpandedForm = true;
this.selectCountWithAlias = true;
this.sqlLimiter = new MsSqlServer2005SqlLimiter();
@@ -33,23 +32,23 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
this.openQuote = "[";
this.closeQuote = "]";
dbTypeMap.put(Types.BOOLEAN, new DbType("bit default 0"));
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0"));
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
dbTypeMap.put(Types.BIGINT, new DbType("numeric", 19));
dbTypeMap.put(Types.REAL, new DbType("float(16)"));
dbTypeMap.put(Types.DOUBLE, new DbType("float(32)"));
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
dbTypeMap.put(Types.DECIMAL, new DbType("numeric", 28));
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("numeric", 19));
dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)"));
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float(32)"));
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28));
dbTypeMap.put(Types.BLOB, new DbType("image"));
dbTypeMap.put(Types.CLOB, new DbType("text"));
dbTypeMap.put(Types.LONGVARBINARY, new DbType("image"));
dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
dbTypeMap.put(DbType.BLOB, new DbPlatformType("image"));
dbTypeMap.put(DbType.CLOB, new DbPlatformType("text"));
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("image"));
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("text"));
dbTypeMap.put(Types.DATE, new DbType("date"));
dbTypeMap.put(Types.TIME, new DbType("time"));
dbTypeMap.put(Types.TIMESTAMP, new DbType("datetime2"));
dbTypeMap.put(DbType.DATE, new DbPlatformType("date"));
dbTypeMap.put(DbType.TIME, new DbPlatformType("time"));
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime2"));
}
@@ -7,7 +7,7 @@ package com.avaje.ebean.config.dbplatform;
* If no deployment length is defined longblob is used.
* </p>
*/
public class MySqlBlob extends DbType {
public class MySqlBlob extends DbPlatformType {
private static final int POWER_2_16 = 65536;
private static final int POWER_2_24 = 16777216;
@@ -7,7 +7,7 @@ package com.avaje.ebean.config.dbplatform;
* If no deployment length is defined longtext is used.
* </p>
*/
public class MySqlClob extends DbType {
public class MySqlClob extends DbPlatformType {
private static final int POWER_2_16 = 65536;
private static final int POWER_2_24 = 16777216;
@@ -39,13 +39,13 @@ public class MySqlPlatform extends DatabasePlatform {
this.forwardOnlyHintOnFindIterate = true;
this.booleanDbType = Types.BIT;
dbTypeMap.put(Types.BIT, new DbType("tinyint(1) default 0"));
dbTypeMap.put(Types.BOOLEAN, new DbType("tinyint(1) default 0"));
dbTypeMap.put(Types.TIMESTAMP, new DbType("datetime(6)"));
dbTypeMap.put(Types.CLOB, new MySqlClob());
dbTypeMap.put(Types.BLOB, new MySqlBlob());
dbTypeMap.put(Types.BINARY, new DbType("binary", 255));
dbTypeMap.put(Types.VARBINARY, new DbType("varbinary", 255));
dbTypeMap.put(DbType.BIT, new DbPlatformType("tinyint(1) default 0"));
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("tinyint(1) default 0"));
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime(6)"));
dbTypeMap.put(DbType.CLOB, new MySqlClob());
dbTypeMap.put(DbType.BLOB, new MySqlBlob());
dbTypeMap.put(DbType.BINARY, new DbPlatformType("binary", 255));
dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
}
/**
@@ -34,24 +34,24 @@ public class OraclePlatform extends DatabasePlatform {
this.closeQuote = "\"";
booleanDbType = Types.INTEGER;
dbTypeMap.put(Types.BOOLEAN, new DbType("number(1) default 0"));
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("number(1) default 0"));
dbTypeMap.put(Types.INTEGER, new DbType("number", 10));
dbTypeMap.put(Types.BIGINT, new DbType("number", 19));
dbTypeMap.put(Types.REAL, new DbType("number", 19, 4));
dbTypeMap.put(Types.DOUBLE, new DbType("number", 19, 4));
dbTypeMap.put(Types.SMALLINT, new DbType("number", 5));
dbTypeMap.put(Types.TINYINT, new DbType("number", 3));
dbTypeMap.put(Types.DECIMAL, new DbType("number", 38));
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("number", 10));
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("number", 19));
dbTypeMap.put(DbType.REAL, new DbPlatformType("number", 19, 4));
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("number", 19, 4));
dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("number", 5));
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("number", 3));
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("number", 38));
dbTypeMap.put(Types.VARCHAR, new DbType("varchar2", 255));
dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("varchar2", 255));
dbTypeMap.put(Types.LONGVARBINARY, new DbType("blob"));
dbTypeMap.put(Types.LONGVARCHAR, new DbType("clob"));
dbTypeMap.put(Types.VARBINARY, new DbType("raw", 255));
dbTypeMap.put(Types.BINARY, new DbType("raw", 255));
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("blob"));
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("clob"));
dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("raw", 255));
dbTypeMap.put(DbType.BINARY, new DbPlatformType("raw", 255));
dbTypeMap.put(Types.TIME, new DbType("timestamp"));
dbTypeMap.put(DbType.TIME, new DbPlatformType("timestamp"));
}
@Override
@@ -41,36 +41,53 @@ public class PostgresPlatform extends DatabasePlatform {
this.openQuote = "\"";
this.closeQuote = "\"";
DbType dbTypeText = new DbType("text");
DbType dbBytea = new DbType("bytea", false);
DbPlatformType dbTypeText = new DbPlatformType("text");
DbPlatformType dbBytea = new DbPlatformType("bytea", false);
dbTypeMap.put(DbType.HSTORE, new DbType("hstore", false));
dbTypeMap.put(DbType.JSON, new DbType("json", false));
dbTypeMap.put(DbType.JSONB, new DbType("jsonb", 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));
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
dbTypeMap.put(Types.DOUBLE, new DbType("float"));
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 38));
dbTypeMap.put(Types.TIMESTAMP, new DbType("timestamptz"));
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float"));
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 38));
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("timestamptz"));
dbTypeMap.put(Types.BINARY, dbBytea);
dbTypeMap.put(Types.VARBINARY, dbBytea);
dbTypeMap.put(DbType.BINARY, dbBytea);
dbTypeMap.put(DbType.VARBINARY, dbBytea);
dbTypeMap.put(Types.BLOB, dbBytea);
dbTypeMap.put(Types.CLOB, dbTypeText);
dbTypeMap.put(Types.LONGVARBINARY, dbBytea);
dbTypeMap.put(Types.LONGVARCHAR, dbTypeText);
dbTypeMap.put(DbType.BLOB, dbBytea);
dbTypeMap.put(DbType.CLOB, dbTypeText);
dbTypeMap.put(DbType.LONGVARBINARY, dbBytea);
dbTypeMap.put(DbType.LONGVARCHAR, dbTypeText);
}
@Override
public void configure(Properties properties) {
super.configure(properties);
String tsType = properties.getProperty("ebean.postgres.timestamp");
if (tsType != null) {
// set timestamp type to "timestamp" without time zone
dbTypeMap.put(Types.TIMESTAMP, new DbType(tsType));
public void configure(ServerConfig serverConfig) {
super.configure(serverConfig);
Properties properties = serverConfig.getProperties();
if (properties != null) {
String tsType = properties.getProperty("ebean.postgres.timestamp");
if (tsType != null) {
// set timestamp type to "timestamp" without time zone
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType(tsType));
}
}
addGeoTypes(serverConfig.getGeometrySRID());
}
private void addGeoTypes(int srid) {
dbTypeMap.put(DbType.POINT, geoType("point",srid));
dbTypeMap.put(DbType.POLYGON, geoType("polygon",srid));
dbTypeMap.put(DbType.LINESTRING, geoType("linestring",srid));
dbTypeMap.put(DbType.MULTIPOINT, geoType("multipoint",srid));
dbTypeMap.put(DbType.MULTILINESTRING, geoType("multilinestring",srid));
dbTypeMap.put(DbType.MULTIPOLYGON, geoType("multipolygon",srid));
}
private DbPlatformType geoType(String type, int srid) {
return new DbPlatformType("geometry("+type+","+srid+")");
}
/**
@@ -18,10 +18,10 @@ public class SQLitePlatform extends DatabasePlatform {
this.booleanDbType = Types.INTEGER;
dbTypeMap.put(Types.BIT, new DbType("int default 0"));
dbTypeMap.put(Types.BOOLEAN, new DbType("int default 0"));
dbTypeMap.put(Types.BIGINT, new DbType("integer"));
dbTypeMap.put(Types.SMALLINT, new DbType("integer"));
dbTypeMap.put(DbType.BIT, new DbPlatformType("int default 0"));
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("int default 0"));
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("integer"));
dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("integer"));
}
@@ -40,7 +40,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
protected final BackgroundExecutor backgroundExecutor;
protected final ArrayList<Long> idList = new ArrayList<Long>(50);
protected final ArrayList<Long> idList = new ArrayList<>(50);
protected final int batchSize;
@@ -98,11 +98,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
protected void loadLargeAllocation(final int allocateSize) {
// preAllocateIds was called with a relatively large batchSize
// so we will just go ahead and load those anyway in background
backgroundExecutor.execute(new Runnable() {
public void run() {
loadMoreIds(allocateSize, null);
}
});
backgroundExecutor.execute(() -> loadMoreIds(allocateSize, null));
}
/**
@@ -145,12 +141,10 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
currentlyBackgroundLoading = batchSize;
backgroundExecutor.execute(new Runnable() {
public void run() {
loadMoreIds(batchSize, null);
synchronized (backgroundLoadMonitor) {
currentlyBackgroundLoading = 0;
}
backgroundExecutor.execute(() -> {
loadMoreIds(batchSize, null);
synchronized (backgroundLoadMonitor) {
currentlyBackgroundLoading = 0;
}
});
}
@@ -178,7 +172,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
String sql = getSql(loadSize);
ArrayList<Long> newIds = new ArrayList<Long>(loadSize);
ArrayList<Long> newIds = new ArrayList<>(loadSize);
boolean useTxnConnection = t != null;
@@ -1,7 +1,5 @@
package com.avaje.ebean.config.dbplatform;
import java.sql.Types;
/**
* Sybase SQL Anywhere specific platform.
* <p>
@@ -23,17 +21,17 @@ public class SqlAnywherePlatform extends DatabasePlatform {
this.dbIdentity.setSelectLastInsertedIdTemplate("select @@IDENTITY as X");
this.dbIdentity.setSupportsIdentity(true);
dbTypeMap.put(Types.BOOLEAN, new DbType("bit default 0"));
dbTypeMap.put(Types.BIGINT, new DbType("numeric", 19));
dbTypeMap.put(Types.REAL, new DbType("float(16)"));
dbTypeMap.put(Types.DOUBLE, new DbType("float(32)"));
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
dbTypeMap.put(Types.DECIMAL, new DbType("numeric", 28));
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0"));
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("numeric", 19));
dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)"));
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float(32)"));
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28));
dbTypeMap.put(Types.BLOB, new DbType("binary(4500)"));
dbTypeMap.put(Types.CLOB, new DbType("long varchar"));
dbTypeMap.put(Types.LONGVARBINARY, new DbType("long binary"));
dbTypeMap.put(Types.LONGVARCHAR, new DbType("long varchar"));
dbTypeMap.put(DbType.BLOB, new DbPlatformType("binary(4500)"));
dbTypeMap.put(DbType.CLOB, new DbPlatformType("long varchar"));
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("long binary"));
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("long varchar"));
}
@@ -7,7 +7,7 @@ import com.avaje.ebean.config.DbMigrationConfig;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DB2Platform;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbPlatformName;
import com.avaje.ebean.config.Platform;
import com.avaje.ebean.config.dbplatform.H2Platform;
import com.avaje.ebean.config.dbplatform.MsSqlServer2005Platform;
import com.avaje.ebean.config.dbplatform.MySqlPlatform;
@@ -79,7 +79,7 @@ public class DbMigration {
protected DatabasePlatform databasePlatform;
protected List<Pair> platforms = new ArrayList<Pair>();
protected List<Pair> platforms = new ArrayList<>();
protected ServerConfig serverConfig;
@@ -139,7 +139,7 @@ public class DbMigration {
* If not set this defaults to the platform of the default server.
* </p>
*/
public void setPlatform(DbPlatformName platform) {
public void setPlatform(Platform platform) {
setPlatform(getPlatform(platform));
}
@@ -163,10 +163,7 @@ public class DbMigration {
* from the migration (e.g. generate migration sql for MySql, Postgres and Oracle).
* </p>
*/
public void addPlatform(DbPlatformName platform, String prefix) {
if (!prefix.endsWith("-")) {
prefix += "-";
}
public void addPlatform(Platform platform, String prefix) {
platforms.add(new Pair(getPlatform(platform), prefix));
}
@@ -204,13 +201,20 @@ public class DbMigration {
// use this flag to stop other plugins like full DDL generation
if (!online) {
DbOffline.setRunningMigration();
DbOffline.setGenerateMigration();
if (databasePlatform == null && !platforms.isEmpty()) {
// for multiple platform generation set the general platform
// to H2 so that it runs offline without DB connection
setPlatform(platforms.get(0).platform);
}
}
setDefaults();
try {
Request request = createRequest();
generateExtraDdl(request);
if (platforms.isEmpty()) {
generateExtraDdl(request.migrationDir, databasePlatform);
}
String pendingVersion = generatePendingDrop();
if (pendingVersion != null) {
@@ -234,15 +238,15 @@ public class DbMigration {
* migration runner.
* </p>
*/
private void generateExtraDdl(Request request) throws IOException {
private void generateExtraDdl(File migrationDir, DatabasePlatform dbPlatform) throws IOException {
if (databasePlatform != null) {
if (dbPlatform != null) {
ExtraDdl extraDdl = ExtraDdlXmlReader.read("/extra-ddl.xml");
if (extraDdl != null) {
List<DdlScript> ddlScript = extraDdl.getDdlScript();
for (DdlScript script : ddlScript) {
if (ExtraDdlXmlReader.matchPlatform(databasePlatform.getName(), script.getPlatforms())) {
writeExtraDdl(request, script);
if (ExtraDdlXmlReader.matchPlatform(dbPlatform.getName(), script.getPlatforms())) {
writeExtraDdl(migrationDir, script);
}
}
}
@@ -252,13 +256,13 @@ public class DbMigration {
/**
* Write (or override) the "repeatable" migration script.
*/
private void writeExtraDdl(Request request, DdlScript script) throws IOException {
private void writeExtraDdl(File migrationDir, DdlScript script) throws IOException {
String fullName = repeatableMigrationName(script.getName());
logger.info("writing repeatable script {}", fullName);
File file = new File(request.migrationDir, fullName);
File file = new File(migrationDir, fullName);
FileWriter writer = new FileWriter(file);
writer.write(script.getValue());
writer.flush();
@@ -363,14 +367,16 @@ public class DbMigration {
logger.warn("migration already exists, not generating DDL");
} else {
if (databasePlatform != null) {
if (!platforms.isEmpty()) {
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
} else if (databasePlatform != null) {
// writer needs the current model to provide table/column details for
// history ddl generation (triggers, history tables etc)
DdlWrite write = new DdlWrite(new MConfiguration(), request.current);
PlatformDdlWriter writer = createDdlWriter(databasePlatform, "");
writer.processMigration(dbMigration, write, request.migrationDir, fullVersion);
}
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
}
}
@@ -426,7 +432,10 @@ public class DbMigration {
for (Pair pair : platforms) {
DdlWrite platformBuffer = new DdlWrite(new MConfiguration(), currentModel.read());
PlatformDdlWriter platformWriter = createDdlWriter(pair);
platformWriter.processMigration(dbMigration, platformBuffer, writePath, fullVersion);
File subPath = platformWriter.subPath(writePath, pair.prefix);
platformWriter.processMigration(dbMigration, platformBuffer, subPath, fullVersion);
generateExtraDdl(subPath, pair.platform);
}
}
@@ -506,7 +515,7 @@ public class DbMigration {
/**
* Return the DatabasePlatform given the platform key.
*/
protected DatabasePlatform getPlatform(DbPlatformName platform) {
protected DatabasePlatform getPlatform(Platform platform) {
switch (platform) {
case H2:
return new H2Platform();
@@ -1,6 +1,6 @@
package com.avaje.ebean.dbmigration;
import com.avaje.ebean.config.dbplatform.DbPlatformName;
import com.avaje.ebean.config.Platform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -14,12 +14,12 @@ public class DbOffline {
private static final String KEY = "ebean.dboffline";
private static boolean runningMigration;
private static boolean generateMigration;
/**
* Set the platform to use when creating the next EbeanServer instance.
*/
public static void setPlatform(DbPlatformName dbPlatform) {
public static void setPlatform(Platform dbPlatform) {
System.setProperty(KEY, dbPlatform.name());
}
@@ -41,7 +41,7 @@ public class DbOffline {
* Bring up the next EbeanServer instance using the H2 platform.
*/
public static void asH2() {
setPlatform(DbPlatformName.H2);
setPlatform(Platform.H2);
}
/**
@@ -55,23 +55,23 @@ public class DbOffline {
* Return true if the migration is running. This typically means don't run the
* plugins like full DDL generation.
*/
public static boolean isRunningMigration() {
return runningMigration;
public static boolean isGenerateMigration() {
return generateMigration;
}
/**
* Called when the migration is running is order to stop other plugins
* like the full DDL generation from executing.
*/
public static void setRunningMigration() {
runningMigration = true;
public static void setGenerateMigration() {
generateMigration = true;
}
/**
* Reset the offline platform and runningMigration flag.
*/
public static void reset() {
runningMigration = false;
generateMigration = false;
System.clearProperty(KEY);
logger.debug("reset");
}
@@ -96,7 +96,13 @@ public class DdlGenerator {
Transaction transaction = server.createTransaction();
Connection connection = transaction.getConnection();
try {
if (expectErrors) {
connection.setAutoCommit(true);
}
int count = runner.runAll(content, connection);
if (expectErrors) {
connection.setAutoCommit(false);
}
transaction.commit();
return count;
@@ -53,7 +53,7 @@ public class BaseTableDdl implements TableDdl {
/**
* Used when unique constraints specifically for OneToOne can't be created normally (MsSqlServer).
*/
protected List<Column> externalUnique = new ArrayList<Column>();
protected List<Column> externalUnique = new ArrayList<>();
// counters used when constraint names are truncated due to maximum length
// and these counters are used to keep the constraint name unique
@@ -66,7 +66,7 @@ public class BaseTableDdl implements TableDdl {
* Base tables that have associated history tables that need their triggers/functions regenerated as
* columns have been added, removed, included or excluded.
*/
protected Map<String, HistoryTableUpdate> regenerateHistoryTriggers = new LinkedHashMap<String, HistoryTableUpdate>();
protected Map<String, HistoryTableUpdate> regenerateHistoryTriggers = new LinkedHashMap<>();
/**
* Construct with a naming convention and platform specific DDL.
@@ -499,7 +499,7 @@ public class BaseTableDdl implements TableDdl {
* Return the list of columns that make the primary key.
*/
protected List<Column> determinePrimaryKeyColumns(List<Column> columns) {
List<Column> pk = new ArrayList<Column>(3);
List<Column> pk = new ArrayList<>(3);
for (Column column : columns) {
if (isTrue(column.isPrimaryKey())) {
pk.add(column);
@@ -583,6 +583,12 @@ public class BaseTableDdl implements TableDdl {
}
}
for (Column column : columns) {
if (hasValue(column.getReferences())) {
writeForeignKey(writer, tableName, column);
}
}
// add a bit of whitespace
writer.apply().end();
}
@@ -831,9 +837,10 @@ public class BaseTableDdl implements TableDdl {
protected void alterTableAddColumn(DdlBuffer buffer, String tableName, Column column, boolean onHistoryTable) throws IOException {
String convertedType = platformDdl.convert(column.getType(), false);
buffer.append("alter table ").append(tableName)
.append(" add column ").append(column.getName())
.append(" ").append(column.getType());
.append(" ").append(convertedType);
if (!onHistoryTable) {
if (isTrue(column.isNotnull())) {
@@ -43,7 +43,7 @@ public class HistoryTableUpdate {
private final String baseTable;
private final List<Column> columnChanges = new ArrayList<Column>();
private final List<Column> columnChanges = new ArrayList<>();
/**
* Construct with a given base table name.
@@ -11,6 +11,8 @@ public class Oracle10Ddl extends PlatformDdl {
super(platform);
this.dropTableIfExists = "drop table ";
this.dropSequenceIfExists = "drop sequence ";
this.dropConstraintIfExists = "drop constraint";
this.dropIndexIfExists = "drop index ";
this.dropTableCascade = " cascade constraints purge";
this.foreignKeyRestrict = "";
this.alterColumn = "modify";
@@ -26,6 +26,8 @@ import java.util.List;
*/
public class PlatformDdl {
protected final DatabasePlatform platform;
protected PlatformHistoryDdl historyDdl = new NoHistorySupportDdl();
/**
@@ -98,6 +100,7 @@ public class PlatformDdl {
protected final DbDefaultValue dbDefaultValue;
public PlatformDdl(DatabasePlatform platform) {
this.platform = platform;
this.dbIdentity = platform.getDbIdentity();
this.dbDefaultValue = platform.getDbDefaultValue();
this.typeConverter = new PlatformTypeConverter(platform.getDbTypeMap());
@@ -1,6 +1,7 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@@ -8,7 +9,7 @@ import java.util.List;
*/
public class IndexColumns {
List<String> columns = new ArrayList<String>(4);
List<String> columns = new ArrayList<>(4);
/**
* Construct representing as a single column index.
@@ -21,9 +22,7 @@ public class IndexColumns {
* Construct representing index.
*/
public IndexColumns(String[] columnNames) {
for (int i = 0; i < columnNames.length; i++) {
columns.add(columnNames[i]);
}
Collections.addAll(columns, columnNames);
}
/**
@@ -11,7 +11,7 @@ import java.util.List;
*/
public class IndexSet {
private List<IndexColumns> indexes = new ArrayList<IndexColumns>();
private List<IndexColumns> indexes = new ArrayList<>();
/**
* Clear the indexes (for each table).
@@ -1,7 +1,7 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform.util;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
import com.avaje.ebean.config.dbplatform.DbPlatformTypeMapping;
/**
* Converts a logical column definition into platform specific one.
@@ -10,12 +10,12 @@ import com.avaje.ebean.config.dbplatform.DbTypeMap;
*/
public class PlatformTypeConverter {
protected final DbTypeMap platformTypes;
protected final DbPlatformTypeMapping platformTypes;
/**
* Construct with the platform specific types.
*/
public PlatformTypeConverter(DbTypeMap platformTypes) {
public PlatformTypeConverter(DbPlatformTypeMapping platformTypes) {
this.platformTypes = platformTypes;
}
@@ -47,7 +47,7 @@ public class PlatformTypeConverter {
String suffix = close + 1 < columnDefinition.length() ? columnDefinition.substring(close + 1) : "";
String type = columnDefinition.substring(0, open);
try {
DbType dbType = platformTypes.lookup(type, true);
DbPlatformType dbType = platformTypes.lookup(type, true);
int comma = columnDefinition.indexOf(',', open);
if (comma > -1) {
// scale and precision - decimal(10,4)
@@ -73,7 +73,7 @@ public class PlatformTypeConverter {
protected String convertNoScale(String columnDefinition) {
try {
DbType dbType = platformTypes.lookup(columnDefinition, false);
DbPlatformType dbType = platformTypes.lookup(columnDefinition, false);
return dbType.renderType(0, 0);
} catch (IllegalArgumentException e) {
@@ -70,7 +70,7 @@ public class AddColumn {
*/
public List<Column> getColumn() {
if (column == null) {
column = new ArrayList<Column>();
column = new ArrayList<>();
}
return this.column;
}
@@ -61,7 +61,7 @@ public class Applications {
*/
public List<Application> getApplication() {
if (application == null) {
application = new ArrayList<Application>();
application = new ArrayList<>();
}
return this.application;
}
@@ -113,7 +113,7 @@ public class ChangeSet {
*/
public List<Object> getChangeSetChildren() {
if (changeSetChildren == null) {
changeSetChildren = new ArrayList<Object>();
changeSetChildren = new ArrayList<>();
}
return this.changeSetChildren;
}
@@ -105,7 +105,7 @@ public class CreateTable {
*/
public List<Column> getColumn() {
if (column == null) {
column = new ArrayList<Column>();
column = new ArrayList<>();
}
return this.column;
}
@@ -134,7 +134,7 @@ public class CreateTable {
*/
public List<UniqueConstraint> getUniqueConstraint() {
if (uniqueConstraint == null) {
uniqueConstraint = new ArrayList<UniqueConstraint>();
uniqueConstraint = new ArrayList<>();
}
return this.uniqueConstraint;
}
@@ -163,7 +163,7 @@ public class CreateTable {
*/
public List<ForeignKey> getForeignKey() {
if (foreignKey == null) {
foreignKey = new ArrayList<ForeignKey>();
foreignKey = new ArrayList<>();
}
return this.foreignKey;
}
@@ -63,7 +63,7 @@ public class Migration {
*/
public List<ChangeSet> getChangeSet() {
if (changeSet == null) {
changeSet = new ArrayList<ChangeSet>();
changeSet = new ArrayList<>();
}
return this.changeSet;
}
@@ -16,8 +16,8 @@ import java.io.InputStream;
*/
public class MigrationXmlReader {
private static final MigrationXmlReader INSTANCE = new MigrationXmlReader();
private MigrationXmlReader() {}
/**
* Read and return a Migration from an xml document at the given resource path.
*/
@@ -28,7 +28,7 @@ public class MigrationXmlReader {
throw new IllegalArgumentException("No resource found for path [" + resourcePath + "]");
}
return INSTANCE.read(is);
return read(is);
}
/**
@@ -45,10 +45,7 @@ public class MigrationXmlWriter {
writer.close();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (JAXBException e) {
} catch (IOException | JAXBException e) {
throw new RuntimeException(e);
}
}
@@ -11,7 +11,6 @@ import com.avaje.ebean.dbmigration.model.visitor.VisitAllUsing;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import java.io.IOException;
import java.util.List;
/**
* Reads EbeanServer bean descriptors to build the current model.
@@ -24,6 +23,8 @@ public class CurrentModel {
private final DbConstraintNaming.MaxLength maxLength;
private final boolean platformTypes;
private ModelContainer model;
private ChangeSet changeSet;
@@ -31,32 +32,31 @@ public class CurrentModel {
private DdlWrite write;
/**
* Construct with a given EbeanServer instance.
* Construct with a given EbeanServer instance for DDL create all generation, not migration.
*/
public CurrentModel(SpiEbeanServer server) {
this(server, server.getServerConfig().getConstraintNaming());
this(server, server.getServerConfig().getConstraintNaming(), true);
}
/**
* Construct with a given EbeanServer, platformDdl and constraintNaming convention.
* <p>
* Note the EbeanServer is just used to read the BeanDescriptors and platformDdl supplies
* the platform specific handling on
* Note the EbeanServer is just used to read the BeanDescriptors and platformDdl supplies
* the platform specific handling on
* </p>
*/
public CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming) {
this(server, constraintNaming, false);
}
private CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, boolean platformTypes) {
this.server = server;
this.constraintNaming = constraintNaming;
this.maxLength = maxLength(server, constraintNaming);
this.platformTypes = platformTypes;
}
public CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, int maxConstraintLength) {
this.server = server;
this.constraintNaming = constraintNaming;
this.maxLength = new DefaultConstraintMaxLength(maxConstraintLength);
}
private DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
private static DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
if (naming.getMaxLength() != null) {
return naming.getMaxLength();
@@ -73,7 +73,7 @@ public class CurrentModel {
if (model == null) {
model = new ModelContainer();
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength);
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength, platformTypes);
ModelBuildBeanVisitor visitor = new ModelBuildBeanVisitor(context);
VisitAllUsing visit = new VisitAllUsing(visitor, server);
visit.visitAllBeans();
@@ -16,8 +16,8 @@ public class MCompoundForeignKey {
private String name;
private final String referenceTable;
private final List<String> columns = new ArrayList<String>();
private final List<String> referenceColumns = new ArrayList<String>();
private final List<String> columns = new ArrayList<>();
private final List<String> referenceColumns = new ArrayList<>();
private String indexName;
public MCompoundForeignKey(String name, String referenceTable, String indexName) {
@@ -4,6 +4,7 @@ import com.avaje.ebean.dbmigration.migration.CreateIndex;
import com.avaje.ebean.dbmigration.migration.DropIndex;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@@ -15,7 +16,7 @@ public class MIndex {
private String indexName;
private List<String> columns = new ArrayList<String>();
private List<String> columns = new ArrayList<>();
/**
* Create a single column non unique index.
@@ -32,9 +33,7 @@ public class MIndex {
public MIndex(String indexName, String tableName, String[] columnNames) {
this.tableName = tableName;
this.indexName = indexName;
for (int i = 0; i < columnNames.length; i++) {
this.columns.add(columnNames[i]);
}
Collections.addAll(this.columns, columnNames);
}
public MIndex(CreateIndex createIndex) {
@@ -101,7 +100,6 @@ public class MIndex {
* Return true if the index has changed.
*/
private boolean changed(MIndex newIndex) {
if (!tableName.equals(newIndex.getTableName())) {
return true;
}
@@ -119,12 +117,9 @@ public class MIndex {
private List<String> split(String columns) {
List<String> colList = new ArrayList<String>();
List<String> colList = new ArrayList<>();
String[] cols = columns.split(",");
for (int i = 0; i <cols.length; i++) {
colList.add(cols[i]);
}
Collections.addAll(colList, cols);
return colList;
}
@@ -99,17 +99,17 @@ public class MTable {
/**
* The columns on the table.
*/
private Map<String, MColumn> columns = new LinkedHashMap<String, MColumn>();
private Map<String, MColumn> columns = new LinkedHashMap<>();
/**
* Compound unique constraints.
*/
private List<MCompoundUniqueConstraint> compoundUniqueConstraints = new ArrayList<MCompoundUniqueConstraint>();
private List<MCompoundUniqueConstraint> uniqueConstraints = new ArrayList<>();
/**
* Compound foreign keys.
*/
private List<MCompoundForeignKey> compoundKeys = new ArrayList<MCompoundForeignKey>();
private List<MCompoundForeignKey> compoundKeys = new ArrayList<>();
/**
* Column name for the 'When created' column. This can be used for the initial effective start date when adding
@@ -122,7 +122,7 @@ public class MTable {
*/
private AddColumn addColumn;
private List<String> droppedColumns = new ArrayList<String>();
private List<String> droppedColumns = new ArrayList<>();
/**
* Create a copy of this table structure as a 'draft' table.
@@ -216,7 +216,7 @@ public class MTable {
createTable.getForeignKey().add(compoundKey.createForeignKey());
}
for (MCompoundUniqueConstraint constraint : compoundUniqueConstraints) {
for (MCompoundUniqueConstraint constraint : uniqueConstraints) {
UniqueConstraint uq = new UniqueConstraint();
uq.setName(constraint.getName());
String[] columns = constraint.getColumns();
@@ -270,17 +270,15 @@ public class MTable {
}
// compare existing columns (look for dropped columns)
int columnPosition = 0;
for (MColumn existingColumn : allColumns()) {
MColumn newColumn = newColumnMap.get(existingColumn.getName());
if (newColumn == null) {
diffDropColumn(modelDiff, existingColumn, columnPosition, newTable);
diffDropColumn(modelDiff, existingColumn);
} else if (newColumn.isDraftOnly() && !draft) {
// effectively a drop column (draft only column on a non-draft table)
logger.trace("... drop column {} from table {} as now draftOnly", newColumn.getName(), name);
diffDropColumn(modelDiff, existingColumn, columnPosition, newTable);
diffDropColumn(modelDiff, existingColumn);
}
columnPosition++;
}
if (addColumn != null) {
@@ -371,7 +369,7 @@ public class MTable {
public List<String> allHistoryColumns(boolean includeDropped) {
List<String> columnNames = new ArrayList<String>(columns.size());
List<String> columnNames = new ArrayList<>(columns.size());
for (MColumn column : columns.values()) {
if (column.isIncludeInHistory()) {
columnNames.add(column.getName());
@@ -404,8 +402,8 @@ public class MTable {
return columns;
}
public List<MCompoundUniqueConstraint> getCompoundUniqueConstraints() {
return compoundUniqueConstraints;
public List<MCompoundUniqueConstraint> getUniqueConstraints() {
return uniqueConstraints;
}
public List<MCompoundForeignKey> getCompoundKeys() {
@@ -446,7 +444,7 @@ public class MTable {
* Return the list of columns that make the primary key.
*/
public List<MColumn> primaryKeyColumns() {
List<MColumn> pk = new ArrayList<MColumn>(3);
List<MColumn> pk = new ArrayList<>(3);
for (MColumn column : allColumns()) {
if (column.isPrimaryKey()) {
pk.add(column);
@@ -476,21 +474,21 @@ public class MTable {
}
/**
* Add a compound unique constraint.
* Add a unique constraint.
*/
public void addCompoundUniqueConstraint(String[] columns, boolean oneToOne, String constraintName) {
compoundUniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne, constraintName));
public void addUniqueConstraint(String[] columns, boolean oneToOne, String constraintName) {
uniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne, constraintName));
}
/**
* Add a compound unique constraint.
* Add a unique constraint.
*/
public void addCompoundUniqueConstraint(List<MColumn> columns, boolean oneToOne, String constraintName) {
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();
}
addCompoundUniqueConstraint(cols, oneToOne, constraintName);
addUniqueConstraint(cols, oneToOne, constraintName);
}
/**
@@ -540,7 +538,7 @@ public class MTable {
/**
* Add a 'drop column' to the diff.
*/
private void diffDropColumn(ModelDiff modelDiff, MColumn existingColumn, int columnPosition, MTable newTable) {
private void diffDropColumn(ModelDiff modelDiff, MColumn existingColumn) {
DropColumn dropColumn = new DropColumn();
dropColumn.setTableName(name);
@@ -592,7 +590,7 @@ public class MTable {
* Return true if the foreign key names are not unique.
*/
private boolean hasDuplicateForeignKeys() {
Set<String> fkNames = new HashSet<String>();
Set<String> fkNames = new HashSet<>();
for (MCompoundForeignKey fk : compoundKeys) {
if (!fkNames.add(fk.getName())) {
return true;
@@ -42,14 +42,9 @@ public class MigrationModel {
private void readMigrations() {
// find all the migration xml files
File[] xmlFiles = modelDirectory.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().toLowerCase().endsWith(modelSuffix);
}
});
File[] xmlFiles = modelDirectory.listFiles(pathname -> pathname.getName().toLowerCase().endsWith(modelSuffix));
List<MigrationResource> resources = new ArrayList<MigrationResource>();
List<MigrationResource> resources = new ArrayList<>();
for (File xmlFile: xmlFiles) {
resources.add(new MigrationResource(xmlFile, createVersion(xmlFile)));
@@ -28,12 +28,12 @@ public class ModelContainer {
/**
* All the tables in the model.
*/
private final Map<String, MTable> tables = new LinkedHashMap<String, MTable>();
private final Map<String, MTable> tables = new LinkedHashMap<>();
/**
* All the non unique non foreign key indexes.
*/
private final Map<String, MIndex> indexes = new LinkedHashMap<String, MIndex>();
private final Map<String, MIndex> indexes = new LinkedHashMap<>();
private final PendingDrops pendingDrops = new PendingDrops();
@@ -30,12 +30,12 @@ public class ModelDiff {
/**
* List of 'create' type changes.
*/
private final List<Object> applyChanges = new ArrayList<Object>();
private final List<Object> applyChanges = new ArrayList<>();
/**
* List of 'drop' type changes. Expected to be placed into a separate DDL script.
*/
private final List<Object> dropChanges = new ArrayList<Object>();
private final List<Object> dropChanges = new ArrayList<>();
/**
* Construct with a base model.
@@ -16,7 +16,7 @@ import java.util.List;
*/
public class PendingDrops {
private final LinkedHashMap<String, Entry> map = new LinkedHashMap<String, Entry>();
private final LinkedHashMap<String, Entry> map = new LinkedHashMap<>();
/**
* Add a 'pending drops' changeSet for the given version.
@@ -36,7 +36,7 @@ public class PendingDrops {
*/
public List<String> pendingDrops() {
List<String> versions = new ArrayList<String>();
List<String> versions = new ArrayList<>();
for (Entry value : map.values()) {
if (value.hasPendingDrops()) {
versions.add(value.version.asString());
@@ -143,7 +143,7 @@ public class PendingDrops {
final MigrationVersion version;
final List<ChangeSet> list = new ArrayList<ChangeSet>();
final List<ChangeSet> list = new ArrayList<>();
Entry(MigrationVersion version) {
this.version = version;
@@ -9,6 +9,8 @@ import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.migration.ChangeSetType;
import com.avaje.ebean.dbmigration.migration.Migration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileWriter;
@@ -21,6 +23,8 @@ import java.util.List;
*/
public class PlatformDdlWriter {
private static final Logger logger = LoggerFactory.getLogger(PlatformDdlWriter.class);
private final ServerConfig serverConfig;
private final DatabasePlatform platform;
@@ -67,7 +71,7 @@ public class PlatformDdlWriter {
protected void writePlatformDdl(DdlWrite write, File resourcePath, String fullVersion) throws IOException {
if (!write.isApplyEmpty()) {
FileWriter applyWriter = createWriter(resourcePath, fullVersion, "", config.getApplySuffix());
FileWriter applyWriter = createWriter(resourcePath, fullVersion, config.getApplySuffix());
try {
writeApplyDdl(applyWriter, write);
applyWriter.flush();
@@ -77,28 +81,12 @@ public class PlatformDdlWriter {
}
}
protected FileWriter createWriter(File path, String fullVersion, String subPath, String suffix) throws IOException {
protected FileWriter createWriter(File path, String fullVersion, String suffix) throws IOException {
String fileName = fullVersion;
if (!platformPrefix.isEmpty()) {
fileName += "-"+platformPrefix;
}
if (subPath != null && !subPath.isEmpty()) {
path = subPath(path, subPath);
}
fileName += suffix;
File applyFile = new File(path, fileName);
File applyFile = new File(path, fullVersion + suffix);
return new FileWriter(applyFile);
}
protected File subPath(File path, String suffix) {
File subPath = new File(path, suffix);
if (!subPath.exists()) {
subPath.mkdirs();
}
return subPath;
}
/**
* Write the 'Apply' DDL buffers to the writer.
*/
@@ -127,4 +115,17 @@ public class PlatformDdlWriter {
return platform.createDdlHandler(serverConfig);
}
/**
* Return a sub directory (for multi-platform ddl generation).
*/
public File subPath(File path, String suffix) {
File subPath = new File(path, suffix);
if (!subPath.exists()) {
if (!subPath.mkdirs()) {
logger.error("failed to create directories for " + subPath.getAbsolutePath());
}
}
return subPath;
}
}
@@ -1,6 +1,6 @@
package com.avaje.ebean.dbmigration.model.build;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebean.dbmigration.migration.IdentityType;
import com.avaje.ebean.dbmigration.model.MColumn;
@@ -52,7 +52,7 @@ public class ModelBuildBeanVisitor implements BeanVisitor {
if (inheritInfo != null && inheritInfo.isRoot()) {
// add the discriminator column
String discColumn = inheritInfo.getDiscriminatorColumn();
DbType dbType = ctx.getDbTypeMap().get(inheritInfo.getDiscriminatorType());
DbPlatformType dbType = ctx.getDbTypeMap().get(inheritInfo.getDiscriminatorType());
String discDbType = dbType.renderType(inheritInfo.getDiscriminatorLength(), 0);
table.addColumn(new MColumn(discColumn, discDbType, true));
@@ -1,8 +1,8 @@
package com.avaje.ebean.dbmigration.model.build;
import com.avaje.ebean.config.DbConstraintNaming;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
import com.avaje.ebean.config.dbplatform.DbPlatformTypeMapping;
import com.avaje.ebean.dbmigration.model.MColumn;
import com.avaje.ebean.dbmigration.model.MTable;
import com.avaje.ebean.dbmigration.model.ModelContainer;
@@ -21,7 +21,7 @@ public class ModelBuildContext {
* Use platform agnostic logical types. These types are converted to
* platform specific types in the DDL generation.
*/
private final DbTypeMap dbTypeMap = DbTypeMap.logicalTypes();
private final DbPlatformTypeMapping dbTypeMap = DbPlatformTypeMapping.logicalTypes();
private final ModelContainer model;
@@ -29,10 +29,13 @@ public class ModelBuildContext {
private final DbConstraintNaming.MaxLength maxLength;
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength) {
private final boolean platformTypes;
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength, boolean platformTypes) {
this.model = model;
this.constraintNaming = naming;
this.maxLength = maxLength;
this.platformTypes = platformTypes;
}
/**
@@ -103,7 +106,7 @@ public class ModelBuildContext {
* Return the map used to determine the DB specific type
* for a given bean property.
*/
public DbTypeMap getDbTypeMap() {
public DbPlatformTypeMapping getDbTypeMap() {
return dbTypeMap;
}
@@ -112,14 +115,14 @@ public class ModelBuildContext {
* Render the DB type for this property given the strict mode.
*/
public String getColumnDefn(BeanProperty p, boolean strict) {
DbType dbType = getDbType(p);
DbPlatformType dbType = getDbType(p);
if (dbType == null) {
throw new IllegalStateException("Unknown DbType mapping for " + p.getFullBeanName());
}
return p.renderDbType(dbType, strict);
}
private DbType getDbType(BeanProperty p) {
private DbPlatformType getDbType(BeanProperty p) {
if (p.isDbEncrypted()) {
return dbTypeMap.get(p.getDbEncryptedType());
@@ -132,7 +135,7 @@ public class ModelBuildContext {
}
// can be the logical JSON types (JSON, JSONB, JSONClob, JSONBlob, JSONVarchar)
int dbType = p.getDbType();
int dbType = p.getDbType(platformTypes);
if (dbType == 0) {
throw new RuntimeException("No scalarType defined for " + p.getFullBeanName());
}
@@ -10,7 +10,7 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueConstraint;
import com.avaje.ebeaninternal.server.deploy.IndexDefinition;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.deploy.TableJoinColumn;
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
@@ -45,30 +45,30 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
this.ctx = ctx;
this.table = table;
this.beanDescriptor = beanDescriptor;
addCompoundUniqueConstraint(beanDescriptor.getCompoundUniqueConstraints());
addIndexes(beanDescriptor.getIndexDefinitions());
}
/**
* Add unique constraints defined via JPA UniqueConstraint annotations.
*/
private void addCompoundUniqueConstraint(CompoundUniqueConstraint[] constraints) {
private void addIndexes(IndexDefinition[] indexes) {
if (constraints != null) {
for (int i = 0; i < constraints.length; i++) {
CompoundUniqueConstraint constraint = constraints[i];
String[] columns = constraint.getColumns();
if (indexes != null) {
for (int i = 0; i < indexes.length; i++) {
IndexDefinition index = indexes[i];
String[] columns = index.getColumns();
indexSet.add(columns);
if (constraint.isUnique()) {
String uqName = constraint.getName();
if (index.isUnique()) {
String uqName = index.getName();
if (uqName == null || uqName.trim().isEmpty()) {
uqName = determineUniqueConstraintName(columns);
}
table.addCompoundUniqueConstraint(columns, false, uqName);
table.addUniqueConstraint(columns, false, uqName);
} else {
// 'just' an index (not a unique constraint)
String idxName = constraint.getName();
String idxName = index.getName();
if (idxName == null || idxName.trim().isEmpty()) {
idxName = determineIndexName(columns);
}
@@ -166,7 +166,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
ImportedId importedId = p.getImportedId();
List<MColumn> modelColumns = new ArrayList<MColumn>(columns.length);
List<MColumn> modelColumns = new ArrayList<>(columns.length);
MCompoundForeignKey compoundKey = null;
if (columns.length > 1) {
@@ -216,7 +216,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
} else {
String uqName = determineUniqueConstraintName(p.getName());
table.addCompoundUniqueConstraint(modelColumns, true, uqName);
table.addUniqueConstraint(modelColumns, true, uqName);
indexSetAdd(modelColumns);
}
}
@@ -236,6 +236,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
col.setDefaultValue(p.getDbColumnDefault());
col.setComment(p.getDbComment());
col.setDraftOnly(p.isDraftOnly());
col.setHistoryExclude(p.isExcludedFromHistory());
if (p.isId()) {
col.setPrimaryKey(true);
@@ -260,15 +261,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
col.setCheckConstraintName(determineCheckConstraintName(col.getName()));
}
String indexName = p.getIndexName();
if (indexName != null) {
// single column non-unique index
if (indexName.trim().isEmpty()) {
indexName = determineIndexName(col.getName());
}
ctx.addIndex(indexName, table.getName(), p.getDbColumn());
}
lastColumn = col;
table.addColumn(col);
}

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