Compare commits

...
Author SHA1 Message Date
Robin Bygrave 7e233edcc3 [maven-release-plugin] prepare release avaje-ebeanorm-6.10.1 2015-10-29 09:00:55 +13:00
Robin Bygrave a8b98282a1 Bump pom to 6.10.1-SNAPSHOT 2015-10-29 09:00:00 +13:00
Robin Bygrave b4506aa718 #444 - Spring Boot classpath scanning not finding entity beans - part2 - embedded jar scanning 2015-10-29 08:59:06 +13:00
Robin Bygrave 848a3b8888 #444 - Spring Boot classpath scanning not finding entity beans 2015-10-28 15:45:09 +13:00
Robin Bygrave 67c711d75f #442 - @JsonIgnore / @Expose ... not working on @OneToMany or @ManyToMany - was - @Transient field on @MappedSuperclass is not ignored by toJson() 2015-10-28 09:10:19 +13:00
Robin Bygrave 3d62f58930 #439 - @EnumValue("01") stored as integer rather than string - ENum stores strings as numerics? 2015-10-28 08:53:14 +13:00
Robin Bygrave a30948d38d #438 - findPagedList and getTotalRowCount, the query.getAlias() is null 2015-10-28 08:15:15 +13:00
Robin Bygrave a8232d2d8b #441 - ENH: Add support for test-ebean.properties ... for mechanism to configure ebean to run tests 2015-10-27 00:17:47 +13:00
Robin Bygrave d4b8f23a5a Fix test - MySql limitations with delete query syntax 2015-10-26 21:52:35 +13:00
Robin Bygrave bcf2a44187 #430 - ENH: Support for UUID mapping to native DB UUID type (Postgres, H2) 2015-10-26 20:52:16 +13:00
Robin Bygrave f3102ba02c #432 - Delete using Query does not commit 2015-10-22 13:29:21 +13:00
Robin Bygrave 0351eab3a7 #431 - Annotation PrivateOwned seems not enough to update an change in the list of children (fix) 2015-10-22 11:10:41 +13:00
Robin Bygrave 409e2b75ce #431 - Add failing test ... Annotation PrivateOwned seems not enough to update an change in the list of children 2015-10-22 09:27:32 +13:00
Robin Bygrave dc968f16bf Q: Ebean @ManyToMany(cascade=REMOVE) described #429 2015-10-06 14:38:05 +13:00
Robin Bygrave bbbb6482fb [maven-release-plugin] prepare for next development iteration 2015-10-02 13:03:34 +13:00
Robin Bygrave 001968fcf8 [maven-release-plugin] prepare release avaje-ebeanorm-6.9.1 2015-10-02 13:03:07 +13:00
Robin Bygrave 6abcb186a4 Bump pom to 6.9.1-SNAPSHOT 2015-10-02 13:02:13 +13:00
Robin Bygrave f250447fbe Add test for ManyToMany delete scenario 2015-10-01 22:21:47 +13:00
Robin Bygrave bfa86f241b #427 - ENH: Add support for Removing ShutdownManager.shutdownHook ... manually control entire shutdown. 2015-10-01 10:33:09 +13:00
Robin Bygrave 19459b71b4 Fix for #425 - Extra instance of root level bean with findIterate() and fetch of OneToMany relationship - Ebean parses the first bean correctly and the rest not 2015-09-30 23:35:10 +13:00
Robin Bygrave 5e97c3bbbc #425 - Extra instance of root level bean with findIterate() and fetch of OneToMany relationship - Ebean parses the first bean correctly and the rest not 2015-09-30 23:24:53 +13:00
Robin Bygrave 986eadd023 #424 - DDL generation - support turning off lower casing of table and column names DbConstraintNaming, DbConstraintNormalise 2015-09-30 22:44:47 +13:00
Robin Bygrave c6787d0901 Update javadoc 2015-09-30 17:26:30 +13:00
Robin Bygrave 3792e06859 Update javadoc 2015-09-30 17:26:05 +13:00
Robin Bygrave c77446ba24 Update javadoc 2015-09-30 17:25:26 +13:00
Robin Bygrave dba245c517 #421 - ENH: Add support for unsetting the loaded state of a bean property (via BeanState) 2015-09-22 13:21:19 +12:00
Robin Bygrave 489eb483c0 No effective change - parameter name from val -> value 2015-09-22 12:34:30 +12:00
Robin Bygrave 11301846be #422 - ENH: Add jsonBetween() expression 2015-09-22 12:32:46 +12:00
Robin Bygrave d022e4aec8 No effective change - parameter name from val -> value 2015-09-22 11:48:41 +12:00
Robin Bygrave aa788edb68 #421 - ENH: Add support for unsetting the loaded state of a bean property (via BeanState) ... initial test 2015-09-22 09:00:06 +12:00
Robin Bygrave 288adcdf68 Update README 2015-09-21 18:01:31 +12:00
Robin Bygrave ddb07ca202 Update README 2015-09-21 17:59:45 +12:00
Robin Bygrave 524b592e82 [maven-release-plugin] prepare for next development iteration 2015-09-21 17:45:47 +12:00
Robin Bygrave 0124f0f254 [maven-release-plugin] prepare release avaje-ebeanorm-6.8.1 2015-09-21 17:45:21 +12:00
Robin Bygrave eddd6a36d6 No effective change - javadoc only 2015-09-21 17:36:13 +12:00
Robin Bygrave 91e309d770 Bump pom version to 6.8.1-SNAPSHOT 2015-09-21 17:03:22 +12:00
Robin Bygrave 5726410f6f #417 - ENH: Add JSON expressions ... path exists and value at path equals value 2015-09-21 16:20:14 +12:00
Robin Bygrave 054f7dc86f #415 - ENH: Add ExplicitJdbcTransaction ... so like AutoCommitJdbcTransaction but using explicit statements to commit and rollback 2015-09-18 22:25:19 +12:00
Robin Bygrave 06b5ebc14e #419 - Support running History DDL scripts in full drop and create ddl execution - detect $$ procedures/triggers in ddl script 2015-09-18 22:19:52 +12:00
Robin Bygrave f6ee82428f Change test - disable this test for MySql - it does not like trying to delete using sub query select from same table 2015-09-18 22:18:37 +12:00
Robin Bygrave e1d45dd79d #419 - Support running History DDL scripts in full drop and create ddl execution - detect $$ procedures/triggers in ddl script 2015-09-18 22:03:26 +12:00
Robin Bygrave 08c455279f #418 - Postgres History DDL generation - invalid update table statement to initialise the sys_period 2015-09-18 21:30:59 +12:00
Robin Bygrave 32dcbc6703 Change test to only run with H2 (but it would also run with db's that use history table views/triggers but not with oracle total recall) 2015-09-18 21:13:19 +12:00
Robin Bygrave c9e733df4e Fix test - incorrect raw sql syntax (breaks in Oracle) 2015-09-18 21:06:54 +12:00
Robin Bygrave 606e1e6d3a #414 - Enh info: @History support for H2 2015-09-18 17:16:46 +12:00
Robin Bygrave fcb50ea13a No effective change - remove whitespace 2015-09-18 11:45:19 +12:00
Robin Bygrave 5b26e77cfd #413 - ENH: Add ability to clear the OrderBy ... so that a default order by can be set in code and then cleared / overwritten 2015-09-18 11:39:47 +12:00
Robin Bygrave 9fc5d8a201 Pom - bump test Postgres JDBC driver version 2015-09-17 11:33:09 +12:00
Robin Bygrave ba78c5e904 [maven-release-plugin] prepare for next development iteration 2015-09-14 16:19:59 +12:00
Robin Bygrave 6627195fc2 [maven-release-plugin] prepare release avaje-ebeanorm-6.7.1 2015-09-14 16:19:33 +12:00
Robin Bygrave b76c4a83ec #411 - AutoTune - add reporting empty tuned profiles, ignore org.avaje.ebean type safe finders, refactor CallStack creation 2015-09-14 16:16:22 +12:00
Robin Bygrave 3dcb82b1f5 gitignore example ebean-autotune.xml 2015-09-14 12:58:58 +12:00
Robin Bygrave ae55a40ebd Remove example ebean-autotune.xml 2015-09-14 12:57:57 +12:00
Robin Bygrave 8ba07419fa Bump pom to 6.7.1-SNAPSHOT 2015-09-14 12:02:26 +12:00
Robin Bygrave 5f8f735bbe #412 - SQL_LOGGER trace() to debug() issue - Unintelligible logging settings 2015-09-14 11:49:16 +12:00
Robin Bygrave 47829f3985 #410 - Require findPagedList() query to specify an order by clause - throw exception if no order by supplied 2015-09-14 11:29:38 +12:00
Robin Bygrave ec4f655312 #410 - Require findPagedList() query to specify an order by clause - throw exception if no order by supplied 2015-09-14 10:39:41 +12:00
Robin Bygrave 04fda0a6b4 #411 - Refactor AutoFetch, rename to "AutoTune", store/load tuning and profiling as XML 2015-09-10 23:22:23 +12:00
Robin Bygrave 0a8c902790 #411 - Refactor AutoFetch, rename to "AutoTune", store/load tuning and profiling as XML 2015-09-10 23:20:57 +12:00
Robin Bygrave 9632279c2f AutoTune update - clean up for query ignore 2015-09-10 22:36:12 +12:00
Robin Bygrave 262d52ed44 Merge AutoTune refactor with master 2015-09-10 10:27:24 +12:00
Robin Bygrave 74330918e1 AutoTune update - .gitignore the profiling output 2015-09-10 10:04:31 +12:00
Robin Bygrave 373598ab26 AutoTune update - config properties for queryTuningFile and profilingFile + logging adjustment 2015-09-10 10:02:17 +12:00
Robin Bygrave 0096477757 AutoTune update - repackage tests and sort profiling xml entries 2015-09-10 09:16:39 +12:00
Robin Bygrave a2a4a15f32 AutoTune update - rename and profiling against original query 2015-09-10 00:18:11 +12:00
Robin Bygrave 71dd0e5728 AutoTune update - rename and profiling against original query 2015-09-10 00:17:49 +12:00
Robin Bygrave 116cc3a3fe AutoTune update - remove resources 2015-09-09 15:21:10 +12:00
Robin Bygrave 92132d6613 [maven-release-plugin] prepare for next development iteration 2015-09-09 00:08:33 +12:00
Robin Bygrave d6e3292a7d [maven-release-plugin] prepare release avaje-ebeanorm-6.6.1 2015-09-09 00:08:12 +12:00
Robin Bygrave 227a1ba032 Bump pom to 6.6.1-SNAPSHOT 2015-09-09 00:07:20 +12:00
Robin Bygrave 953cae6ce8 #407 - ENH: Add example uses of raw() into javadoc for ExpressionList.raw() 2015-09-09 00:06:14 +12:00
Robin Bygrave 98fc739600 #404 - ENH: ExpressionList missing setUseQueryCache() method - need to add it. 2015-09-08 23:55:53 +12:00
Robin Bygrave fc3ab10984 No effective change - javadoc on Ebean 2015-09-08 16:20:56 +12:00
Robin Bygrave 5b8ce8eaa0 WIP AutoTune refactor 2015-09-04 08:48:25 +12:00
Robin Bygrave 97cf8b30f6 Extend test for #322 - using inheritance discriminator with RawSql - extra test with columnMappingIgnore() 2015-09-03 16:29:45 +12:00
Robin Bygrave 7e66e0db1f Extend test for #322 - using inheritance discriminator with RawSql 2015-09-03 15:57:38 +12:00
Robin Bygrave 572bb41b73 Code Cleanup - move diff flatten into DiffHelp class from DiffHelpUpdate #406 2015-09-03 14:31:36 +12:00
Robin Bygrave 088fcfb296 #406 - Remove diff "non flat mode" ... so diff going forward only supports flat mode 2015-09-03 14:29:03 +12:00
Robin Bygrave 54172aec6c #405 - ENH: Add @ReadAudit and associated functionality for auditing reads including queries and L2 cache access 2015-09-03 13:54:52 +12:00
Robin Bygrave 5c1de0a886 WIP Autotune refactor 2015-09-02 09:28:17 +12:00
Robin Bygrave c292da736b #403 - Long property names result in invalid DDL 2015-09-01 08:00:46 +12:00
Robin Bygrave 987fe38618 WIP AutoTune refactor 2015-09-01 07:55:25 +12:00
Robin Bygrave f4ed813c08 No effective change - code format only 2015-08-31 16:16:10 +12:00
Robin Bygrave a358fba31d Bump agent and maven enhancer versions to 4.7.1 2015-08-31 15:37:32 +12:00
Robin Bygrave 76783d525a No effective change - improve error message 2015-08-31 15:36:56 +12:00
Robin Bygrave 3f0f5c7fde #401 - Fix for - Caused by: java.lang.NullPointerException at com.avaje.ebeaninternal.server.changelog.DefaultChangeLogListener.configure(DefaultChangeLogListener.java:62) 2015-08-30 23:38:05 +12:00
Robin Bygrave 6df1058aab [maven-release-plugin] prepare for next development iteration 2015-08-29 01:03:00 +12:00
Robin Bygrave 335c5fb69b [maven-release-plugin] prepare release avaje-ebeanorm-6.5.1 2015-08-29 01:02:37 +12:00
Robin Bygrave 94ed568812 Bump pom to 6.5.1-SNAPSHOT 2015-08-29 01:01:17 +12:00
Robin Bygrave 1c23720605 #398 - ENH: Support delete using a Query instance 2015-08-29 00:58:47 +12:00
Robin Bygrave ccba5d08ef #368 - ENH: Enhance @Index to support multiple columns, unique flag and hence also be able to put on the class (annotation target TYPE) 2015-08-28 21:56:38 +12:00
Robin Bygrave 641ada001e Fix test for CustomerFinder 2015-08-28 20:43:05 +12:00
Robin Bygrave fca80ac649 #399 - ENH: Add new Finder ... to effectively replace Model.Finder 2015-08-28 20:32:40 +12:00
Robin Bygrave 379cc39e38 Initial add of Finder 2015-08-28 07:52:46 +12:00
Robin Bygrave 386d3a37f1 No effective change - format only 2015-08-27 09:37:22 +12:00
Robin Bygrave 37612c6f83 [maven-release-plugin] prepare for next development iteration 2015-08-26 10:48:57 +12:00
Robin Bygrave 7984553d96 [maven-release-plugin] prepare release avaje-ebeanorm-6.4.1 2015-08-26 10:48:35 +12:00
Robin Bygrave d592e7d35f No effective change - format only 2015-08-26 10:47:22 +12:00
Robin Bygrave 5a0b65b4f2 Bump pom to 6.4.1-SNAPSHOT 2015-08-26 10:45:06 +12:00
Robin Bygrave aaefaa5dcd #390 - ChangeLog - Add inheritance hierarchy check for @ChangeLog 2015-08-26 10:42:12 +12:00
Robin Bygrave f3e66c459a #390 - ChangeLog - Add ServerConfig.isChangeLogIncludeInserts() and ChangeLogInsertMode enum with associated changes 2015-08-25 13:54:34 +12:00
Robin Bygrave 16d5e04809 #390 - ChangeLog - Change userContext to be Map<String,String> 2015-08-25 13:22:09 +12:00
Robin Bygrave b01df515bd #390 - ChangeLog - Refactor DefaultChangeLogListener (simplify to use standard logger) 2015-08-25 13:05:58 +12:00
Robin Bygrave 7fda911931 #394 - ENH: SpiServer - Add getServerConfig() to the api 2015-08-25 13:04:36 +12:00
Robin Bygrave e332aace16 No effective change - format test logback-test.xml 2015-08-25 11:54:11 +12:00
Robin Bygrave c79231c846 #394 - ENH: Add plugin API SpiServer - add shutdown() method to SpiServerPlugin. 2015-08-25 11:52:58 +12:00
Robin Bygrave efad23d482 #390 - ENH: Add Change log mechanism - javadoc update - no effective change 2015-08-25 08:12:22 +12:00
Robin Bygrave fe8a32ea18 #390 - ENH: Add Change log mechanism for easy fine grained logging of insert, update, delete activity.
This adds default implementations for register,filter, prepare and log of the change sets.
2015-08-22 12:10:30 +12:00
Robin Bygrave 31099f6dda #397 - Internal logger name change - Rename DefaultContainer logger to be com.avaje.ebean.internal.DefaultContainer ... so that the offline debugging messages come out without a extra logback name logger entry 2015-08-22 12:02:21 +12:00
Robin Bygrave 58f4f791f6 Opps - remove Oracle jdbc and MS SQL Server jdbc drivers ... (put those in here by mistake during @History testing). 2015-08-22 10:18:46 +12:00
Robin Bygrave b27989f541 #396 - Rename migration method to DbMigration.generateMigration() ... update javadoc 2015-08-21 21:37:36 +12:00
Robin Bygrave 7bc1a902ed No effective change - code format only 2015-08-21 21:10:22 +12:00
Robin Bygrave 358720776e No effective change - code format only 2015-08-21 21:08:29 +12:00
Robin Bygrave 417ee4061e #395 - No functional change - cleanup unused BeanDelta 2015-08-21 21:06:33 +12:00
Robin Bygrave 394cb3854a No effective change - format and organise imports 2015-08-21 18:31:55 +12:00
Robin Bygrave 547fa342c4 Internal change only - just reuse class name as bean descriptor key 2015-08-21 18:28:10 +12:00
Robin Bygrave f8b8a41bce #394 - ENH: Add plugin API SpiServer, SpiBeanType ... migrate plugins towards using this API, migrate away from direct use of BeanDescriptor etc. 2015-08-21 17:33:43 +12:00
Robin Bygrave ba39897b18 ChangeSet - add size() method 2015-08-21 16:05:30 +12:00
Robin Bygrave 1437843f08 #393 - ENH: Add ServerConfig.getProperties() ... serverConfig remembers the properties that were used in configuration in order to make these available to plugins 2015-08-21 16:05:09 +12:00
Robin Bygrave 7c705e2baa #377 - Add back support for JsonWriteBeanVisitor 2015-08-21 08:20:47 +12:00
Robin Bygrave 2caeb4fff1 #392 - Fix for AutoCommit mode ... fixing change from #204 ... such that AutoCommitJdbcTransaction works as expected 2015-08-20 22:38:53 +12:00
Robin Bygrave 84190f3c2a #390 - ENH: Add Change log mechanism for easy fine grained logging of insert, update, delete activity 2015-08-20 20:46:28 +12:00
Robin Bygrave 46b158a0a0 #391 - Minor internals - Ebean catch Throwable on instantiation rather than RuntimeException 2015-08-20 10:08:54 +12:00
Robin Bygrave b172a32710 No effective change - remove commented out test 2015-08-19 15:58:13 +12:00
Robin Bygrave f8ef87f7a8 #389 - ENH: Allow Postgres8 platform also support identity (stills defaults to use sequences but can also use identity if defined explicitly) 2015-08-19 13:24:58 +12:00
Robin Bygrave ea54d1b794 #388 - Postgres DbType.HSTORE ... not registered as logical type for DbMigration 2015-08-19 13:16:22 +12:00
Robin Bygrave b1780948a8 #387 - Change ebeanServer.diff() to default to 'flat' mode 2015-08-19 12:47:31 +12:00
Robin Bygrave 1a0f3a6614 #386 - ENH: Add setDistinct() onto ExpressionList ... so you don't need to get back to the query(and #385 javadoc) 2015-08-19 12:37:53 +12:00
Robin Bygrave 580b51381e #384 - ENH: Add findVersionsBetween(start, end) ... including implementation support for Oracle total recall 2015-08-18 23:57:11 +12:00
Robin Bygrave 75e9770d5e #383 - Refactor - Rename Oracle10Platform to OraclePlatform, remove Oracle9Platform (as not different) 2015-08-18 22:26:44 +12:00
Robin Bygrave 10937de24b #382 - ENH: Add support for @History using Oracle Total Recall ... for 'as of' queries 2015-08-18 22:19:55 +12:00
Robin Bygrave 18aeedc153 #381 - Change DbMigration to use default server platform when no platform specified 2015-08-18 22:15:11 +12:00
Robin Bygrave 9ca1a87f8b No effective change - add missing javadoc 2015-08-18 22:13:12 +12:00
Robin Bygrave 111354f391 [maven-release-plugin] prepare for next development iteration 2015-08-18 08:21:32 +12:00
Robin Bygrave 79879fb326 [maven-release-plugin] prepare release avaje-ebeanorm-6.3.1 2015-08-18 08:21:11 +12:00
Robin Bygrave 9f6ccdee66 #369 - Add test .sql resources 2015-08-18 08:16:19 +12:00
Robin Bygrave bbf469bd54 #369 - Rollback of base column attributes 2015-08-18 08:02:37 +12:00
Robin Bygrave ad97ac2be9 #369 - Rollback of create index - drop index 2015-08-18 07:00:34 +12:00
Robin Bygrave 9d83017374 #379 - Add MySql support for @History 2015-08-18 06:13:59 +12:00
Robin Bygrave 98ec00a2d6 #374 - Add @History support with MySql - refactor extracting DbTriggerBasedHistoryDdl 2015-08-17 22:12:06 +12:00
Robin Bygrave 24971bcc86 #374 - Refactor to support generating multiple platform DDL for a single migration 2015-08-17 16:03:51 +12:00
Robin Bygrave c1c45139a0 #374 - Cleanup - remove 'all' migration xml 2015-08-17 14:48:29 +12:00
Robin Bygrave 116425b460 #374 - Add support for rollback on history function 2015-08-17 14:43:44 +12:00
Robin Bygrave 48acb6294b #374 - Add DropIndex and CreateIndex migration 2015-08-17 13:06:05 +12:00
Robin Bygrave 61f5057528 #374 - Add DropIndex and CreateIndex migration 2015-08-17 13:05:54 +12:00
Robin Bygrave b91ef46243 #374 - Cleanup - remove unused migration objects 2015-08-17 11:42:12 +12:00
Robin Bygrave 0eddcc30bb #374 - Cleanup - remove unused migration objects 2015-08-17 11:42:06 +12:00
Robin Bygrave 24ec0fefba #374 - DbConstrainNaming - add index naming 2015-08-17 11:41:49 +12:00
Robin Bygrave 5ac28cb3fb #374 - BaseTableDdl change to protected visibility 2015-08-17 11:41:31 +12:00
Robin Bygrave d4635fb615 #374 - Add PlatformDdl.configure() and move add fk and create index onto PlatformDdl 2015-08-17 08:35:43 +12:00
Robin Bygrave b9774e64e9 #374 - Add comments for when a history table trigger/function is regenerated 2015-08-17 07:44:59 +12:00
Robin Bygrave f29ba8383e #374 - Find whenCreatedColumn and use as default effective start when adding history 2015-08-16 20:19:52 +12:00
Robin Bygrave a15dd33380 #374 - Add GeneratedWhenCreated and GeneratedWhenModified marker interfaces etc - used to find bean properties with those behaviours 2015-08-16 20:08:56 +12:00
Robin Bygrave f22563b36a #374 - ms sql server ... alter column default values 2015-08-15 16:53:02 +12:00
Robin Bygrave fe17ec5dbb #374 - Update tests 2015-08-15 16:09:27 +12:00
Robin Bygrave 85fdf8646d #374 - Update migration generation 2015-08-15 01:58:35 +12:00
Robin Bygrave bd9acab335 #374 - Update ModelDiff and migration generation 2015-08-15 00:06:24 +12:00
Robin Bygrave 0a6941bda5 #374 - Update ModelDiff and migration generation 2015-08-15 00:06:14 +12:00
Robin Bygrave 215417a43c #374 - Move db constraint max length to database platform 2015-08-14 17:06:08 +12:00
Robin Bygrave 60c1a5b111 #374 - Add DbOffline check into TransactionManager isReadCommittedIsolation() 2015-08-14 17:02:58 +12:00
Robin Bygrave 5166fbed96 #374 - Merge BaseColumnDdl into BaseTableDdl 2015-08-14 12:14:18 +12:00
Robin Bygrave 851f40e7b0 DbMigration update - constraints up front 2015-08-11 08:25:29 +12:00
Robin Bygrave 845faf74ff WIP: Db migration alterColumn ... 2015-08-10 14:26:47 +12:00
Robin Bygrave c0d4dac2b3 #374 - Update example/sample xml for xml schema changes 2015-08-07 13:26:35 +12:00
Robin Bygrave f6c3279e86 #374 - Table remarks -> comment 2015-08-07 13:25:22 +12:00
Robin Bygrave 48f0da9343 No effective change - update test to give slf4j a little time in multithreaded case to catch logged sql 2015-08-07 13:24:26 +12:00
Robin Bygrave ce0d73cf23 #374 - updated migration xml generated 2015-08-07 13:23:25 +12:00
Robin Bygrave 1585bd7cd0 #374 - ChangeSetType ... baseline, CreateHistoryTable whenCreatedColumn 2015-08-07 12:46:17 +12:00
Robin Bygrave 1603c69156 #374 - IdentityType lowered 2015-08-07 12:45:45 +12:00
Robin Bygrave 7cd9dc0c8d Quiet down the logging of enhancement via AgentLoader 2015-08-07 12:45:03 +12:00
Robin Bygrave e4304494e1 #374 - ChangeSetType ... baseline, CreateHistoryTable whenCreatedColumn 2015-08-07 12:44:13 +12:00
Robin Bygrave 0612d89e9a #376 - Refactor - Remove PstmtDelegate ... that was used to access the underlying oracle specific PreparedStatement 2015-08-06 23:03:25 +12:00
Robin Bygrave e6f779268a Update .gitignore to include ddl-review directory 2015-08-06 22:26:23 +12:00
Robin Bygrave 815d846695 Add ddl-review with sql/ddl for the various databases, can review/diff over time 2015-08-06 22:25:35 +12:00
Robin Bygrave 4b74062d80 #374 - uniqueOneToOne reflected in migration.xml 2015-08-06 22:03:18 +12:00
Robin Bygrave 1dd0841f00 #374 - MsSqlServer - adjust tests (due to jdbc batch support etc) add in support for unique index handling 2015-08-06 21:49:04 +12:00
Robin Bygrave 3a9668fe6c #375 - javax.persistence.PersistenceException: Query threw SQLException:Incorrect syntax near the keyword distinct 2015-08-06 19:30:57 +12:00
Robin Bygrave 93f802f7fe #374 - Drop foreign keys before indexes 2015-08-06 13:37:51 +12:00
Robin Bygrave 8cde0da419 #374 - Update tests for cross db (order by and too fast) 2015-08-06 13:36:55 +12:00
Robin Bygrave 14f984ea3e #374 - Remove old DbDdlSyntax - move to PlatformDdl 2015-08-06 13:09:41 +12:00
Robin Bygrave 253bebb9bb No effective change - camel case variable names 2015-08-06 12:27:03 +12:00
Robin Bygrave 483538bbc1 #374 -Move DdlGenerator 2015-08-06 12:16:06 +12:00
Robin Bygrave c0ef6d8b34 #374 - removed old ddl generation mechanism 2015-08-06 12:04:41 +12:00
Robin Bygrave 7f06863b19 #374 - SpiEbeanPlugin API change : DatabasePlatform dbPlatform parameter removed 2015-08-06 12:03:32 +12:00
Robin Bygrave 8be7ee1b7d identityType="EXTERNAL" - Internal changes for DB Migration / DDL generation #369 2015-08-06 11:51:00 +12:00
Robin Bygrave 15e2fde864 Postgres updated migration xml - Internal changes for DB Migration / DDL generation #369 2015-08-06 11:46:29 +12:00
Robin Bygrave 4e5140c877 Postgres dropTableCascade - Internal changes for DB Migration / DDL generation #369 2015-08-06 11:46:12 +12:00
Robin Bygrave 13ed298ee8 MySql update - Internal changes for DB Migration / DDL generation #369 2015-08-06 11:15:31 +12:00
Robin Bygrave e83a6f05bc Oracle specific changes - Internal changes for DB Migration / DDL generation #369 2015-08-06 08:09:20 +12:00
Robin Bygrave a0c312e5a4 #373 - Internals for Oracle - Remove the oracle proprietary jdbc batch handling in favour of standard jdbc batch api 2015-08-06 08:06:46 +12:00
Robin Bygrave 1eabb7fdb4 #373 - Internals for Oracle - Remove the oracle proprietary jdbc batch handling in favour of standard jdbc batch api 2015-08-06 08:02:44 +12:00
Robin Bygrave 9e170b40f6 Support duplicate index detection, max constraint names - Internal changes for DB Migration / DDL generation #369 2015-08-06 07:39:50 +12:00
Robin Bygrave efd5e16511 Update tests for better cross database execution (ordering of results etc) 2015-08-06 07:27:04 +12:00
Robin Bygrave c4e0d7aedc Internal - BeanRequest.rollbackTransIfRequired() ... change catch from PersistenceException -> Exception #371 2015-08-06 05:31:55 +12:00
Robin Bygrave d1584bed40 Change tests for better portability - Internal changes for DB Migration / DDL generation #369 2015-08-06 05:28:25 +12:00
Robin Bygrave 689d201b04 Update for pg - Internal changes for DB Migration / DDL generation #369 2015-08-05 20:59:09 +12:00
Robin Bygrave 22407506ff DB migration initial 2015-08-04 23:23:32 +12:00
Robin Bygrave 009f91b949 WIP Db Migration compound keys 2015-08-04 19:48:47 +12:00
Robin Bygrave 3bd281bea0 DB migration initial 2015-08-04 17:37:16 +12:00
Robin Bygrave 30c3a435d6 Internal changes for DB Migration / DDL generation #369 2015-08-03 17:29:57 +12:00
Robin Bygrave 0fe321b0ef Bump pom to 6.3.1-SNAPSHOT 2015-08-03 17:23:40 +12:00
Robin Bygrave 8f12442ac7 #363 - API CHANGE - BeanPersistController postLoad() ... moved to new/separate BeanPostLoad interface 2015-08-02 21:56:56 +12:00
Robin Bygrave 40ab3c81dc #364 - CallableStatement with a parameter that is both IN and OUT (so an INOUT parameter) 2015-08-02 15:24:01 +12:00
Robin Bygrave d5a8bf38ad No effective change - @SuppressWarnings("unchecked") 2015-08-02 13:48:15 +12:00
Robin Bygrave 0e793036fb No effective change - remove unused ScalarTypeConverter from BeanPropertyCompound (ala wrapper type like Option) 2015-08-02 13:27:32 +12:00
Robin Bygrave 19b7637d46 No effective change - param always true 2015-08-02 13:18:40 +12:00
Robin Bygrave 5609bc6d02 No effective change - add extra tests 2015-08-02 13:07:48 +12:00
Robin Bygrave fceeeacf88 #367 - ENH: Add EbeanServer deleteAll() with an explicit transaction 2015-08-02 12:43:19 +12:00
Robin Bygrave 4327108ddf No effective change - param always null, removed 2015-08-02 11:27:49 +12:00
Robin Bygrave cb77f33fc8 No effective change - param always null, removed 2015-08-02 11:22:46 +12:00
Robin Bygrave b687305be2 No effective change - param always true, removed 2015-08-02 11:15:43 +12:00
Robin Bygrave 192305c61f No effective change - suppress code inspection warnings 2015-08-02 11:06:38 +12:00
Robin Bygrave 03faf29bcf #366 - ServerConfigStart when registered via instance rather than class not fired 2015-08-02 11:02:02 +12:00
Robin Bygrave d389f8b5ac No effective change - remove unread variable 2015-08-02 09:52:56 +12:00
Robin Bygrave 56348938fb No effective change - remove unread variable (include props) 2015-08-02 09:48:00 +12:00
Robin Bygrave 9b0aafbfa8 No effective change - remove unused fields 2015-08-02 09:37:17 +12:00
Robin Bygrave 9239d61c74 No effective change - simplify ManyType to be an enum 2015-08-02 09:34:11 +12:00
Robin Bygrave 58a110e109 No effective change - remove unused 2015-08-02 09:33:46 +12:00
Robin Bygrave b255102780 No effective change - remove unused 2015-08-02 09:18:49 +12:00
Robin Bygrave 3a14b4c87f No effective change - remove unused methods 2015-08-02 09:17:10 +12:00
Robin Bygrave e1d6bf5961 No effective change - BeanPropertyAssocOne - importedPrimaryKey never set 2015-08-02 09:04:46 +12:00
Robin Bygrave 8e546bde0b No effective change - remove unused methods 2015-08-02 09:04:07 +12:00
Robin Bygrave 29a97d84a1 No effective change - format only 2015-08-02 08:55:36 +12:00
Robin Bygrave c526b3ef57 DataSourcePool - use IllegalArgumentException - remove need for DataSourceException 2015-08-02 08:54:00 +12:00
Robin Bygrave 032721d246 No effective change - remove unused 2015-08-02 08:51:40 +12:00
Robin Bygrave 0731084ec0 No effective change - remove unused 2015-08-02 08:47:37 +12:00
Robin Bygrave 11a3e49daa No effective change - remove unused 2015-08-02 08:41:10 +12:00
Robin Bygrave 68481844ee No effective change - param always true 2015-08-02 08:24:44 +12:00
Robin Bygrave 96a9def513 No effective change - LoadBeanRequest / LoadManyRequest cleanup of constructors 2015-08-01 22:35:35 +12:00
Robin Bygrave 98a4f046ee No effective change - format only 2015-08-01 22:21:08 +12:00
Robin Bygrave 9db8c941dc No effective change - SplitName - extract constant 2015-08-01 22:20:24 +12:00
Robin Bygrave fd4a6906bd No effective change - SqlTreeNodeBean cleanup - always same value params 2015-08-01 22:17:50 +12:00
Robin Bygrave da65256208 No effective change - ArrayStack cleanup 2015-08-01 22:00:00 +12:00
Robin Bygrave 0d2615522f No effective change - suppress warnings, simplify if 2015-08-01 21:16:03 +12:00
Robin Bygrave 6e5e5fb666 No effective change - remove unused assignment 2015-08-01 21:07:57 +12:00
Robin Bygrave 8005ef8432 No effective change - simplify if 2015-08-01 21:07:09 +12:00
Robin Bygrave 49fe97bbe4 No effective change - simplify if 2015-08-01 21:06:36 +12:00
Robin Bygrave 95ab97df73 No effective change - add code inspection suppression comments 2015-08-01 21:01:53 +12:00
Robin Bygrave 3be9833ee0 No effective change - DeployBeanPropertyLists cleanup - Assoc One / Many types when collected 2015-08-01 20:58:43 +12:00
Robin Bygrave b82223dc1d No effective change - add code inspection suppression comments 2015-08-01 20:41:50 +12:00
Robin Bygrave 17d97623d5 No effective change - add test HashQueryPlanTest 2015-08-01 20:41:07 +12:00
Robin Bygrave 1fca5ba008 BeanMap - code cleanup - while loop to foreach 2015-08-01 20:17:57 +12:00
Robin Bygrave 5bb97ee42f No effective change - code cleanup - remove unnecessary boxing 2015-08-01 20:12:09 +12:00
Robin Bygrave ae9a03e58c No effective change - code cleanup - remove unused 2015-08-01 20:11:21 +12:00
Robin Bygrave ca12761fb2 No effective change - code cleanup - remove unused 2015-08-01 20:06:13 +12:00
Robin Bygrave 18a61416fd No effective change - code cleanup - unused imports 2015-08-01 20:03:31 +12:00
Robin Bygrave 37ff2c7227 No effective change - code cleanup - removed unused param 2015-08-01 20:02:19 +12:00
Robin Bygrave af4018403b No effective change - code cleanup - removed unused param 2015-08-01 19:59:54 +12:00
Robin Bygrave d3b9bde5c2 No effective change - code cleanup - removed unused param 2015-08-01 19:59:01 +12:00
Robin Bygrave d704fef294 No effective change - code cleanup - removed unused param 2015-08-01 19:57:53 +12:00
Robin Bygrave bb4bb64795 No effective change - code cleanup - removed unused param 2015-08-01 19:55:52 +12:00
Robin Bygrave 402ab092d8 No effective change - code cleanup - removed unused param 2015-08-01 19:53:07 +12:00
Robin Bygrave 9769e4b574 No effective change - code cleanup - removed unused param 2015-08-01 19:47:05 +12:00
Robin Bygrave e19fe5ccd3 No effective change - code cleanup - removed unused param 2015-08-01 19:42:39 +12:00
Robin Bygrave 11963e1ff7 No effective change - code cleanup - removed unused param 2015-08-01 19:41:07 +12:00
Robin Bygrave ec0d4fbd07 No effective change - code cleanup - removed unused param 2015-08-01 19:38:40 +12:00
Robin Bygrave 4e66e348fc No effective change - code cleanup - removed unused param 2015-08-01 19:36:52 +12:00
Robin Bygrave eb6fce5a72 No effective change - code cleanup - removed unused param - TypeManager 2015-08-01 19:33:48 +12:00
Robin Bygrave 21b33bb9cd No effective change - code cleanup - removed unused BeanCollectionParams 2015-08-01 19:30:06 +12:00
Robin Bygrave 430b3cff96 No effective change - code cleanup - removed not required throws 2015-08-01 19:29:09 +12:00
Robin Bygrave 334a8b66bd No effective change - code cleanup - removed not required throws 2015-08-01 19:20:51 +12:00
Robin Bygrave 204b9ca6e5 No effective change - code cleanup - return void (unused return values), remove unused methods 2015-08-01 17:54:06 +12:00
Robin Bygrave 93f13113e6 No effective change - code cleanup - return void (unused return values) 2015-08-01 17:51:04 +12:00
Robin Bygrave ca1f95df7a No effective change - code cleanup - remove unused 2015-08-01 17:40:40 +12:00
Robin Bygrave 0c9bcca584 No effective change - code cleanup - BeanPropertyOverride - unused override of sql formula 2015-08-01 17:21:09 +12:00
Robin Bygrave a27433dc11 No effective change - code cleanup - unused params 2015-08-01 17:16:33 +12:00
Robin Bygrave dbd789f4be No effective change - suppress warnings in test 2015-08-01 16:56:12 +12:00
Robin Bygrave 7efbffb46d No effective change - format only 2015-08-01 09:11:04 +12:00
Robin Bygrave 559383a810 No effective change - format only 2015-08-01 09:02:34 +12:00
Robin Bygrave 1897ac67a0 No effective change - OrmQueryDetail - remove unnecessary if, simplify if 2015-08-01 09:01:43 +12:00
Robin Bygrave 4f2d669897 No effective change - format only 2015-08-01 08:54:49 +12:00
Robin Bygrave f50b18556e No effective change - SqlTreeBuilder , remove unnecessary null check 2015-08-01 08:51:40 +12:00
Robin Bygrave 1dc8a7f314 Add int getPageSize() to PagedList 2015-08-01 08:42:37 +12:00
Robin Bygrave b526d07eed No effective change - remove unused methods and parameters, simplify if 2015-08-01 08:42:09 +12:00
Robin Bygrave 97cd0909e8 No effective change - format only 2015-07-31 23:10:26 +12:00
Robin Bygrave 39cb85fda6 No effective change - remove unused BindValue comment 2015-07-31 23:09:31 +12:00
Robin Bygrave 498f567e37 No effective change - format only 2015-07-31 23:03:17 +12:00
Robin Bygrave 99cecd6756 No effective change - simplify if, remove unused 2015-07-31 23:02:17 +12:00
Robin Bygrave 7ab374b4ee No effective change - format only 2015-07-31 22:59:02 +12:00
Robin Bygrave 22d36bd1c4 No effective change - remove unused 2015-07-31 22:55:58 +12:00
Robin Bygrave ebc4d9fdc5 No effective change - format only 2015-07-31 22:52:59 +12:00
Robin Bygrave b1c41a58f2 No effective change - remove unused 2015-07-31 22:51:45 +12:00
Robin Bygrave 40710f788d No effective change - remove unused 2015-07-31 22:49:13 +12:00
Robin Bygrave 5513c46f78 No effective change - format only 2015-07-31 22:47:37 +12:00
Robin Bygrave 8879bd2be8 No effective change - format only 2015-07-31 22:46:20 +12:00
Robin Bygrave 4ab8ced4a3 No effective change - remove unused 2015-07-31 22:45:40 +12:00
Robin Bygrave 5bb9e1b188 No effective change - format only 2015-07-31 22:45:32 +12:00
Robin Bygrave db97d4576f No effective change - code cleanup - remove unused for GenerateDmlRequest 2015-07-31 22:42:28 +12:00
Robin Bygrave c581fa27ab No effective change - code cleanup - remove unused 2015-07-31 22:29:32 +12:00
Robin Bygrave bef4e476d7 No effective change - code cleanup - remove unused 2015-07-31 22:26:44 +12:00
Robin Bygrave e30e35bf4f No effective change - code cleanup - remove unused 2015-07-31 22:25:09 +12:00
Robin Bygrave 2e1f02163c No effective change - code cleanup - remove unused - TableJoin properties 2015-07-31 22:22:57 +12:00
Robin Bygrave 1ce84ec343 No effective change - code cleanup - remove unused - methods 2015-07-31 22:06:34 +12:00
Robin Bygrave 6dc21ce69b No effective change - code cleanup - remove unused - methods 2015-07-31 22:03:45 +12:00
Robin Bygrave 8d5621248f No effective change - code cleanup - remove unused - objects 2015-07-31 22:00:52 +12:00
Robin Bygrave b73cc378b5 No effective change - code cleanup - remove unused - methods 2015-07-31 21:57:26 +12:00
Robin Bygrave 564c7b8317 No effective change - code cleanup - remove unused - methods 2015-07-31 21:55:35 +12:00
Robin Bygrave f4a61cddaf No effective change - code cleanup - remove unused - methods 2015-07-31 21:51:48 +12:00
Robin Bygrave 456f5c1d6a No effective change - code cleanup - remove unused - BeanSqlSelect 2015-07-31 21:48:34 +12:00
Robin Bygrave ae0404b1a7 No effective change - code cleanup - BeanRequest remove unused 2015-07-31 21:46:17 +12:00
Robin Bygrave 31f91e571d No effective change - code cleanup - format only 2015-07-31 21:44:08 +12:00
Robin Bygrave 20acd56bb9 No effective change - code cleanup - format only 2015-07-31 21:43:38 +12:00
Robin Bygrave a764006523 No effective change - code cleanup - remove unused propMap 2015-07-31 21:43:23 +12:00
Robin Bygrave 84b8777c2b No effective change - code cleanup - BeanPropertyAssoc cleanup 2015-07-31 21:41:28 +12:00
Robin Bygrave c0fc7d69a6 No effective change - code cleanup - remove unused validateCascade property 2015-07-31 21:38:05 +12:00
Robin Bygrave 4807ca32be No effective change - code cleanup - remove unused methods 2015-07-31 21:33:05 +12:00
Robin Bygrave 4c841a8f9f No effective change - code cleanup - remove unused BeanPathUpdate 2015-07-31 21:32:36 +12:00
Robin Bygrave 6babebfec5 No effective change - code cleanup - simplify if 2015-07-31 21:28:36 +12:00
Robin Bygrave 660666a28b No effective change - code cleanup - removed unused logger 2015-07-31 21:25:41 +12:00
Robin Bygrave 34550dd778 No effective change - code cleanup - BeanIdList - removed unused methods 2015-07-31 21:24:05 +12:00
Robin Bygrave 64bc0636d7 No effective change - code cleanup - empty method 2015-07-31 21:09:35 +12:00
Robin Bygrave aa199da57d No effective change - code cleanup - SocketCluster 2015-07-31 21:07:22 +12:00
Robin Bygrave b265ffd7d6 No effective change - code cleanup - ResourceSource 2015-07-31 21:02:31 +12:00
Robin Bygrave 00f4aee80a No effective change - code cleanup - remove unused throws exception 2015-07-31 20:58:18 +12:00
Robin Bygrave d6973ed88d No effective change - code cleanup - remove unused throws exception 2015-07-31 20:56:26 +12:00
Robin Bygrave 2ada43f6ba No effective change - code cleanup - remove unused throws exception 2015-07-31 20:53:31 +12:00
Robin Bygrave e800a18b31 No effective change - code cleanup - remove unused methods 2015-07-31 20:49:21 +12:00
Robin Bygrave ea5ceb61ca No effective change - code cleanup - BeanProperty - remove unused extraAttributeMap 2015-07-31 20:45:58 +12:00
Robin Bygrave 972609281f No effective change - code cleanup - BeanProperty - remove unused defaultValue 2015-07-31 20:43:30 +12:00
Robin Bygrave 4ea68ebce4 No effective change - code cleanup - IdBinder - remove unused method 2015-07-31 20:36:18 +12:00
Robin Bygrave d01c6262b6 No effective change - format only 2015-07-31 20:34:17 +12:00
Robin Bygrave 19e3d82d98 No effective change - code cleanup - BeanFkeyProperty 2015-07-31 20:32:27 +12:00
Robin Bygrave f06c1b83a9 No effective change - code cleanup - change return to void 2015-07-31 20:28:41 +12:00
Robin Bygrave ea504a93cf No effective change - code cleanup - remove redundant casts 2015-07-31 20:11:31 +12:00
Robin Bygrave 9fe47194ff No effective change - code cleanup - remove unnecessary boxing 2015-07-31 20:08:30 +12:00
Robin Bygrave ba3b1fea6f No effective change - code cleanup - suppress some warnings 2015-07-31 19:48:59 +12:00
Robin Bygrave 58088b2090 No effective change - code cleanup - remove unnecessary colon 2015-07-31 19:43:12 +12:00
Robin Bygrave cca7a505a3 No effective change - code cleanup - while to foreach on BeanList etc 2015-07-31 19:39:18 +12:00
Robin Bygrave ece7466117 No effective change - code cleanup - while to foreach 2015-07-31 16:51:43 +12:00
Robin Bygrave 3451280679 No effective change - code cleanup - while to foreach 2015-07-31 16:51:12 +12:00
Robin Bygrave bef2894949 No effective change - code cleanup - StringBuffer to StringBuilder 2015-07-31 15:02:46 +12:00
Robin Bygrave 06b6638926 No effective change - code cleanup - string indexOf to contains 2015-07-31 15:00:02 +12:00
Robin Bygrave 53cf6c162c No effective change - code cleanup - simplify if 2015-07-31 14:51:34 +12:00
Robin Bygrave 069b83b78d No effective change - code cleanup - unused imports 2015-07-31 14:37:13 +12:00
Robin Bygrave c0c56c0040 No effective change - code cleanup - remove redundant overrides 2015-07-31 14:14:25 +12:00
Robin Bygrave 92c298b848 No effective change - code cleanup - duplicate throws 2015-07-31 14:08:12 +12:00
Robin Bygrave 831d2a6179 No effective change - add final modifier 2015-07-31 14:07:09 +12:00
Robin Bygrave 90886193c0 No effective change - add final modifier 2015-07-31 14:02:38 +12:00
Robin Bygrave deed0bb01d No effective change - add final modifier 2015-07-31 13:53:10 +12:00
Robin Bygrave 7f2c705b94 No effective change - remove unused 2015-07-31 13:42:09 +12:00
Robin Bygrave 6c0401b191 No effective change - remove unused 2015-07-31 13:34:32 +12:00
Robin Bygrave 331d28b512 No effective change - Code cleanup, remove unused param 2015-07-31 13:33:35 +12:00
Robin Bygrave 9fd936c521 No effective change - Code cleanup, remove redundant variables 2015-07-31 13:29:42 +12:00
Robin Bygrave 4a13fc307b No effective change - Code cleanup, remove unnecessary return 2015-07-31 13:25:54 +12:00
Robin Bygrave adef15ce2b No effective change - Code cleanup, simplified if 2015-07-31 13:23:49 +12:00
Robin Bygrave 88340618af No effective change - Code cleanup, simplified if 2015-07-31 13:20:23 +12:00
Robin Bygrave 49b97887b0 No effective change - Code cleanup,remove unnecessary comma 2015-07-31 13:18:26 +12:00
Robin Bygrave 6843c72149 No effective change - Code cleanup,remove unnecessary public modifier on interfaces 2015-07-31 13:16:36 +12:00
Robin Bygrave f78c217d83 No effective change - Code cleanup,remove unnecessary public modifier on interfaces 2015-07-31 13:11:08 +12:00
Robin Bygrave ede91ecf78 No effective change - Code cleanup,remove unnecessary public modifier on interfaces 2015-07-31 13:08:07 +12:00
Robin Bygrave efe4e69ed1 No effective change - Code cleanup,remove unnecessary public modifier on interfaces 2015-07-31 13:05:22 +12:00
Robin Bygrave 8a3d9edd34 No effective change - Code cleanup, convert unnecessary fields to local vars 2015-07-31 13:00:53 +12:00
Robin Bygrave b9aa76c367 [maven-release-plugin] prepare for next development iteration 2015-07-30 06:45:59 +12:00
1019 changed files with 61308 additions and 23716 deletions
+3
View File
@@ -7,8 +7,11 @@
target/
logs/
log/
ebean-autotune.xml
ebean-profiling*.xml
/db
/mydb.db
!src/test/ddl-review/*.sql
# Intellij project files
+1 -10
View File
@@ -5,16 +5,7 @@
Ebean ORM
==============
[http://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
Maven Dependency
----------------
<dependency>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>4.7.3</version>
</dependency>
[https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
[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")
+34 -10
View File
@@ -9,7 +9,7 @@
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>6.2.2</version>
<version>6.10.1</version>
<packaging>jar</packaging>
<name>avaje-ebeanorm</name>
@@ -61,6 +61,14 @@
<version>1.7.7</version>
</dependency>
<!-- provided scope for Spring boot loader classpath scanning support -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-loader</artifactId>
<version>1.2.7.RELEASE</version>
<scope>provided</scope>
</dependency>
<!-- provided scope for JsonNode support -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
@@ -109,10 +117,24 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1201-jdbc41</version>
<version>9.4-1202-jdbc41</version>
<scope>provided</scope>
</dependency>
<!--<dependency>-->
<!--<groupId>oracle</groupId>-->
<!--<artifactId>oracle-jdbc</artifactId>-->
<!--<version>7.0</version>-->
<!--<scope>test</scope>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>microsoft</groupId>-->
<!--<artifactId>sqlserver-jdbc</artifactId>-->
<!--<version>4.2</version>-->
<!--<scope>test</scope>-->
<!--</dependency>-->
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>okhttp</artifactId>
@@ -130,15 +152,17 @@
<dependency>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-agent</artifactId>
<version>4.5.1</version>
<version>4.7.1</version>
<scope>test</scope>
</dependency>
<!-- Provided scope so that the H2HistoryTrigger can live in Ebean core
and not require a separate module for it -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.182</version>
<scope>test</scope>
<version>1.4.189</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -195,7 +219,7 @@
<plugin>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
<version>4.5.1</version>
<version>4.7.1</version>
<executions>
<!-- Not going to enhance Model bean -->
<execution>
@@ -204,7 +228,7 @@
<configuration>
<classSource>target/test-classes</classSource>
<packages>com.avaje.tests.**</packages>
<transformArgs>debug=1</transformArgs>
<transformArgs>debug=2</transformArgs>
</configuration>
<goals>
<goal>enhance</goal>
@@ -249,11 +273,11 @@
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<doctitle>Ebean 4</doctitle>
<doctitle>Ebean 6</doctitle>
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
<source>1.8</source>
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
<excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
<excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util:com.avaje.ebean.dbmigration.ddlgeneration:com.avaje.ebean.dbmigration.migration:com.avaje.ebean.dbmigration.migrationreader:com.avaje.ebean.dbmigration.model</excludePackageNames>
<docletArtifact>
<groupId>org.avaje</groupId>
<artifactId>pygments-doclet</artifactId>
@@ -1,137 +0,0 @@
package com.avaje.ebean;
/**
* Administrative control of Autofetch during runtime.
*/
public interface AdminAutofetch {
/**
* Return true if profiling is enabled.
*/
boolean isProfiling();
/**
* Set to true to enable profiling.
*/
void setProfiling(boolean enable);
/**
* Return true if autoFetch automatic query tuning is enabled.
*/
boolean isQueryTuning();
/**
* Set to true to enable autoFetch automatic query tuning.
*/
void setQueryTuning(boolean enable);
/**
* Returns the rate which profiling is collected. This is an int between 0 and
* 100.
*/
double getProfilingRate();
/**
* Set the rate at which profiling is collected after the base.
*
* @param rate
* a int between 0 and 100.
*/
void setProfilingRate(double rate);
/**
* Return the number of queries profiled after which profiling is collected at
* a percentage rate.
*/
int getProfilingBase();
/**
* Set a base number of queries to profile per query point.
* <p>
* After this amount of profiling has been obtained profiling is collected at
* the Profiling Percentage rate.
* </p>
*/
void setProfilingBase(int profilingBase);
/**
* Return the minimum number of queries profiled before autoFetch will start
* automatically tuning the queries.
* <p>
* This could be one which means start autoFetch tuning after the first
* profiling information is collected.
* </p>
*/
int getProfilingMin();
/**
* Set the minimum number of queries profiled per query point before autoFetch
* will automatically tune the queries.
* <p>
* Increasing this number will mean more profiling is collected before
* autoFetch starts tuning the query.
* </p>
*/
void setProfilingMin(int autoFetchMinThreshold);
/**
* Fire a garbage collection (hint to the JVM). Assuming garbage collection
* fires this will gather the usage profiling information.
*/
String collectUsageViaGC();
/**
* This will take the current profiling information and update the "tuned
* query detail".
* <p>
* This is done periodically and can also be manually invoked.
* </p>
*
* @return a summary of the updates that occurred
*/
String updateTunedQueryInfo();
/**
* Clear all the tuned query info.
* <p>
* Should only need do this for testing and playing around.
* </p>
*
* @return the amount of tuned query information cleared.
*/
int clearTunedQueryInfo();
/**
* Clear all the profiling information.
* <p>
* This means the profiling information will need to be re-gathered.
* </p>
* <p>
* Should only need do this for testing and playing around.
* </p>
*
* @return the amount of profiled information cleared.
*/
int clearProfilingInfo();
/**
* Clear the query execution statistics.
*/
void clearQueryStatistics();
/**
* Return the number of queries tuned by AutoFetch.
*/
int getTotalTunedQueryCount();
/**
* Return the size of the TuneQuery map.
*/
int getTotalTunedQuerySize();
/**
* Return the size of the profile map.
*/
int getTotalProfileSize();
}
@@ -0,0 +1,14 @@
package com.avaje.ebean;
/**
* Administrative control of AutoTune during runtime.
*/
public interface AutoTune {
/**
* Fire a garbage collection (hint to the JVM). Assuming garbage collection
* fires this will gather remaining usage profiling information.
*/
void collectProfiling();
}
@@ -38,6 +38,33 @@ public interface BeanState {
*/
void setDisableLazyLoad(boolean disableLazyLoading);
/**
* Set the loaded state of the property given it's name.
*
* <p>
* Typically this would be used to set the loaded state of a property
* to false to ensure that the specific property is excluded from a
* stateless update.
* </p>
*
* <pre>{@code
*
* // populate a bean via say JSON
* User user = ...;
*
* // set loaded state on the email property to false so that
* // the email property is not included in a stateless update
* Ebean.getBeanState(user).setPropertyLoaded("email", false);
*
* user.update();
*
* }</pre>
*
*
* This will throw an IllegalArgumentException if the property is unknown.
*/
void setPropertyLoaded(String propertyName, boolean loaded);
/**
* For partially populated beans returns the properties that are loaded on the
* bean.
@@ -80,7 +80,7 @@ public interface CallableSql {
/**
* Return the label that is put into the transaction log.
*/
public String getLabel();
String getLabel();
/**
* Set the label that is put in the transaction log.
@@ -80,17 +80,16 @@ final class DRawSqlColumnsParser {
return new ColumnMapping.Column(indexPos++, sb.toString(), split[split.length - 1]);
}
private int nextComma() {
private void nextComma() {
boolean inQuote = false;
while (pos < end) {
char c = sqlSelect.charAt(pos);
if (c == '\'') {
inQuote = !inQuote;
} else if (!inQuote && c == ',') {
return pos;
return;
}
pos++;
}
return pos;
}
}
@@ -24,7 +24,7 @@ class DRawSqlParser {
private int placeHolderAndWhere;
private int placeHolderHaving;
private int placeHolderAndHaving;
private boolean hasPlaceHolders;
private final boolean hasPlaceHolders;
private int selectPos = -1;
private int distinctPos = -1;
@@ -98,19 +98,7 @@ class DRawSqlParser {
}
private boolean hasPlaceHolders() {
if (placeHolderWhere > -1) {
return true;
}
if (placeHolderAndWhere > -1) {
return true;
}
if (placeHolderHaving > -1) {
return true;
}
if (placeHolderAndHaving > -1) {
return true;
}
return false;
return placeHolderWhere > -1 || placeHolderAndWhere > -1 || placeHolderHaving > -1 || placeHolderAndHaving > -1;
}
/**
+6 -6
View File
@@ -22,7 +22,7 @@ import com.avaje.ebean.text.json.JsonContext;
/**
* This Ebean object is effectively a singleton that holds a map of registered
* {@link EbeanServer}s. It additionally provides a convenient way to use the
* 'default/primary' EbeanServer.
* 'default' EbeanServer.
* <p>
* If you are using a Dependency Injection framework such as
* <strong>Spring</strong> or <strong>Guice</strong> you will probably
@@ -168,9 +168,9 @@ public final class Ebean {
defaultServer = getWithCreate(defaultName.trim());
}
}
} catch (RuntimeException e) {
} catch (Throwable e) {
logger.error("Error trying to create the default EbeanServer", e);
throw e;
throw new RuntimeException(e);
}
}
@@ -178,7 +178,7 @@ public final class Ebean {
if (defaultServer == null) {
String msg = "The default EbeanServer has not been defined?";
msg += " This is normally set via the ebean.datasource.default property.";
msg += " Otherwise it should be registered programatically via registerServer()";
msg += " Otherwise it should be registered programmatically via registerServer()";
throw new PersistenceException(msg);
}
return defaultServer;
@@ -217,8 +217,8 @@ public final class Ebean {
/**
* Register a server so we can get it by its name.
*/
private void register(EbeanServer server, boolean isPrimaryServer) {
registerWithName(server.getName(), server, isPrimaryServer);
private void register(EbeanServer server, boolean isDefaultServer) {
registerWithName(server.getName(), server, isDefaultServer);
}
private void registerWithName(String name, EbeanServer server, boolean isDefaultServer) {
+42 -19
View File
@@ -1,21 +1,21 @@
package com.avaje.ebean;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import com.avaje.ebean.annotation.CacheStrategy;
import com.avaje.ebean.cache.ServerCacheManager;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.meta.MetaInfoManager;
import com.avaje.ebean.plugin.SpiServer;
import com.avaje.ebean.text.csv.CsvReader;
import com.avaje.ebean.text.json.JsonContext;
import org.jetbrains.annotations.Nullable;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Provides the API for fetching and saving beans to a particular DataSource.
* <p>
@@ -106,10 +106,9 @@ public interface EbeanServer {
void shutdown(boolean shutdownDataSource, boolean deregisterDriver);
/**
* Return the AdminAutofetch which is used to control and configure the
* Autofetch service at runtime.
* Return AutoTune which is used to control the AutoTune service at runtime.
*/
AdminAutofetch getAdminAutofetch();
AutoTune getAutoTune();
/**
* Return the name. This is used with {@link Ebean#getServer(String)} to get a
@@ -128,6 +127,11 @@ public interface EbeanServer {
*/
MetaInfoManager getMetaInfoManager();
/**
* Return the extended API intended for use by plugins.
*/
SpiServer getPluginApi();
/**
* Return the BeanState for a given entity bean.
* <p>
@@ -1108,6 +1112,21 @@ public interface EbeanServer {
@Nullable
<T> T findUnique(Query<T> query, Transaction transaction);
/**
* Execute as a delete query deleting the 'root level' beans that match the predicates
* in the query.
* <p>
* Note that if the query includes joins then the generated delete statement may not be
* optimal depending on the database platform.
* </p>
*
* @param query the query used for the delete
* @param transaction the transaction to use (can be null)
* @param <T> the type of entity bean to fetch.
* @return the number of beans/rows that were deleted
*/
<T> int delete(Query<T> query, Transaction transaction);
/**
* Execute the sql query returning a list of MapBean.
* <p>
@@ -1205,7 +1224,6 @@ public interface EbeanServer {
* public class Order { ...
*
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
* @JoinColumn(name="order_id")
* List<OrderDetail> details;
* ...
* }
@@ -1235,9 +1253,9 @@ public interface EbeanServer {
void delete(Object bean) throws OptimisticLockException;
/**
* Delete all the beans in the collection.
* Delete the bean with an explicit transaction.
*/
int deleteAll(Collection<?> beans) throws OptimisticLockException;
void delete(Object bean, Transaction transaction) throws OptimisticLockException;
/**
* Delete the bean given its type and id.
@@ -1249,6 +1267,16 @@ public interface EbeanServer {
*/
int delete(Class<?> beanType, Object id, Transaction transaction);
/**
* Delete all the beans in the collection.
*/
int deleteAll(Collection<?> beans) throws OptimisticLockException;
/**
* Delete all the beans in the collection using an explicit transaction.
*/
int deleteAll(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
/**
* Delete several beans given their type and id values.
*/
@@ -1260,11 +1288,6 @@ public interface EbeanServer {
*/
void deleteAll(Class<?> beanType, Collection<?> ids, Transaction transaction);
/**
* Delete the bean with an explicit transaction.
*/
void delete(Object bean, Transaction transaction) throws OptimisticLockException;
/**
* Execute a Sql Update Delete or Insert statement. This returns the number of
* rows that where updated, deleted or inserted. If is executed in batch then
@@ -36,6 +36,51 @@ import java.util.Map;
*/
public interface ExpressionFactory {
/**
* Path exists - for the given path in a JSON document.
*/
Expression jsonExists(String propertyName, String path);
/**
* Path does not exist - for the given path in a JSON document.
*/
Expression jsonNotExists(String propertyName, String path);
/**
* Equal to - for the given path in a JSON document.
*/
Expression jsonEqualTo(String propertyName, String path, Object val);
/**
* Not Equal to - for the given path in a JSON document.
*/
Expression jsonNotEqualTo(String propertyName, String path, Object val);
/**
* Greater than - for the given path in a JSON document.
*/
Expression jsonGreaterThan(String propertyName, String path, Object val);
/**
* Greater than or equal to - for the given path in a JSON document.
*/
Expression jsonGreaterOrEqual(String propertyName, String path, Object val);
/**
* Less than - for the given path in a JSON document.
*/
Expression jsonLessThan(String propertyName, String path, Object val);
/**
* Less than or equal to - for the given path in a JSON document.
*/
Expression jsonLessOrEqualTo(String propertyName, String path, Object val);
/**
* Between - for the given path in a JSON document.
*/
Expression jsonBetween(String propertyName, String path, Object lowerValue, Object upperValue);
/**
* Equal To - property equal to the given value.
*/
+196 -17
View File
@@ -107,6 +107,18 @@ public interface ExpressionList<T> extends Serializable {
*/
Query<T> asOf(Timestamp asOf);
/**
* Execute as a delete query deleting the 'root level' beans that match the predicates
* in the query.
* <p>
* Note that if the query includes joins then the generated delete statement may not be
* optimal depending on the database platform.
* </p>
*
* @return the number of beans/rows that were deleted.
*/
int delete();
/**
* Execute the query iterating over the results.
*
@@ -244,6 +256,15 @@ public interface ExpressionList<T> extends Serializable {
*/
List<Version<T>> findVersions();
/**
* 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.
* </p>
*/
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
/**
* Add some filter predicate expressions to the many property.
*/
@@ -257,6 +278,24 @@ public interface ExpressionList<T> extends Serializable {
*/
Query<T> select(String properties);
/**
* Set whether this query uses DISTINCT.
* <p>
* The select() clause MUST be specified when setDistinct(true) is set. The reason for this is that
* generally ORM queries include the "id" property and this doesn't make sense for distinct queries.
* </p>
* <pre>{@code
*
* List<Customer> customers =
* Ebean.find(Customer.class)
* .setDistinct(true)
* .select("name") // only select the customer name
* .findList();
*
* }</pre>
*/
Query<T> setDistinct(boolean distinct);
/**
* Set the first row to fetch.
*
@@ -285,6 +324,13 @@ public interface ExpressionList<T> extends Serializable {
*/
Query<T> setUseCache(boolean useCache);
/**
* Set to true to use the query for executing this query.
*
* @see Query#setUseQueryCache(boolean)
*/
Query<T> setUseQueryCache(boolean useCache);
/**
* Add expressions to the having clause.
* <p>
@@ -299,20 +345,136 @@ public interface ExpressionList<T> extends Serializable {
*/
ExpressionList<T> where();
/**
* Path exists - for the given path in a JSON document.
*
* <pre>{@code
*
* where().jsonExists("content", "path.other")
*
* }</pre>
*
* @param propertyName the property that holds a JSON document
* @param path the nested path in the JSON document in dot notation
*/
ExpressionList<T> jsonExists(String propertyName, String path);
/**
* Path does not exist - for the given path in a JSON document.
*
* <pre>{@code
*
* where().jsonNotExists("content", "path.other")
*
* }</pre>
*
* @param propertyName the property that holds a JSON document
* @param path the nested path in the JSON document in dot notation
*/
ExpressionList<T> jsonNotExists(String propertyName, String path);
/**
* Equal to expression for the value at the given path in the JSON document.
*
* <pre>{@code
*
* where().jsonEqualTo("content", "path.other", 34)
*
* }</pre>
*
* @param propertyName the property that holds a JSON document
* @param path the nested path in the JSON document in dot notation
* @param value the value used to test against the document path's value
*/
ExpressionList<T> jsonEqualTo(String propertyName, String path, Object value);
/**
* Not Equal to - for the given path in a JSON document.
*
* <pre>{@code
*
* where().jsonNotEqualTo("content", "path.other", 34)
*
* }</pre>
*
* @param propertyName the property that holds a JSON document
* @param path the nested path in the JSON document in dot notation
* @param value the value used to test against the document path's value
*/
ExpressionList<T> jsonNotEqualTo(String propertyName, String path, Object value);
/**
* Greater than - for the given path in a JSON document.
*
* <pre>{@code
*
* where().jsonGreaterThan("content", "path.other", 34)
*
* }</pre>
*/
ExpressionList<T> jsonGreaterThan(String propertyName, String path, Object value);
/**
* Greater than or equal to - for the given path in a JSON document.
*
* <pre>{@code
*
* where().jsonGreaterOrEqual("content", "path.other", 34)
*
* }</pre>
*/
ExpressionList<T> jsonGreaterOrEqual(String propertyName, String path, Object value);
/**
* Less than - for the given path in a JSON document.
*
* <pre>{@code
*
* where().jsonLessThan("content", "path.other", 34)
*
* }</pre>
*/
ExpressionList<T> jsonLessThan(String propertyName, String path, Object value);
/**
* Less than or equal to - for the given path in a JSON document.
*
* <pre>{@code
*
* where().jsonLessOrEqualTo("content", "path.other", 34)
*
* }</pre>
*/
ExpressionList<T> jsonLessOrEqualTo(String propertyName, String path, Object value);
/**
* Between - for the given path in a JSON document.
*
* <pre>{@code
*
* where().jsonBetween("content", "orderDate", lowerDateTime, upperDateTime)
*
* }</pre>
*/
ExpressionList<T> jsonBetween(String propertyName, String path, Object lowerValue, Object upperValue);
/**
* Add an Expression to the list.
* <p>
* This returns the list so that add() can be chained.
* </p>
*
* <pre class="code">
* Query&lt;Customer&gt; query = Ebean.createQuery(Customer.class);
*
* <pre>{@code
*
* Query<Customer> query = Ebean.find(Customer.class);
* query.where()
* .like(&quot;name&quot;,&quot;Rob%&quot;)
* .eq(&quot;status&quot;, Customer.ACTIVE);
* List&lt;Customer&gt; list = query.findList();
* .like("name","Rob%")
* .eq("status", Customer.ACTIVE);
*
* List<Customer> list = query.findList();
* ...
* </pre>
*
* }</pre>
*/
ExpressionList<T> add(Expression expr);
@@ -393,33 +555,36 @@ public interface ExpressionList<T> extends Serializable {
* those options such as case insensitive etc.
* </p>
*
* <pre class="code">
* <pre>{@code
*
* // create an example bean and set the properties
* // with the query parameters you want
* Customer example = new Customer();
* example.setName(&quot;Rob%&quot;);
* example.setNotes(&quot;%something%&quot;);
* 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(&quot;id&quot;, 2).findList();
* .gt("id", 2).findList();
*
* </pre>
* }</pre>
*
* Similarly you can create an ExampleExpression
*
* <pre>
* <pre>{@code
*
* Customer example = new Customer();
* example.setName(&quot;Rob%&quot;);
* example.setNotes(&quot;%something%&quot;);
* example.setName("Rob%");
* example.setNotes("%something%");
*
* // create a ExampleExpression with more control
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO).includeZeros();
*
* List&lt;Customer&gt; list = Ebean.find(Customer.class).where().add(qbe).findList();
* </pre>
* List<Customer> list = Ebean.find(Customer.class).where().add(qbe).findList();
*
* }</pre>
*/
ExpressionList<T> exampleLike(Object example);
@@ -547,6 +712,14 @@ public interface ExpressionList<T> extends Serializable {
* then they are not translated. logical property name names (not fully
* qualified) will still be translated to their physical name.
* </p>
*
* <h4>Example:</h4>
* <pre>{@code
*
* // use a database function
* raw("add_days(orderDate, 10) < ?", someDate)
*
* }</pre>
*/
ExpressionList<T> raw(String raw, Object value);
@@ -571,6 +744,12 @@ public interface ExpressionList<T> extends Serializable {
* then they are not translated. logical property name names (not fully
* qualified) will still be translated to their physical name.
* </p>
*
* <pre>{@code
*
* raw("orderQty < shipQty")
*
* }</pre>
*/
ExpressionList<T> raw(String raw);
+1 -1
View File
@@ -36,7 +36,7 @@ import java.util.Set;
* .sort(&quot;avgTimeMicros desc&quot;)
* .gt(&quot;executionCount&quot;, 0)
* .gt(&quot;lastQueryTime&quot;, nowMinus24Hrs)
* .eq(&quot;autofetchTuned&quot;, true)
* .eq(&quot;autoTuned&quot;, true)
* .maxRows(10)
* .filter(list);
*
+167
View File
@@ -0,0 +1,167 @@
package com.avaje.ebean;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* Intended to be used as a base class for 'Finder' implementations that can then
* be injected or used as public static fields on the associated entity bean.
* <p>
* These 'finders' are a place to organise all the finder methods for that bean type
* and specific finder methods are expected to be added (find by unique properties etc).
* </p>
*
* <h3>Testing</h3>
* <p>
* For testing the mocki-ebean project has the ability to replace the finder implementation
*
* </p>
* <pre>{@code
*
* public class CustomerFinder extends Finder<Customer> {
*
* public CustomerFinder() {
* super(Customer.class);
* }
*
* // Add your customer finder methods ...
*
* public Customer byName(String name) {
* return query().eq("name", name).findUnique();
* }
*
* public List<Customer> findNew() {
* return query()
* .eq("status", Customer.Status.NEW)
* .orderBy("name")
* .findList()
* }
* }
*
* @Entity
* public class Customer extends BaseModel {
*
* public static final CustomerFinder find = new CustomerFinder();
* ...
*
* }</pre>
*/
public class Finder<I, T> {
/**
* The entity bean type.
*/
private final Class<T> type;
/**
* The name of the EbeanServer, null for the default server.
*/
private final String serverName;
/**
* Create with the type of the entity bean.
*
* <pre>{@code
*
* public class CustomerFinder extends Finder<Customer> {
*
* public CustomerFinder() {
* super(Customer.class);
* }
*
* // ... add extra customer specific finder methods
* }
*
* @Entity
* public class Customer extends BaseModel {
*
* public static final CustomerFinder find = new CustomerFinder();
* ...
*
* }</pre>
*/
public Finder(Class<T> type) {
this.type = type;
this.serverName = null;
}
/**
* Create with the type of the entity bean and specific server name.
*/
public Finder(Class<T> type, String serverName) {
this.type = type;
this.serverName = serverName;
}
/**
* Return the underlying 'default' EbeanServer.
*
* <p>
* This provides full access to the API such as explicit transaction demarcation etc.
*
*/
public EbeanServer db() {
return Ebean.getServer(serverName);
}
/**
* Return typically a different EbeanServer to the default.
* <p>
* This is equivalent to {@link Ebean#getServer(String)}
*
* @param server
* The name of the EbeanServer. If this is null then the default EbeanServer is
* returned.
*/
public EbeanServer db(String server) {
return Ebean.getServer(server);
}
/**
* Creates an entity reference for this ID.
*
* <p>
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
*/
public T ref(I id) {
return db().getReference(type, id);
}
/**
* Retrieves an entity by ID.
*
* <p>
* Equivalent to {@link EbeanServer#find(Class, Object)}
*/
@Nullable
public T byId(I id) {
return db().find(type, id);
}
/**
* Delete a bean by Id.
* <p>
* Equivalent to {@link EbeanServer#delete(Class, Object)}
*/
public void deleteById(I id) {
db().delete(type, id);
}
/**
* Retrieves all entities of the given type.
*/
public List<T> all() {
return query().findList();
}
/**
* Creates a query.
* <p>
* Equivalent to {@link EbeanServer#find(Class)}
*/
public Query<T> query() {
return db().find(type);
}
}
@@ -2,7 +2,6 @@ package com.avaje.ebean;
import javax.persistence.PersistenceException;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+30 -4
View File
@@ -1,5 +1,6 @@
package com.avaje.ebean;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebean.util.ClassUtil;
import org.jetbrains.annotations.Nullable;
@@ -193,7 +194,31 @@ public abstract class Model {
public void markAsDirty() {
db().markAsDirty(this);
}
/**
* Mark the property as unset or 'not loaded'.
* <p>
* This would be used to specify a property that we did not wish to include in a stateless update.
* </p>
* <pre>{@code
*
* // populate an entity bean from JSON or whatever
* User user = ...;
*
* // mark the email property as 'unset' so that it is not
* // included in a 'stateless update'
* user.markPropertyUnset("email");
*
* user.update();
*
* }</pre>
*
* @param propertyName the name of the property on the bean to be marked as 'unset'
*/
public void markPropertyUnset(String propertyName) {
((EntityBean)this)._ebean_getIntercept().setPropertyLoaded(propertyName, false);
}
/**
* Insert or update this entity depending on its state.
*
@@ -441,6 +466,7 @@ public abstract class Model {
*
* }</pre>
*/
@SuppressWarnings("unchecked")
public Find() {
this.serverName = null;
this.type = (Class<T>)ClassUtil.getSecondArgumentType(getClass());
@@ -835,10 +861,10 @@ public abstract class Model {
}
/**
* Create a query with explicit 'Autofetch' use.
* Create a query with explicit 'AutoTune' use.
*/
public Query<T> setAutofetch(boolean autofetch) {
return query().setAutofetch(autofetch);
public Query<T> setAutoTune(boolean autoTune) {
return query().setAutoTune(autoTune);
}
/**
+27 -2
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>(2);
this.list = new ArrayList<Property>(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>(2);
this.list = new ArrayList<Property>(3);
parse(orderByClause);
}
@@ -83,6 +83,19 @@ public final class OrderBy<T> implements Serializable {
return query;
}
/**
* Return true if the property is known to be contained in the order by clause.
*/
public boolean containsProperty(String propertyName) {
for (int i = 0; i < list.size(); i++) {
if (propertyName.equals(list.get(i).getProperty())) {
return true;
}
}
return false;
}
/**
* Return a copy of this OrderBy with the path trimmed.
*/
@@ -185,6 +198,18 @@ public final class OrderBy<T> implements Serializable {
return list.hashCode();
}
/**
* Clear the orderBy removing any current order by properties.
* <p>
* This is intended to be used when some code creates a query with a
* 'default' order by clause and some other code may clear the 'default'
* order by clause and replace.
* </p>
*/
public void clear() {
list.clear();
}
/**
* A property and its ascending descending order.
*/
@@ -159,6 +159,11 @@ public interface PagedList<T> {
*/
int getPageIndex();
/**
* Return the page size used for this query.
*/
int getPageSize();
/**
* Return true if there is a next page.
* <p>
+60 -11
View File
@@ -67,9 +67,9 @@ import java.util.Set;
* ...
* }</pre>
*
* <h3>Autofetch</h3>
* <h3>AutoTune</h3>
* <p>
* Ebean has built in support for "Autofetch". This is a mechanism where a query
* Ebean has built in support for "AutoTune". This is a mechanism where a query
* can be automatically tuned based on profiling information that is collected.
* </p>
* <p>
@@ -78,7 +78,7 @@ import java.util.Set;
* more.
* </p>
* <p>
* It is expected that Autofetch will be the default approach for many queries
* It is expected that AutoTune will be the default approach for many queries
* in a system. It is possibly not as useful where the result of a query is sent
* to a remote client or where there is some requirement for "Read Consistency"
* guarantees.
@@ -338,23 +338,23 @@ public interface Query<T> extends Serializable {
ExpressionFactory getExpressionFactory();
/**
* Returns true if this query was tuned by autoFetch.
* Returns true if this query was tuned by autoTune.
*/
boolean isAutofetchTuned();
boolean isAutoTuned();
/**
* Explicitly specify whether to use Autofetch for this query.
* Explicitly specify whether to use AutoTune for this query.
* <p>
* If you do not call this method on a query the "Implicit Autofetch mode" is
* used to determine if Autofetch should be used for a given query.
* If you do not call this method on a query the "Implicit AutoTune mode" is
* used to determine if AutoTune should be used for a given query.
* </p>
* <p>
* Autofetch can add additional fetch paths to the query and specify which
* AutoTune can add additional fetch paths to the query and specify which
* properties are included for each path. If you have explicitly defined some
* fetch paths Autofetch will not remove.
* fetch paths AutoTune will not remove them.
* </p>
*/
Query<T> setAutofetch(boolean autofetch);
Query<T> setAutoTune(boolean autoTune);
/**
* Set the default lazy loading batch size to use.
@@ -366,6 +366,16 @@ public interface Query<T> extends Serializable {
*/
Query<T> setLazyLoadBatchSize(int lazyLoadBatchSize);
/**
* Disable read auditing for this query.
* <p>
* This is intended to be used when the query is not a user initiated query and instead
* part of the internal processing in an application to load a cache or document store etc.
* In these cases we don't want the query to be part of read auditing.
* </p>
*/
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
@@ -723,12 +733,38 @@ public interface Query<T> extends Serializable {
/**
* 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.
* </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.
* </p>
*/
List<Version<T>> findVersions();
/**
* 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.
* </p>
*/
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
/**
* Execute as a delete query deleting the 'root level' beans that match the predicates
* in the query.
* <p>
* Note that if the query includes joins then the generated delete statement may not be
* optimal depending on the database platform.
* </p>
*
* @return the number of beans/rows that were deleted.
*/
int delete();
/**
* Return the count of entities this query should return.
* <p>
@@ -1129,6 +1165,19 @@ public interface Query<T> extends Serializable {
/**
* Set whether this query uses DISTINCT.
* <p>
* The select() clause MUST be specified when setDistinct(true) is set. The reason for this is that
* generally ORM queries include the "id" property and this doesn't make sense for distinct queries.
* </p>
* <pre>{@code
*
* List<Customer> customers =
* Ebean.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .findList();
*
* }</pre>
*/
Query<T> setDistinct(boolean isDistinct);
+1 -1
View File
@@ -153,7 +153,7 @@ public interface SqlRow extends Serializable, Map<String, Object> {
/**
* Put all the values from t into this map.
*/
void putAll(Map<? extends String, ? extends Object> t);
void putAll(Map<? extends String, ?> t);
/**
* Return the size of the map.
@@ -2,7 +2,6 @@ package com.avaje.ebean;
import com.avaje.ebean.config.PersistBatch;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import javax.persistence.RollbackException;
import java.io.Closeable;
@@ -290,7 +289,7 @@ public interface Transaction extends Closeable {
* <li>Transaction commit occurs</li>
* </ul>
*/
void flushBatch() throws PersistenceException, OptimisticLockException;
void flushBatch() throws PersistenceException;
/**
* Return the underlying Connection object.
+1 -1
View File
@@ -46,5 +46,5 @@ public enum TxType {
* If there is an existing transaction throws an Exception. Method runs
* without a transaction.
*/
NEVER;
NEVER
}
@@ -0,0 +1,34 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marks an entity bean as being included in the change logging.
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ChangeLog {
/**
* Specify if inserts should be explicitly Included or Excluded.
* <p>
* If not defined explicitly then the server default behaviour defined
* on ServerConfig is used.
* </p>
*/
ChangeLogInsertMode inserts() default ChangeLogInsertMode.DEFAULT;
/**
* When specified only include update requests that have at least one
* of the given properties as a dirty property.
* <p>
* This provides a way to filter requests to include in the change log such that
* only updates that include at least one of the given properties is included
* in the change log.
* </p>
*/
String[] updatesThatInclude() default {};
}
@@ -0,0 +1,22 @@
package com.avaje.ebean.annotation;
/**
* The mode used to determine if inserts should be included or not for a given bean type.
*/
public enum ChangeLogInsertMode {
/**
* Use the default behaviour as defined on ServerConfig.
*/
DEFAULT,
/**
* Include inserts in the change log.
*/
INCLUDE,
/**
* Exclude inserts in the change log.
*/
EXCLUDE
}
@@ -10,15 +10,24 @@ import java.lang.annotation.Target;
*
* @author rvbiljouw
*/
@Target({ElementType.FIELD})
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Index {
/**
* Name of the index
*
* @return index name
* Name of the index. If left blank a name is derived using the built in naming convention.
*/
String value() default "";
String name() default "";
/**
* If set true indicates this is a unique index.
*/
boolean unique() default false;
/**
* When placed on the class (rather than field) you can specify the columns
* to include in the index in order.
*/
String[] columnNames() default {};
}
@@ -0,0 +1,15 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marks an entity bean as being included in read auditing.
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ReadAudit {
}
@@ -6,7 +6,7 @@ import java.util.Arrays;
/**
* Represent the call stack (stack trace elements).
* <p>
* Used with a query to identify a CallStackQuery for AutoFetch automatic query
* Used with a query to identify a CallStackQuery for AutoTune automatic query
* tuning.
* </p>
* <p>
@@ -26,16 +26,12 @@ public final class CallStack implements Serializable {
private final StackTraceElement[] callStack;
public CallStack(StackTraceElement[] callStack) {
public CallStack(StackTraceElement[] callStack, int zeroHash, int pathHash) {
this.callStack = callStack;
this.zeroHash = enc(callStack[0].hashCode());
int hc = 0;
for (int i = 1; i < callStack.length; i++) {
hc = 31 * hc + callStack[i].hashCode();
}
this.pathHash = enc(hc);
this.zeroHash = enc(zeroHash);
this.pathHash = enc(pathHash);
}
public int hashCode() {
int hc = 0;
for (int i = 0; i < callStack.length; i++) {
@@ -87,8 +83,19 @@ public final class CallStack implements Serializable {
return zeroHash + ":" + pathHash + ":" + callStack[0];
}
/**
* Return the call stack lines appended with the given newLine string.
*/
public String description(String newLine) {
StringBuilder sb = new StringBuilder(400);
for (int i = 0; i < callStack.length; i++) {
sb.append(callStack[i].toString()).append(newLine);
}
return sb.toString();
}
public String getOriginKey(int queryHash) {
return zeroHash + "." + enc(queryHash) + "." + pathHash;
return enc(queryHash)+ "." + zeroHash + "." + pathHash;
}
private static final int radix = 1 << 6;
@@ -45,7 +45,7 @@ public final class EntityBeanIntercept implements Serializable {
/**
* The actual entity bean that 'owns' this intercept.
*/
private EntityBean owner;
private final EntityBean owner;
private EntityBean embeddedOwner;
private int embeddedOwnerIndex;
@@ -72,7 +72,7 @@ public final class EntityBeanIntercept implements Serializable {
/**
* Used when a bean is partially filled.
*/
private boolean[] loadedProps;
private final boolean[] loadedProps;
private boolean fullyLoadedBean;
@@ -449,7 +449,18 @@ public final class EntityBeanIntercept implements Serializable {
public int getPropertyLength() {
return owner._ebean_getPropertyNames().length;
}
/**
* Set the loaded state of the property given it's name.
*/
public void setPropertyLoaded(String propertyName, boolean loaded) {
int position = findProperty(propertyName);
if (position == -1) {
throw new IllegalArgumentException("Property "+propertyName+" not found");
}
loadedProps[position] = loaded;
}
/**
* Set the property to be treated as unloaded. Used for properties initialised in default
* constructor.
@@ -581,7 +592,29 @@ public final class EntityBeanIntercept implements Serializable {
}
}
}
/**
* Return true if any of the given property names are dirty.
*/
public boolean hasDirtyProperty(Set<String> propertyNames) {
String[] names = owner._ebean_getPropertyNames();
int len = getPropertyLength();
for (int i = 0; i < len; i++) {
if (changedProps != null && changedProps[i]) {
// the property has been changed on this bean
if (propertyNames.contains(names[i])) {
return true;
}
} else if (embeddedDirty != null && embeddedDirty[i]) {
if (propertyNames.contains(names[i])) {
return true;
}
}
}
return false;
}
/**
* Return a map of dirty properties with their new and old values.
*/
@@ -891,7 +924,7 @@ public final class EntityBeanIntercept implements Serializable {
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
@@ -906,7 +939,7 @@ public final class EntityBeanIntercept implements Serializable {
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Integer.valueOf(oldValue), Integer.valueOf(newValue));
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
@@ -922,7 +955,7 @@ public final class EntityBeanIntercept implements Serializable {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Long.valueOf(oldValue), Long.valueOf(newValue));
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
@@ -937,7 +970,7 @@ public final class EntityBeanIntercept implements Serializable {
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Double.valueOf(oldValue), Double.valueOf(newValue));
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
@@ -952,7 +985,7 @@ public final class EntityBeanIntercept implements Serializable {
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Float.valueOf(oldValue), Float.valueOf(newValue));
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
@@ -967,7 +1000,7 @@ public final class EntityBeanIntercept implements Serializable {
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Short.valueOf(oldValue), Short.valueOf(newValue));
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
@@ -982,7 +1015,7 @@ public final class EntityBeanIntercept implements Serializable {
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Character.valueOf(oldValue), Character.valueOf(newValue));
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
@@ -997,7 +1030,7 @@ public final class EntityBeanIntercept implements Serializable {
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Byte.valueOf(oldValue), Byte.valueOf(newValue));
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
@@ -1,13 +1,13 @@
package com.avaje.ebean.bean;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Collects profile information for a bean (or reference/proxy bean) at a given
* AutoFetchNode.
* Collects profile information for a bean (or reference/proxy bean) at a given node.
* <p>
* The AutoFetchNode identifies the location of the bean in the object graph.
* The node identifies the location of the bean in the object graph.
* </p>
* <p>
* It has to use a weak reference so as to ensure that it does not stop the
@@ -29,7 +29,7 @@ public final class NodeUsageCollector {
/**
* The properties used at this profile point.
*/
private final HashSet<String> used = new HashSet<String>();
private final Set<String> used = new LinkedHashSet<String>();
/**
* set to true if the bean is modified (setter called)
@@ -105,7 +105,7 @@ public final class NodeUsageCollector {
/**
* Return the set of used properties.
*/
public HashSet<String> getUsed() {
public Set<String> getUsed() {
return used;
}
@@ -9,7 +9,7 @@ public interface NodeUsageListener {
* Collect node usage "profiling" information.
* <p>
* This is the properties that are used for a given bean in the object graph.
* This information is used by autoFetch to tune queries.
* This information is used by autoTune to tune queries.
* </p>
*/
void collectNodeUsage(NodeUsageCollector collector);
@@ -82,6 +82,7 @@ public final class ObjectGraphNode implements Serializable {
}
ObjectGraphNode e = (ObjectGraphNode) obj;
//noinspection StringEquality
return ((e.path == path) || (e.path != null && e.path.equals(path)))
&& e.originQueryPoint.equals(originQueryPoint);
}
@@ -9,7 +9,7 @@ import java.io.Serializable;
* The call stack is included so that the query can have different tuned fetches
* for each unique call stack. For example, a query to fetch a customer could be
* called by three different methods and each can be treated as a separate
* origin point (and autoFetch can tune each one separately).
* origin point (and autoTune can tune each one separately).
* </p>
*/
public final class ObjectGraphOrigin implements Serializable {
@@ -74,12 +74,12 @@ public interface PersistenceContext {
* The bean was previously deleted from this persistence context (can't hit
* L2 cache).
*/
public static WithOption DELETED = new WithOption(true);
public static final WithOption DELETED = new WithOption();
private final boolean deleted;
private final Object bean;
private WithOption(boolean deleted) {
private WithOption() {
this.deleted = true;
this.bean = null;
}
@@ -40,7 +40,8 @@ public class ServerCacheStatistics {
protected long evictByLRU;
public String toString() {
StringBuilder sb = new StringBuilder();
//noinspection StringBufferReplaceableByString
StringBuilder sb = new StringBuilder(80);
sb.append(cacheName);
sb.append(" maxSize:").append(maxSize);
sb.append(" size:").append(size);
@@ -343,41 +343,41 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.remove(o);
}
public boolean removeAll(Collection<?> c) {
public boolean removeAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
boolean changed = false;
Iterator<?> it = c.iterator();
while (it.hasNext()) {
Object o = it.next();
if (list.remove(o)) {
modifyRemoval(o);
for (Object bean : beans) {
if (list.remove(bean)) {
// register this bean as having been removed
modifyRemoval(bean);
changed = true;
}
}
return changed;
}
return list.removeAll(c);
return list.removeAll(beans);
}
public boolean retainAll(Collection<?> c) {
public boolean retainAll(Collection<?> retainBeans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
boolean changed = false;
Iterator<E> it = list.iterator();
while (it.hasNext()) {
Object o = it.next();
if (!c.contains(o)) {
Object bean = it.next();
if (!retainBeans.contains(bean)) {
// removing this bean
it.remove();
modifyRemoval(o);
modifyRemoval(bean);
changed = true;
}
}
return changed;
}
return list.retainAll(c);
return list.retainAll(retainBeans);
}
public E set(int index, E element) {
@@ -415,6 +415,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public <T> T[] toArray(T[] a) {
init();
//noinspection SuspiciousToArrayCall
return list.toArray(a);
}
@@ -1,15 +1,14 @@
package com.avaje.ebean.common;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
/**
* Map capable of lazy loading.
*/
@@ -148,8 +147,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
public Collection<E> getActualDetails() {
return map.values();
}
/**
* Returns the map entrySet.
* <p>
@@ -159,7 +157,6 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
*/
public Collection<?> getActualEntries() {
return map.entrySet();
}
public String toString() {
@@ -195,9 +192,9 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
checkReadOnly();
initClear();
if (modifyRemoveListening) {
for (K key : map.keySet()) {
E o = map.remove(key);
modifyRemoval(o);
// add all beans to the removal list
for (E bean : map.values()) {
modifyRemoval(bean);
}
}
map.clear();
@@ -249,27 +246,30 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
checkReadOnly();
init();
if (modifyListening) {
Object o = map.put(key, value);
modifyAddition(value);
modifyRemoval(o);
Object oldBean = map.put(key, value);
if (value != oldBean) {
// register the add of the new and the removal of the old
modifyAddition(value);
modifyRemoval(oldBean);
}
}
return map.put(key, value);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public void putAll(Map<? extends K, ? extends E> t) {
public void putAll(Map<? extends K, ? extends E> puts) {
checkReadOnly();
init();
if (modifyListening) {
Iterator it = t.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
Object o = map.put((K) entry.getKey(), (E) entry.getValue());
modifyAddition((E) entry.getValue());
modifyRemoval(o);
for (Entry<? extends K, ? extends E> entry : puts.entrySet()) {
Object oldBean = map.put(entry.getKey(), entry.getValue());
if (entry.getValue() != oldBean) {
modifyAddition(entry.getValue());
modifyRemoval(oldBean);
}
}
}
map.putAll(t);
map.putAll(puts);
}
public E remove(Object key) {
@@ -192,32 +192,29 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.add(o);
}
public boolean addAll(Collection<? extends E> c) {
public boolean addAll(Collection<? extends E> addCollection) {
checkReadOnly();
init();
if (modifyAddListening) {
boolean changed = false;
Iterator<? extends E> it = c.iterator();
while (it.hasNext()) {
E o = it.next();
if (set.add(o)) {
modifyAddition(o);
for (E bean : addCollection) {
if (set.add(bean)) {
// register the addition of the bean
modifyAddition(bean);
changed = true;
}
}
return changed;
}
return set.addAll(c);
return set.addAll(addCollection);
}
public void clear() {
checkReadOnly();
initClear();
if (modifyRemoveListening) {
Iterator<E> it = set.iterator();
while (it.hasNext()) {
E e = it.next();
modifyRemoval(e);
for (E bean : set) {
modifyRemoval(bean);
}
}
set.clear();
@@ -262,41 +259,40 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.remove(o);
}
public boolean removeAll(Collection<?> c) {
public boolean removeAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
boolean changed = false;
Iterator<?> it = c.iterator();
while (it.hasNext()) {
Object o = it.next();
if (set.remove(o)) {
modifyRemoval(o);
for (Object bean : beans) {
if (set.remove(bean)) {
modifyRemoval(bean);
changed = true;
}
}
return changed;
}
return set.removeAll(c);
return set.removeAll(beans);
}
public boolean retainAll(Collection<?> c) {
public boolean retainAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
boolean changed = false;
Iterator<?> it = set.iterator();
while (it.hasNext()) {
Object o = it.next();
if (!c.contains(o)) {
Object bean = it.next();
if (!beans.contains(bean)) {
// not retaining this bean so add it to the removal list
it.remove();
modifyRemoval(o);
modifyRemoval(bean);
changed = true;
}
}
return changed;
}
return set.retainAll(c);
return set.retainAll(beans);
}
public int size() {
@@ -311,6 +307,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public <T> T[] toArray(T[] a) {
init();
//noinspection SuspiciousToArrayCall
return set.toArray(a);
}
@@ -40,9 +40,7 @@ class ModifyCollection<E> implements Collection<E> {
public boolean addAll(Collection<? extends E> collection) {
boolean changed = false;
Iterator<? extends E> it = collection.iterator();
while (it.hasNext()) {
E o = it.next();
for (E o : collection) {
if (c.add(o)) {
owner.modifyAddition(o);
changed = true;
@@ -51,27 +49,33 @@ class ModifyCollection<E> implements Collection<E> {
return changed;
}
@Override
public void clear() {
c.clear();
}
@Override
public boolean contains(Object o) {
return c.contains(o);
}
@Override
public boolean containsAll(Collection<?> collection) {
return c.containsAll(collection);
}
@Override
public boolean isEmpty() {
return c.isEmpty();
}
@Override
public Iterator<E> iterator() {
Iterator<E> it = c.iterator();
return new ModifyIterator<E>(owner, it);
}
@Override
public boolean remove(Object o) {
if (c.remove(o)) {
owner.modifyRemoval(o);
@@ -80,42 +84,47 @@ class ModifyCollection<E> implements Collection<E> {
return false;
}
@Override
public boolean removeAll(Collection<?> collection) {
boolean changed = false;
Iterator<?> it = collection.iterator();
while (it.hasNext()) {
Object o = (Object) it.next();
if (c.remove(o)) {
owner.modifyRemoval(o);
for (Object bean : collection) {
if (c.remove(bean)) {
owner.modifyRemoval(bean);
changed = true;
}
}
return changed;
}
@Override
public boolean retainAll(Collection<?> collection) {
boolean changed = false;
Iterator<?> it = c.iterator();
while (it.hasNext()) {
Object o = (Object) it.next();
if (!collection.contains(o)) {
Object bean = it.next();
if (!collection.contains(bean)) {
// not retaining this bean so add to removals
it.remove();
owner.modifyRemoval(o);
owner.modifyRemoval(bean);
changed = true;
}
}
return changed;
}
@Override
public int size() {
return c.size();
}
@Override
public Object[] toArray() {
return c.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
//noinspection SuspiciousToArrayCall
return c.toArray(a);
}
@@ -58,7 +58,7 @@ class ModifyHolder<E> implements Serializable {
void modifyRemoval(Object bean) {
if (bean != null) {
// If it is to be added then just remove the addition
if (!modifyAdditions.remove((E) bean)) {
if (!modifyAdditions.remove(bean)) {
modifyDeletions.add((E) bean);
}
}
@@ -1,7 +1,6 @@
package com.avaje.ebean.common;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
@@ -39,12 +38,10 @@ class ModifyList<E> extends ModifyCollection<E> implements List<E> {
owner.modifyAddition(element);
}
public boolean addAll(int index, Collection<? extends E> co) {
if (list.addAll(index, co)) {
Iterator<? extends E> it = co.iterator();
while (it.hasNext()) {
E o = it.next();
owner.modifyAddition(o);
public boolean addAll(int index, Collection<? extends E> addCollection) {
if (list.addAll(index, addCollection)) {
for (E bean : addCollection) {
owner.modifyAddition(bean);
}
return true;
}
@@ -67,9 +67,7 @@ class ModifyListIterator<E> implements ListIterator<E> {
}
public void set(E o) {
if (last == null) {
// in theory this is not allowed
} else {
if (last != null) {
owner.modifyRemoval(last);
owner.modifyAddition(o);
}
@@ -1,12 +1,10 @@
package com.avaje.ebean.config;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import javax.persistence.Inheritance;
import javax.persistence.Table;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Provides some base implementation for NamingConventions.
*
@@ -14,31 +12,39 @@ import org.slf4j.LoggerFactory;
*/
public abstract class AbstractNamingConvention implements NamingConvention {
/** The Constant logger. */
private static final Logger logger = LoggerFactory.getLogger(AbstractNamingConvention.class);
/** The Constant DEFAULT_SEQ_FORMAT. */
/**
* The Constant DEFAULT_SEQ_FORMAT.
*/
public static final String DEFAULT_SEQ_FORMAT = "{table}_seq";
/** Sequence Format that includes the Primary Key column */
/**
* Sequence Format that includes the Primary Key column
*/
public static final String TABLE_PKCOLUMN_SEQ_FORMAT = "{table}_{column}_seq";
/** The catalog. */
/**
* The catalog.
*/
private String catalog;
/** The schema. */
/**
* The schema.
*/
private String schema;
/** The sequence format. */
/**
* The sequence format.
*/
private String sequenceFormat;
/** The database platform. */
/**
* The database platform.
*/
protected DatabasePlatform databasePlatform;
/** The max length of constraint names. */
protected int maxConstraintNameLength;
/** Used to trim off extra prefix for M2M. */
/**
* Used to trim off extra prefix for M2M.
*/
protected int rhsPrefixLength = 3;
protected boolean useForeignKeyPrefix;
@@ -62,8 +68,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
}
/**
* Construct with the default sequence format ("{table}_seq") and
* useForeignKeyPrefix as true.
* Construct with the default sequence format ("{table}_seq") and useForeignKeyPrefix as true.
*/
public AbstractNamingConvention() {
this(DEFAULT_SEQ_FORMAT);
@@ -71,9 +76,6 @@ public abstract class AbstractNamingConvention implements NamingConvention {
public void setDatabasePlatform(DatabasePlatform databasePlatform) {
this.databasePlatform = databasePlatform;
this.maxConstraintNameLength = databasePlatform.getDbDdlSyntax().getMaxConstraintNameLength();
logger.trace("Using maxConstraintNameLength of " + maxConstraintNameLength);
}
public String getSequenceName(String tableName, String pkColumn) {
@@ -218,11 +220,11 @@ public abstract class AbstractNamingConvention implements NamingConvention {
}
buffer.append(rhsTableName);
int maxConstraintNameLength = databasePlatform.getDbDdlSyntax().getMaxConstraintNameLength();
int maxTableNameLength = databasePlatform.getMaxTableNameLength();
// maxConstraintNameLength is used as the max table name length.
if (buffer.length() > maxConstraintNameLength) {
buffer.setLength(maxConstraintNameLength);
if (buffer.length() > maxTableNameLength) {
buffer.setLength(maxTableNameLength);
}
return new TableName(lhsTable.getCatalog(), lhsTable.getSchema(), buffer.toString());
@@ -239,7 +241,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
if (t != null && !isEmpty(t.name())) {
// Note: empty catalog and schema are converted to null
// Only need to convert quoted identifiers from annotations
return new TableName(quoteIdentifiers(t.catalog()), quoteIdentifiers(t.schema()), quoteIdentifiers(t.name()));
return new TableName(quoteIdentifiers(t.catalog()), quoteIdentifiers(t.schema()), quoteIdentifiers(t.name()));
}
// No annotation
@@ -272,10 +274,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
* Checks string is null or empty .
*/
protected boolean isEmpty(String s) {
if (s == null || s.trim().length() == 0) {
return true;
}
return false;
return s == null || s.trim().length() == 0;
}
/**
@@ -0,0 +1,218 @@
package com.avaje.ebean.config;
/**
* Defines the AutoTune behaviour for a EbeanServer.
*/
public class AutoTuneConfig {
private AutoTuneMode mode = AutoTuneMode.DEFAULT_ON;
private String queryTuningFile = "ebean-autotune.xml";
private boolean queryTuning;
private boolean queryTuningAddVersion;
private boolean profiling;
private String profilingFile = "ebean-profiling";
private int profilingBase = 5;
private double profilingRate = 0.01;
private int garbageCollectionWait = 100;
private boolean skipCollectionOnShutdown;
public AutoTuneConfig() {
}
/**
* Return the name of the file that holds the query tuning information.
*/
public String getQueryTuningFile() {
return queryTuningFile;
}
/**
* Set the name of the file that holds the query tuning information.
*/
public void setQueryTuningFile(String queryTuningFile) {
this.queryTuningFile = queryTuningFile;
}
/**
* Return the name of the file that profiling information is written to.
*/
public String getProfilingFile() {
return profilingFile;
}
/**
* Set the name of the file that profiling information is written to.
*/
public void setProfilingFile(String profilingFile) {
this.profilingFile = profilingFile;
}
/**
* Return the mode used when autoTune has not been explicit defined on a
* query.
*/
public AutoTuneMode getMode() {
return mode;
}
/**
* Set the mode used when autoTune has not been explicit defined on a query.
*/
public void setMode(AutoTuneMode mode) {
this.mode = mode;
}
/**
* Return true if the queries are being tuned.
*/
public boolean isQueryTuning() {
return queryTuning;
}
/**
* Set to true if the queries should be tuned by autoTune.
*/
public void setQueryTuning(boolean queryTuning) {
this.queryTuning = queryTuning;
}
/**
* Return true if the version property should be added when the query is
* tuned.
* <p>
* If this is false then the version property will be added when profiling
* detects that the bean is possibly going to be modified.
* </p>
*/
public boolean isQueryTuningAddVersion() {
return queryTuningAddVersion;
}
/**
* Set to true to force the version property to be always added by the query
* tuning.
* <p>
* If this is false then the version property will be added when profiling
* detects that the bean is possibly going to be modified.
* </p>
* <p>
* Generally this is not expected to be turned on.
* </p>
*/
public void setQueryTuningAddVersion(boolean queryTuningAddVersion) {
this.queryTuningAddVersion = queryTuningAddVersion;
}
/**
* Return true if profiling information should be collected.
*/
public boolean isProfiling() {
return profiling;
}
/**
* Set to true if profiling information should be collected.
* <p>
* The profiling information is collected and then used to generate the tuned
* queries for autoTune.
* </p>
*/
public void setProfiling(boolean profiling) {
this.profiling = profiling;
}
/**
* Return the base number of queries to profile before changing to profile
* only a percentage of following queries (profileRate).
*/
public int getProfilingBase() {
return profilingBase;
}
/**
* Set the based number of queries to profile.
*/
public void setProfilingBase(int profilingBase) {
this.profilingBase = profilingBase;
}
/**
* Return the rate (%) of queries to be profiled after the 'base' amount of
* profiling.
*/
public double getProfilingRate() {
return profilingRate;
}
/**
* Set the rate (%) of queries to be profiled after the 'base' amount of
* profiling.
*/
public void setProfilingRate(double profilingRate) {
this.profilingRate = profilingRate;
}
/**
* Return the time in millis to wait after a system gc to collect profiling
* information.
* <p>
* The profiling information is collected on object finalise. As such we
* generally don't want to trigger GC (let the JVM do its thing) but on
* shutdown the autoTune manager will trigger System.gc() and then wait
* (default 100 millis) to hopefully collect profiling information -
* especially for short run unit tests.
* </p>
*/
public int getGarbageCollectionWait() {
return garbageCollectionWait;
}
/**
* Set the time in millis to wait after a System.gc() to collect profiling information.
*/
public void setGarbageCollectionWait(int garbageCollectionWait) {
this.garbageCollectionWait = garbageCollectionWait;
}
/**
* Return true if profiling collection should be skipped on shutdown.
*/
public boolean isSkipCollectionOnShutdown() {
return skipCollectionOnShutdown;
}
/**
* Set to true if profiling collection should be skipped on shutdown.
*/
public void setSkipCollectionOnShutdown(boolean skipCollectionOnShutdown) {
this.skipCollectionOnShutdown = skipCollectionOnShutdown;
}
/**
* Load the settings from the properties file.
*/
public void loadSettings(PropertiesWrapper p) {
queryTuning = p.getBoolean("autoTune.queryTuning", queryTuning);
queryTuningAddVersion = p.getBoolean("autoTune.queryTuningAddVersion", queryTuningAddVersion);
queryTuningFile = p.get("autoTune.queryTuningFile", queryTuningFile);
skipCollectionOnShutdown = p.getBoolean("autoTune.skipCollectionOnShutdown", skipCollectionOnShutdown);
mode = p.getEnum(AutoTuneMode.class, "autoTune.mode", mode);
profiling = p.getBoolean("autoTune.profiling", profiling);
profilingBase = p.getInt("autoTune.profilingBase", profilingBase);
profilingRate = p.getDouble("autoTune.profilingRate", profilingRate);
profilingFile = p.get("autoTune.profilingFile", profilingFile);
}
}
@@ -0,0 +1,32 @@
package com.avaje.ebean.config;
import com.avaje.ebean.Query;
/**
* The mode for determining if AutoTune will be used for a given query when
* {@link Query#setAutoTune(boolean)} has not been explicitly set on a query.
* <p>
* The explicit control of {@link Query#setAutoTune(boolean)} will always take
* precedence. This mode is used when this has not been explicitly set on a
* query.
* </p>
*/
public enum AutoTuneMode {
/**
* Don't implicitly use AutoTune. Must explicitly turn it on.
*/
DEFAULT_OFF,
/**
* Use AutoTune implicitly. Must explicitly turn it off.
*/
DEFAULT_ON,
/**
* Implicitly use AutoTune if the query has not got either select() or join()
* defined.
*/
DEFAULT_ONIFEMPTY
}
@@ -1,245 +0,0 @@
package com.avaje.ebean.config;
/**
* Defines the Autofetch behaviour for a EbeanServer.
*/
public class AutofetchConfig {
private AutofetchMode mode = AutofetchMode.DEFAULT_ONIFEMPTY;
private boolean queryTuning = false;
private boolean queryTuningAddVersion = false;
private boolean profiling = false;
private int profilingMin = 1;
private int profilingBase = 10;
private double profilingRate = 0.05;
private String logDirectory;
private int profileUpdateFrequency = 60;
private int garbageCollectionWait = 100;
private boolean garbageCollectionOnShutdown;
public AutofetchConfig() {
}
/**
* Return the mode used when autofetch has not been explicit defined on a
* query.
*/
public AutofetchMode getMode() {
return mode;
}
/**
* Set the mode used when autofetch has not been explicit defined on a query.
*/
public void setMode(AutofetchMode mode) {
this.mode = mode;
}
/**
* Return true if the queries are being tuned.
*/
public boolean isQueryTuning() {
return queryTuning;
}
/**
* Set to true if the queries should be tuned by autofetch.
*/
public void setQueryTuning(boolean queryTuning) {
this.queryTuning = queryTuning;
}
/**
* Return true if the version property should be added when the query is
* tuned.
* <p>
* If this is false then the version property will be added when profiling
* detects that the bean is possibly going to be modified.
* </p>
*/
public boolean isQueryTuningAddVersion() {
return queryTuningAddVersion;
}
/**
* Set to true to force the version property to be always added by the query
* tuning.
* <p>
* If this is false then the version property will be added when profiling
* detects that the bean is possibly going to be modified.
* </p>
*/
public void setQueryTuningAddVersion(boolean queryTuningAddVersion) {
this.queryTuningAddVersion = queryTuningAddVersion;
}
/**
* Return true if profiling information should be collected.
*/
public boolean isProfiling() {
return profiling;
}
/**
* Set to true if profiling information should be collected.
* <p>
* The profiling information is collected and then used to generate the tuned
* queries for autofetch.
* </p>
*/
public void setProfiling(boolean profiling) {
this.profiling = profiling;
}
/**
* Return the minimum number of queries to profile before autofetch will start
* tuning the queries.
*/
public int getProfilingMin() {
return profilingMin;
}
/**
* Set the minimum number of queries to profile before autofetch will start
* tuning the queries.
*/
public void setProfilingMin(int profilingMin) {
this.profilingMin = profilingMin;
}
/**
* Return the base number of queries to profile before changing to profile
* only a percentage of following queries (profileRate).
*/
public int getProfilingBase() {
return profilingBase;
}
/**
* Set the based number of queries to profile.
*/
public void setProfilingBase(int profilingBase) {
this.profilingBase = profilingBase;
}
/**
* Return the rate (%) of queries to be profiled after the 'base' amount of
* profiling.
*/
public double getProfilingRate() {
return profilingRate;
}
/**
* Set the rate (%) of queries to be profiled after the 'base' amount of
* profiling.
*/
public void setProfilingRate(double profilingRate) {
this.profilingRate = profilingRate;
}
/**
* Return the log directory to put the autofetch log.
*/
public String getLogDirectory() {
return logDirectory;
}
/**
* Set the directory to put the autofetch log in.
*/
public void setLogDirectory(String logDirectory) {
this.logDirectory = logDirectory;
}
/**
* Return the frequency in seconds to update the autofetch tuned queries from
* the profiled information.
*/
public int getProfileUpdateFrequency() {
return profileUpdateFrequency;
}
/**
* Set the frequency in seconds to update the autofetch tuned queries from the
* profiled information.
*/
public void setProfileUpdateFrequency(int profileUpdateFrequency) {
this.profileUpdateFrequency = profileUpdateFrequency;
}
/**
* Return the time in millis to wait after a system gc to collect profiling
* information.
* <p>
* The profiling information is collected on object finalise. As such we
* generally don't want to trigger GC (let the JVM do its thing) but on
* shutdown the autofetch manager will trigger System.gc() and then wait
* (default 100 millis) to hopefully collect profiling information -
* especially for short run unit tests.
* </p>
*/
public int getGarbageCollectionWait() {
return garbageCollectionWait;
}
/**
* Set the time in millis to wait after a System.gc() to collect profiling
* information.
*/
public void setGarbageCollectionWait(int garbageCollectionWait) {
this.garbageCollectionWait = garbageCollectionWait;
}
/**
* Return true if GC should be trigger on shutdown.
* <p>
* Autofetch profiling information is collected as part of garbage collection.
* </p>
*/
public boolean isGarbageCollectionOnShutdown() {
return garbageCollectionOnShutdown;
}
/**
* Set to true if you want GC to trigger on shutdown.
* <p>
* This would be done if you want to try and collect Autofetch profiling information
* on shutdown.
* </p>
*/
public void setGarbageCollectionOnShutdown(boolean garbageCollectionOnShutdown) {
this.garbageCollectionOnShutdown = garbageCollectionOnShutdown;
}
/**
* Load the settings from the properties file.
*/
public void loadSettings(PropertiesWrapper p) {
logDirectory = p.get("autofetch.logDirectory", logDirectory);
queryTuning = p.getBoolean("autofetch.querytuning", queryTuning);
queryTuningAddVersion = p.getBoolean("autofetch.queryTuningAddVersion", queryTuningAddVersion);
garbageCollectionOnShutdown = p.getBoolean("autofetch.garbageCollectionOnShutdown", garbageCollectionOnShutdown);
profiling = p.getBoolean("autofetch.profiling", profiling);
mode = p.getEnum(AutofetchMode.class, "autofetch.implicitmode", mode);
profilingMin = p.getInt("autofetch.profiling.min", profilingMin);
profilingBase = p.getInt("autofetch.profiling.base", profilingBase);
profilingRate = p.getDouble("autofetch.profiling.rate", profilingRate);
profileUpdateFrequency = p.getInt("autofetch.profiling.updatefrequency", profileUpdateFrequency);
}
}
@@ -1,32 +0,0 @@
package com.avaje.ebean.config;
import com.avaje.ebean.Query;
/**
* The mode for determining if Autofetch will be used for a given query when
* {@link Query#setAutofetch(boolean)} has not been explicitly set on a query.
* <p>
* The explicit control of {@link Query#setAutofetch(boolean)} will always take
* precedence. This mode is used when this has not been explicitly set on a
* query.
* </p>
*/
public enum AutofetchMode {
/**
* Don't implicitly use Autofetch. Must explicitly turn it on.
*/
DEFAULT_OFF,
/**
* Use Autofetch implicitly. Must explicitly turn it off.
*/
DEFAULT_ON,
/**
* Implicitly use Autofetch if the query has not got either select() or join()
* defined.
*/
DEFAULT_ONIFEMPTY
}
@@ -507,8 +507,7 @@ public class DataSourceConfig {
String customProperties = properties.get("customProperties", null);
if (customProperties != null && customProperties.length() > 0) {
Map<String, String> custProps = StringHelper.delimitedToMap(customProperties, ";", "=");
this.customProperties = custProps;
this.customProperties = StringHelper.delimitedToMap(customProperties, ";", "=");
}
}
@@ -0,0 +1,209 @@
package com.avaje.ebean.config;
/**
* Naming convention used for constraint names.
* <p>
* Note that these constraint names are trimmed in the PlatformDdl which can be overridden
* but provides a decent default implementation.
* </p>
*/
public class DbConstraintNaming {
/**
* Defines how constraint names are shortened if required based on platform limitations.
*/
public interface MaxLength {
/**
* Truncate or shorten the constraint name to support DB platform limitations.
* <p>
* There is a default implementation of this which is used if an implementation is
* not specified.
* </p>
*/
String maxLength(String constraintName, int count);
}
protected String pkPrefix = "pk_";
protected String pkSuffix = "";
protected String fkPrefix = "fk_";
protected String fkMiddle = "_";
protected String fkSuffix = "";
protected String fkIndexPrefix = "ix_";
protected String fkIndexMiddle = "_";
protected String fkIndexSuffix = "";
protected String indexPrefix = "ix_";
protected String indexMiddle = "_";
protected String indexSuffix = "";
protected String uqPrefix = "uq_";
protected String uqSuffix = "";
protected String ckPrefix = "ck_";
protected String ckSuffix = "";
protected MaxLength maxLength;
protected DbConstraintNormalise normalise;
/**
* Construct using default of lower case for both table and column names.
*/
public DbConstraintNaming() {
this(true, true);
}
/**
* Construct specifying if lower case should be used (for both table and column names).
*/
public DbConstraintNaming(boolean lowerCase) {
this(lowerCase, lowerCase);
}
/**
* Construct specifying if lower case should be used for both table and column names.
*/
public DbConstraintNaming(boolean lowerCaseTableNames, boolean lowerCaseColumnNames) {
this.normalise = new DbConstraintNormalise(lowerCaseTableNames, lowerCaseColumnNames);
}
/**
* Return the MaxLength implementation used to truncate/shorten db constraint names as necessary.
*/
public MaxLength getMaxLength() {
return maxLength;
}
/**
* Set the MaxLength implementation used to truncate/shorten db constraint names as necessary.
*/
public void setMaxLength(MaxLength maxLength) {
this.maxLength = maxLength;
}
/**
* Return the primary key constraint name.
*/
public String primaryKeyName(String tableName) {
return pkPrefix + normaliseTable(tableName) + pkSuffix;
}
/**
* Return the foreign key constraint name given a single column foreign key.
*/
public String foreignKeyConstraintName(String tableName, String columnName) {
return fkPrefix + normaliseTable(tableName) + fkMiddle + normaliseColumn(columnName) + fkSuffix;
}
/**
* Return the index name associated with a foreign key constraint given multiple columns.
*/
public String foreignKeyIndexName(String tableName, String[] columns) {
String colPart = joinColumnNames(columns);
return fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix;
}
/**
* Return the index name associated with a foreign key constraint given a single column foreign key.
*/
public String foreignKeyIndexName(String tableName, String column) {
String colPart = normaliseTable(column);
return fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix;
}
/**
* Return the index name for a general index (not associated with a foreign key).
*/
public String indexName(String tableName, String column) {
String colPart = normaliseTable(column);
return indexPrefix + normaliseTable(tableName) + indexMiddle + colPart + indexSuffix;
}
/**
* Return the index name for a general index (not associated with a foreign key).
*/
public String indexName(String tableName, String[] columns) {
String colPart = joinColumnNames(columns);
return indexPrefix + normaliseTable(tableName) + indexMiddle + colPart + indexSuffix;
}
/**
* Join the column names together with underscores.
*/
protected String joinColumnNames(String[] columns) {
if (columns.length == 1) {
return normaliseColumn(columns[0]);
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < columns.length; i++) {
if (i > 0) {
sb.append("_");
}
sb.append(normaliseColumn(columns[i]));
}
return sb.toString();
}
/**
* Return the unique constraint name.
*/
public String uniqueConstraintName(String tableName, String columnName) {
return uqPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + uqSuffix;
}
/**
* Return the unique constraint name.
*/
public String uniqueConstraintName(String tableName, String[] columns) {
String colPart = joinColumnNames(columns);
return uqPrefix + normaliseTable(tableName) + "_" + colPart + uqSuffix;
}
/**
* Return the check constraint name.
*/
public String checkConstraintName(String tableName, String columnName) {
return ckPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + ckSuffix;
}
/**
* Normalise the table name by trimming catalog and schema and removing any
* quoted identifier characters (",',[,] etc).
*/
public String normaliseTable(String tableName) {
return normalise.normaliseTable(tableName);
}
/**
* Normalise the column name by removing any quoted identifier characters (",',[,] etc).
*/
public String normaliseColumn(String tableName) {
return normalise.normaliseColumn(tableName);
}
/**
* Lower case the table name checking for quoted identifiers.
*/
public String lowerTableName(String tableName) {
return normalise.lowerTableName(tableName);
}
/**
* Lower case the column name checking for quoted identifiers.
*/
public String lowerColumnName(String name) {
return normalise.lowerColumnName(name);
}
}
@@ -0,0 +1,105 @@
package com.avaje.ebean.config;
/**
* Used to normalise table and column names which means stripping out
* quoted identifier characters and any catalog or schema prefix.
*/
public class DbConstraintNormalise {
protected final String[] quotedIdentifiers;
protected final boolean lowerCaseTables;
protected final boolean lowerCaseColumns;
public DbConstraintNormalise() {
this(true, true);
}
public DbConstraintNormalise(boolean lowerCaseTables, boolean lowerCaseColumns) {
this.lowerCaseTables = lowerCaseTables;
this.lowerCaseColumns = lowerCaseColumns;
this.quotedIdentifiers = new String[]{"\"", "'", "[", "]", "`"};
}
/**
* Normalise the table name by trimming catalog and schema and removing any
* quoted identifier characters (",',[,] etc).
*/
public String normaliseTable(String tableName) {
tableName = trimQuotes(tableName);
int lastPeriod = tableName.lastIndexOf('.');
if (lastPeriod > -1) {
// trim off catalog and schema prefix
tableName = tableName.substring(lastPeriod + 1);
}
if (lowerCaseTables) {
tableName = tableName.toLowerCase();
}
return tableName;
}
/**
* Normalise the column name by removing any quoted identifier characters.
*/
public String normaliseColumn(String columnName) {
columnName = trimQuotes(columnName);
if (lowerCaseColumns) {
columnName = columnName.toLowerCase();
}
return columnName;
}
/**
* Lower case the table name checking for quoted identifiers.
*/
public String lowerTableName(String tableName) {
if (lowerCaseTables && notQuoted(tableName)) {
return tableName.toLowerCase();
}
return tableName;
}
/**
* Lower case the column name checking for quoted identifiers.
*/
public String lowerColumnName(String name) {
if (lowerCaseColumns && notQuoted(name)) {
return name.toLowerCase();
}
return name;
}
/**
* Trim off the platform quoted identifier quotes like [ ' and ".
*/
public boolean notQuoted(String tableName) {
// remove quoted identifier characters
for (int i = 0; i < quotedIdentifiers.length; i++) {
if (tableName.contains(quotedIdentifiers[i])) {
return false;
}
}
return true;
}
/**
* Trim off the platform quoted identifier quotes like [ ' and ".
*/
public String trimQuotes(String tableName) {
if (tableName == null) {
return "";
}
// remove quoted identifier characters
for (int i = 0; i < quotedIdentifiers.length; i++) {
tableName = tableName.replace(quotedIdentifiers[i], "");
}
return tableName;
}
}
@@ -0,0 +1,39 @@
package com.avaje.ebean.config;
/**
* Configuration for the DB migration processing.
*/
public class DbMigrationConfig {
/**
* Resource path for the migration xml and sql.
* Typically you would change 'app' to be a better/more unique.
*/
private String resourcePath = "dbmigration/app";
/**
* Return the resource path for db migrations.
*/
public String getResourcePath() {
return resourcePath;
}
/**
* Set the resource path for db migrations.
* <p>
* Typically this would be something like "dbmigration/myapp" where myapp gives it a
* unique resource path in the case there are multiple EbeanServer applications in the
* single classpath.
* </p>
*/
public void setResourcePath(String resourcePath) {
this.resourcePath = resourcePath;
}
/**
* Load the settings from the PropertiesWrapper.
*/
public void loadSettings(PropertiesWrapper properties) {
resourcePath = properties.get("migration.resourcePath", resourcePath);
}
}
@@ -82,8 +82,7 @@ public interface NamingConvention {
String getPropertyFromColumn(Class<?> beanClass, String dbColumnName);
/**
* Return the sequence name given the table name (for DB's that use
* sequences).
* Return the sequence name given the table name (for DB's that use sequences).
* <p>
* Typically you might append "_seq" to the table name as an example.
* </p>
@@ -99,14 +98,14 @@ public interface NamingConvention {
* Return true if a prefix should be used building a foreign key name.
* <p>
* This by default is true and this works well when the primary key column
* names are simply "ID". In this case a prefix (such as "ORDER" and
* "CUSTOMER" etc) is added to the foreign key column producing "ORDER_ID" and
* "CUSTOMER_ID".
* names are simply "id". In this case a prefix (such as "order" and
* "customer" etc) is added to the foreign key column producing "order_id" and
* "customer_id".
* </p>
* <p>
* This should return false when your primary key columns are the same as the
* foreign key columns. For example, when the primary key columns are
* "ORDER_ID", "CUST_ID" etc ... and they are the same as the foreign key
* "order_id", "cust_id" etc ... and they are the same as the foreign key
* column names.
* </p>
*/
@@ -36,7 +36,7 @@ public enum PersistBatch {
INHERIT(false);
boolean forInsert;
final boolean forInsert;
PersistBatch(boolean forInsert) {
this.forInsert = forInsert;
@@ -27,12 +27,12 @@ final class PropertyExpression {
/**
* Used to detect the start of an expression.
*/
private static String START = "${";
private static final String START = "${";
/**
* Used to detect the end of an expression.
*/
private static String END = "}";
private static final String END = "}";
/**
* Specify the PropertyHolder.
@@ -144,13 +144,7 @@ final class PropertyExpression {
}
private static boolean isJndiExpression(String exp) {
if (exp.startsWith("JNDI:")) {
return true;
}
if (exp.startsWith("jndi:")) {
return true;
}
return false;
return exp.startsWith("JNDI:") || exp.startsWith("jndi:");
}
/**
@@ -16,7 +16,15 @@ public final class PropertyMap implements Serializable {
private static final long serialVersionUID = 1L;
private LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
private final LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
/**
* Return properties loaded from test-ebean.properties.
*/
public static Properties testProperties() {
PropertyMap propertyMap = PropertyMapLoader.loadTestProperties();
return (propertyMap == null) ? new Properties() : propertyMap.asProperties();
}
public static Properties defaultProperties() {
PropertyMap propertyMap = PropertyMapLoader.loadGlobalProperties();
@@ -14,17 +14,34 @@ final class PropertyMapLoader {
private static final Logger logger = LoggerFactory.getLogger(PropertyMapLoader.class);
/**
* Load the <code>test-ebean.properties</code>.
*/
public static PropertyMap loadTestProperties() {
return load(null, "test-ebean.properties", false);
}
/**
* Load the ebean.properties (and test-ebean.properties if present).
*/
public static PropertyMap loadGlobalProperties() {
boolean loadTestProperties = false;
String fileName = System.getenv("EBEAN_PROPS_FILE");
if (fileName == null) {
fileName = System.getProperty("ebean.props.file");
if (fileName == null) {
loadTestProperties = true;
fileName = "ebean.properties";
}
}
return load(null, fileName);
PropertyMap map = load(null, fileName, true);
if (loadTestProperties) {
// load test properties if present in classpath
load(map, "test-ebean.properties", false);
}
return map;
}
/**
@@ -35,11 +52,13 @@ final class PropertyMapLoader {
* @param fileName
* the name of the properties file to load.
*/
public static PropertyMap load(PropertyMap p, String fileName) {
public static PropertyMap load(PropertyMap p, String fileName, boolean errorOnNull) {
InputStream is = findInputStream(fileName);
if (is == null) {
logger.error(fileName + " not found");
if (errorOnNull) {
logger.error(fileName + " not found");
}
return p;
} else {
return load(p, is);
@@ -1,24 +0,0 @@
package com.avaje.ebean.config;
import java.sql.PreparedStatement;
/**
* Unwrap the PreparedStatement to get the specific underlying implementation.
* <p>
* This is used to handle specific JDBC driver issues. Typically this means
* getting the OraclePreparedStatement to handle Oracle specific issues etc.
* </p>
*
* @author rbygrave
*/
public interface PstmtDelegate {
/**
* Unwrap the PreparedStatement to get the specific underlying implementation.
*
* @param pstmt
* the PreparedStatement coming out of the connection pool
* @return the underlying PreparedStatement
*/
PreparedStatement unwrap(PreparedStatement pstmt);
}
@@ -8,6 +8,11 @@ import com.avaje.ebean.cache.ServerCacheManager;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbEncrypt;
import com.avaje.ebean.event.*;
import com.avaje.ebean.event.changelog.ChangeLogListener;
import com.avaje.ebean.event.changelog.ChangeLogPrepare;
import com.avaje.ebean.event.changelog.ChangeLogRegister;
import com.avaje.ebean.event.readaudit.ReadAuditLogger;
import com.avaje.ebean.event.readaudit.ReadAuditPrepare;
import com.avaje.ebean.meta.MetaInfoManager;
import com.avaje.ebean.util.ClassUtil;
import com.fasterxml.jackson.core.JsonFactory;
@@ -70,6 +75,11 @@ public class ServerConfig {
private ContainerConfig containerConfig;
/**
* The underlying properties that were used during configuration.
*/
private Properties properties;
/**
* The resource directory.
*/
@@ -120,9 +130,9 @@ public class ServerConfig {
private CurrentUserProvider currentUserProvider;
/**
* Config controlling the autofetch behaviour.
* Config controlling the AutoTune behaviour.
*/
private AutofetchConfig autofetchConfig = new AutofetchConfig();
private AutoTuneConfig autoTuneConfig = new AutoTuneConfig();
/**
* The JSON format used for DateTime types. Default to millis.
@@ -162,6 +172,12 @@ public class ServerConfig {
*/
private String asOfSysPeriod = "sys_period";
/**
* 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.
*/
private String historyTableSuffix = "_history";
/**
* Use for transaction scoped batch mode.
*/
@@ -198,11 +214,6 @@ public class ServerConfig {
private ExternalTransactionManager externalTransactionManager;
/**
* Used to unwrap PreparedStatements to perform JDBC Driver specific functions
*/
private PstmtDelegate pstmtDelegate;
/**
* The data source (if programmatically provided).
*/
private DataSource dataSource;
@@ -212,13 +223,23 @@ public class ServerConfig {
*/
private DataSourceConfig dataSourceConfig = new DataSourceConfig();
/**
* The db migration config (migration resource path etc).
*/
private DbMigrationConfig migrationConfig = new DbMigrationConfig();
/**
* Set to true if the DataSource uses autoCommit.
* <p>
* Indicates that Ebean should use autoCommit friendly Transactions and TransactionManager.
*/
private boolean autoCommitMode;
/**
* Set to true if transaction begin should be started with explicit statement.
*/
private boolean explicitTransactionBeginMode;
/**
* The data source JNDI name if using a JNDI DataSource.
*/
@@ -239,6 +260,11 @@ public class ServerConfig {
*/
private NamingConvention namingConvention = new UnderscoreNamingConvention();
/**
* Naming convention used in DDL generation for primary keys, foreign keys etc.
*/
private DbConstraintNaming constraintNaming = new DbConstraintNaming();
/**
* Behaviour of update to include on the change properties.
*/
@@ -255,19 +281,35 @@ public class ServerConfig {
private boolean updatesDeleteMissingChildren = true;
/**
* Setting to indicate if UUID should be stored as binary(16) or varchar(40).
* Setting to indicate if UUID should be stored as binary(16) or varchar(40) or native DB type (for H2 and Postgres).
*/
private boolean uuidStoreAsBinary;
private DbUuid dbUuid = DbUuid.AUTO;
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>();
/**
* By default inserts are included in the change log.
*/
private boolean changeLogIncludeInserts = true;
private ChangeLogPrepare changeLogPrepare;
private ChangeLogListener changeLogListener;
private ChangeLogRegister changeLogRegister;
private ReadAuditLogger readAuditLogger;
private ReadAuditPrepare readAuditPrepare;
private EncryptKeyManager encryptKeyManager;
private EncryptDeployManager encryptDeployManager;
@@ -322,7 +364,6 @@ public class ServerConfig {
private int queryCacheMaxIdleTime = 600;
private int queryCacheMaxTimeToLive = 60*60*6;
private Object objectMapper;
private boolean diffFlatMode;
/**
* Set to true if you want eq("someProperty", null) to generate 1=1 rather than "is null" sql expression.
@@ -506,7 +547,7 @@ public class ServerConfig {
/**
* Return the JDBC batch mode to use per save(), delete(), insert() or update() request.
* <p>
* This makes sense when a save() or delete() etc cascades and executes multiple child statements. The best caase
* This makes sense when a save() or delete() cascades and executes multiple child statements. The best case
* for this is when saving a master/parent bean this cascade inserts many detail/child beans.
* </p>
* <p>
@@ -624,6 +665,125 @@ public class ServerConfig {
this.databaseSequenceBatchSize = databaseSequenceBatchSize;
}
/**
* Return the ChangeLogPrepare.
* <p>
* This is used to set user context information to the ChangeSet in the
* foreground thread prior to the logging occurring in a background thread.
* </p>
*/
public ChangeLogPrepare getChangeLogPrepare() {
return changeLogPrepare;
}
/**
* Set the ChangeLogPrepare.
* <p>
* This is used to set user context information to the ChangeSet in the
* foreground thread prior to the logging occurring in a background thread.
* </p>
*/
public void setChangeLogPrepare(ChangeLogPrepare changeLogPrepare) {
this.changeLogPrepare = changeLogPrepare;
}
/**
* Return the ChangeLogListener which actually performs the logging of change sets
* in the background.
*/
public ChangeLogListener getChangeLogListener() {
return changeLogListener;
}
/**
* Set the ChangeLogListener which actually performs the logging of change sets
* in the background.
*/
public void setChangeLogListener(ChangeLogListener changeLogListener) {
this.changeLogListener = changeLogListener;
}
/**
* Return the ChangeLogRegister which controls which ChangeLogFilter is used for each
* bean type and in this way provide fine grained control over which persist requests
* are included in the change log.
*/
public ChangeLogRegister getChangeLogRegister() {
return changeLogRegister;
}
/**
* Set the ChangeLogRegister which controls which ChangeLogFilter is used for each
* bean type and in this way provide fine grained control over which persist requests
* are included in the change log.
*/
public void setChangeLogRegister(ChangeLogRegister changeLogRegister) {
this.changeLogRegister = changeLogRegister;
}
/**
* Return true if inserts should be included in the change log by default.
*/
public boolean isChangeLogIncludeInserts() {
return changeLogIncludeInserts;
}
/**
* Set if inserts should be included in the change log by default.
*/
public void setChangeLogIncludeInserts(boolean changeLogIncludeInserts) {
this.changeLogIncludeInserts = changeLogIncludeInserts;
}
/**
* Return the ReadAuditLogger to use.
*/
public ReadAuditLogger getReadAuditLogger() {
return readAuditLogger;
}
/**
* Set the ReadAuditLogger to use. If not set the default implementation is used
* which logs the read events in JSON format to a standard named SLF4J logger
* (which can be configured in say logback to log to a separate log file).
*/
public void setReadAuditLogger(ReadAuditLogger readAuditLogger) {
this.readAuditLogger = readAuditLogger;
}
/**
* Return the ReadAuditPrepare to use.
*/
public ReadAuditPrepare getReadAuditPrepare() {
return readAuditPrepare;
}
/**
* Set the ReadAuditPrepare to use.
* <p>
* It is expected that an implementation is used that read user context information
* (user id, user ip address etc) and sets it on the ReadEvent bean before it is sent
* to the ReadAuditLogger.
* </p>
*/
public void setReadAuditPrepare(ReadAuditPrepare readAuditPrepare) {
this.readAuditPrepare = readAuditPrepare;
}
/**
* Return the DB migration configuration.
*/
public DbMigrationConfig getMigrationConfig() {
return migrationConfig;
}
/**
* Set the DB migration configuration.
*/
public void setMigrationConfig(DbMigrationConfig migrationConfig) {
this.migrationConfig = migrationConfig;
}
/**
* Return the 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.
@@ -656,6 +816,20 @@ public class ServerConfig {
this.asOfSysPeriod = asOfSysPeriod;
}
/**
* Return the history table suffix (defaults to _history).
*/
public String getHistoryTableSuffix() {
return historyTableSuffix;
}
/**
* Set the history table suffix.
*/
public void setHistoryTableSuffix(String historyTableSuffix) {
this.historyTableSuffix = historyTableSuffix;
}
/**
* Return true if we are running in a JTA Transaction manager.
*/
@@ -961,35 +1135,31 @@ public class ServerConfig {
}
/**
* Return the configuration for the Autofetch feature.
* Return the constraint naming convention used in DDL generation.
*/
public AutofetchConfig getAutofetchConfig() {
return autofetchConfig;
public DbConstraintNaming getConstraintNaming() {
return constraintNaming;
}
/**
* Set the configuration for the Autofetch feature.
* Set the constraint naming convention used in DDL generation.
*/
public void setAutofetchConfig(AutofetchConfig autofetchConfig) {
this.autofetchConfig = autofetchConfig;
public void setConstraintNaming(DbConstraintNaming constraintNaming) {
this.constraintNaming = constraintNaming;
}
/**
* Return the PreparedStatementDelegate.
* Return the configuration for AutoTune.
*/
public PstmtDelegate getPstmtDelegate() {
return pstmtDelegate;
public AutoTuneConfig getAutoTuneConfig() {
return autoTuneConfig;
}
/**
* Set the PstmtDelegate which can be used to support JDBC driver specific
* features.
* <p>
* Typically this means Oracle JDBC driver specific workarounds.
* </p>
* Set the configuration for AutoTune.
*/
public void setPstmtDelegate(PstmtDelegate pstmtDelegate) {
this.pstmtDelegate = pstmtDelegate;
public void setAutoTuneConfig(AutoTuneConfig autoTuneConfig) {
this.autoTuneConfig = autoTuneConfig;
}
/**
@@ -1055,6 +1225,28 @@ public class ServerConfig {
this.autoCommitMode = autoCommitMode;
}
/**
* Return true if transaction begin should be started with explicit statement.
*/
public boolean isExplicitTransactionBeginMode() {
return explicitTransactionBeginMode;
}
/**
* Set to true if transaction begin should be started with explicit statement.
* <p>
* This works for H2 and Postgres but not for Oracle - only use this if you first name
* is Daryl or you have explicitly talked to Rob about this feature.
* </p>
* <p>
* This is generally not expected to be turned on but instead allow transactions to start
* implicitly which is generally the standard approach.
* </p>
*/
public void setExplicitTransactionBeginMode(boolean explicitTransactionBeginMode) {
this.explicitTransactionBeginMode = explicitTransactionBeginMode;
}
/**
* Return a value used to represent TRUE in the database.
* <p>
@@ -1274,19 +1466,18 @@ public class ServerConfig {
this.dbEncrypt = dbEncrypt;
}
/**
* Return true if UUID should be stored as binary(16) (as opposed to varchar(40)).
* Return the DB type used to store UUID.
*/
public boolean isUuidStoreAsBinary() {
return uuidStoreAsBinary;
public DbUuid getDbUuid() {
return dbUuid;
}
/**
* Set to true if UUID should be stored as binary(16) (as opposed to varchar(40)).
* Set the DB type used to store UUID.
*/
public void setUuidStoreAsBinary(boolean uuidStoreAsBinary) {
this.uuidStoreAsBinary = uuidStoreAsBinary;
public void setDbUuid(DbUuid dbUuid) {
this.dbUuid = dbUuid;
}
/**
@@ -1660,14 +1851,45 @@ public class ServerConfig {
persistControllers.add(beanPersistController);
}
/**
* Register a BeanPostLoad instance.
* <p>
* Note alternatively you can use {@link #setPostLoaders(List)} to set
* all the BeanPostLoad instances.
* </p>
*/
public void add(BeanPostLoad postLoad) {
postLoaders.add(postLoad);
}
/**
* Return the list of BeanFindController instances.
*/
public List<BeanFindController> getFindControllers() {
return findControllers;
}
/**
* Set the list of BeanFindController instances.
*/
public void setFindControllers(List<BeanFindController> findControllers) {
this.findControllers = findControllers;
}
/**
* Return the list of BeanPostLoader instances.
*/
public List<BeanPostLoad> getPostLoaders() {
return postLoaders;
}
/**
* Set the list of BeanPostLoader instances.
*/
public void setPostLoaders(List<BeanPostLoad> postLoaders) {
this.postLoaders = postLoaders;
}
/**
* Return the BeanPersistController instances.
*/
@@ -1812,14 +2034,40 @@ public class ServerConfig {
* Load the settings from the given properties
*/
public void loadFromProperties(Properties properties) {
// keep the properties used for configuration so that these are available for plugins
this.properties = properties;
PropertiesWrapper p = new PropertiesWrapper("ebean", name, properties);
loadSettings(p);
}
/**
* Load settings from test-ebean.properties and do nothing if the properties is not found.
* <p>
* This is typically used when test-ebean.properties is put into the test class path and used
* to configure Ebean for running tests.
* </p>
*/
public void loadTestProperties() {
Properties properties = PropertyMap.testProperties();
if (!properties.isEmpty()) {
PropertiesWrapper p = new PropertiesWrapper("ebean", name, properties);
loadSettings(p);
}
}
/**
* Return the properties that we used for configuration and were set via a call to loadFromProperties().
*/
public Properties getProperties() {
return properties;
}
@SuppressWarnings("unchecked")
private <T> T createInstance(PropertiesWrapper p, Class<T> pluginType, String key) {
private <T> T createInstance(PropertiesWrapper p, Class<T> pluginType, String key, T instance) {
if (instance != null) {
return instance;
}
String classname = p.get(key, null);
return classname == null ? null : (T) ClassUtil.newInstance(classname);
}
@@ -1838,8 +2086,8 @@ public class ServerConfig {
/**
* This is broken out for the same reason as above - preserve existing behaviour but let it be overridden.
*/
protected void loadAutofetchSettings(PropertiesWrapper p) {
autofetchConfig.loadSettings(p);
protected void loadAutoTuneSettings(PropertiesWrapper p) {
autoTuneConfig.loadSettings(p);
}
/**
@@ -1847,32 +2095,35 @@ public class ServerConfig {
*/
protected void loadSettings(PropertiesWrapper p) {
migrationConfig.loadSettings(p);
namingConvention = createNamingConvention(p, namingConvention);
if (namingConvention != null) {
namingConvention.loadFromProperties(p);
}
if (autofetchConfig == null) {
autofetchConfig = new AutofetchConfig();
if (autoTuneConfig == null) {
autoTuneConfig = new AutoTuneConfig();
}
loadAutofetchSettings(p);
loadAutoTuneSettings(p);
if (dataSourceConfig == null) {
dataSourceConfig = new DataSourceConfig();
}
loadDataSourceSettings(p);
explicitTransactionBeginMode = p.getBoolean("explicitTransactionBeginMode", explicitTransactionBeginMode);
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager);
currentUserProvider = createInstance(p, CurrentUserProvider.class, "currentUserProvider");
disableClasspathSearch = p.getBoolean("disableClasspathSearch", disableClasspathSearch);
databasePlatform = createInstance(p, DatabasePlatform.class, "databasePlatform");
encryptKeyManager = createInstance(p, EncryptKeyManager.class, "encryptKeyManager");
encryptDeployManager = createInstance(p, EncryptDeployManager.class, "encryptDeployManager");
encryptor = createInstance(p, Encryptor.class, "encryptor");
dbEncrypt = createInstance(p, DbEncrypt.class, "dbEncrypt");
serverCacheFactory = createInstance(p, ServerCacheFactory.class, "serverCacheFactory");
serverCacheManager = createInstance(p, ServerCacheManager.class, "serverCacheManager");
currentUserProvider = createInstance(p, CurrentUserProvider.class, "currentUserProvider", currentUserProvider);
databasePlatform = createInstance(p, DatabasePlatform.class, "databasePlatform", databasePlatform);
encryptKeyManager = createInstance(p, EncryptKeyManager.class, "encryptKeyManager", encryptKeyManager);
encryptDeployManager = createInstance(p, EncryptDeployManager.class, "encryptDeployManager", encryptDeployManager);
encryptor = createInstance(p, Encryptor.class, "encryptor", encryptor);
dbEncrypt = createInstance(p, DbEncrypt.class, "dbEncrypt", dbEncrypt);
serverCacheFactory = createInstance(p, ServerCacheFactory.class, "serverCacheFactory", serverCacheFactory);
serverCacheManager = createInstance(p, ServerCacheManager.class, "serverCacheManager", serverCacheManager);
cacheWarmingDelay = p.getInt("cacheWarmingDelay", cacheWarmingDelay);
classPathReaderClassName = p.get("classpathreader");
@@ -1907,16 +2158,21 @@ public class ServerConfig {
persistenceContextScope = PersistenceContextScope.valueOf(p.get("persistenceContextScope", "TRANSACTION"));
changeLogIncludeInserts = p.getBoolean("changeLogIncludeInserts", changeLogIncludeInserts);
expressionEqualsWithNullAsNoop = p.getBoolean("expressionEqualsWithNullAsNoop", expressionEqualsWithNullAsNoop);
diffFlatMode = p.getBoolean("diffFlatMode", diffFlatMode);
asOfViewSuffix = p.get("asOfViewSuffix", asOfViewSuffix);
asOfSysPeriod = p.get("asOfSysPeriod", asOfSysPeriod);
historyTableSuffix = p.get("historyTableSuffix", historyTableSuffix);
dataSourceJndiName = p.get("dataSourceJndiName", dataSourceJndiName);
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
databasePlatformName = p.get("databasePlatformName", databasePlatformName);
uuidStoreAsBinary = p.getBoolean("uuidStoreAsBinary", uuidStoreAsBinary);
dbUuid = p.getEnum(DbUuid.class, "dbuuid", dbUuid);
if (p.getBoolean("uuidStoreAsBinary", false)) {
dbUuid = DbUuid.BINARY;
}
localTimeWithNanos = p.getBoolean("localTimeWithNanos", localTimeWithNanos);
lazyLoadBatchSize = p.getInt("lazyLoadBatchSize", lazyLoadBatchSize);
@@ -1938,7 +2194,7 @@ public class ServerConfig {
private NamingConvention createNamingConvention(PropertiesWrapper properties, NamingConvention namingConvention) {
NamingConvention nc = createInstance(properties, NamingConvention.class, "namingconvention");
NamingConvention nc = createInstance(properties, NamingConvention.class, "namingconvention", null);
return (nc != null) ? nc : namingConvention;
}
@@ -2020,22 +2276,6 @@ public class ServerConfig {
this.objectMapper = objectMapper;
}
/**
* Return true if diff should return flat properties with dot notation rather than
* embedded beans or reference beans (when the associated bean id is different).
*/
public boolean isDiffFlatMode() {
return diffFlatMode;
}
/**
* Set to true if diff should return flat properties with dot notation rather than
* embedded beans or reference beans (when the associated bean id is different).
*/
public void setDiffFlatMode(boolean diffFlatMode) {
this.diffFlatMode = diffFlatMode;
}
/**
* Return true if eq("someProperty", null) should to generate "1=1" rather than "is null" sql expression.
*/
@@ -2054,4 +2294,25 @@ public class ServerConfig {
public void setExpressionEqualsWithNullAsNoop(boolean expressionEqualsWithNullAsNoop) {
this.expressionEqualsWithNullAsNoop = expressionEqualsWithNullAsNoop;
}
/**
* Specify how UUID is stored.
*/
public enum DbUuid {
/**
* Store using native UUID in H2 and Postgres.
*/
AUTO,
/**
* Store using DB VARCHAR.
*/
VARCHAR,
/**
* Store using DB BINARY.
*/
BINARY
}
}
@@ -3,23 +3,26 @@ package com.avaje.ebean.config;
/**
* Converts between Camel Case and Underscore based names for both table and
* column names (and is the default naming convention in Ebean).
*
*
* @author emcgreal
* @author rbygrave
*/
public class UnderscoreNamingConvention extends AbstractNamingConvention {
/** Force toUnderscore to return in upper case. */
/**
* Force toUnderscore to return in upper case.
*/
private boolean forceUpperCase = false;
/** The digits compressed. */
/**
* The digits compressed.
*/
private boolean digitsCompressed = true;
/**
* Create with a given sequence format.
*
* @param sequenceFormat
* the sequence format
*
* @param sequenceFormat the sequence format
*/
public UnderscoreNamingConvention(String sequenceFormat) {
super(sequenceFormat);
@@ -34,39 +37,30 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention {
/**
* Returns the last part of the class name.
*
* @param beanClass
* the bean class
*
*
* @param beanClass the bean class
* @return the table name from class
*/
public TableName getTableNameByConvention(Class<?> beanClass) {
return new TableName(getCatalog(),
getSchema(),
toUnderscoreFromCamel(beanClass.getSimpleName()));
return new TableName(getCatalog(), getSchema(), toUnderscoreFromCamel(beanClass.getSimpleName()));
}
/**
* Converts Camel case property name to underscore based column name.
*
*
* @return the column from property
*/
public String getColumnFromProperty(Class<?> beanClass, String propertyName) {// Field
// field)
// {
public String getColumnFromProperty(Class<?> beanClass, String propertyName) {
return toUnderscoreFromCamel(propertyName);
}
/**
* Converts underscore based column name to Camel case property name.
*
* @param beanClass
* the bean class
* @param dbColumnName
* the db column name
*
*
* @param beanClass the bean class
* @param dbColumnName the db column name
* @return the property from column
*/
public String getPropertyFromColumn(Class<?> beanClass, String dbColumnName) {
@@ -110,7 +104,7 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention {
protected String toUnderscoreFromCamel(String camelCase) {
int lastUpper = -1;
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder(camelCase.length()+4);
for (int i = 0; i < camelCase.length(); i++) {
char c = camelCase.charAt(i);
@@ -144,16 +138,11 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention {
}
/**
* To camel from underscore.
*
* @param underscore
* the underscore
*
* @return the string
* Convert and return the from string from underscore to camel case.
*/
protected String toCamelFromUnderscore(String underscore) {
StringBuffer result = new StringBuffer();
StringBuilder result = new StringBuilder(underscore.length());
String[] vals = underscore.split("_");
for (int i = 0; i < vals.length; i++) {
@@ -5,6 +5,7 @@ import java.sql.Types;
import javax.sql.DataSource;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.DB2Ddl;
/**
* DB2 specific platform.
@@ -14,10 +15,11 @@ public class DB2Platform extends DatabasePlatform {
public DB2Platform() {
super();
this.name = "db2";
// only support getGeneratedKeys with non-batch JDBC
// so generally use SEQUENCE instead for H2
this.maxTableNameLength = 18;
this.maxConstraintNameLength = 18;
this.sqlLimiter = new Db2SqlLimiter();
this.platformDdl = new DB2Ddl(dbTypeMap, dbIdentity);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsSequence(true);
@@ -25,8 +27,6 @@ public class DB2Platform extends DatabasePlatform {
dbTypeMap.put(Types.REAL, new DbType("real"));
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 15));
this.dbDdlSyntax.setIdentity("generated by default as identity");
}
/**
@@ -1,15 +1,16 @@
package com.avaje.ebean.config.dbplatform;
import java.sql.Types;
import javax.sql.DataSource;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.Query;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import java.sql.Types;
/**
* Database platform specific settings.
*/
@@ -17,6 +18,7 @@ public class DatabasePlatform {
private static final Logger logger = LoggerFactory.getLogger(DatabasePlatform.class);
/**
* Behavior used when ending a query only transaction (at read committed isolation level).
*/
@@ -50,33 +52,33 @@ public class DatabasePlatform {
*/
protected OnQueryOnly onQueryOnly = OnQueryOnly.ROLLBACK;
/**
* The open quote used by quoted identifiers.
/**
* The open quote used by quoted identifiers.
*/
protected String openQuote = "\"";
/**
* The close quote used by quoted identifiers.
* The close quote used by quoted identifiers.
*/
protected String closeQuote = "\"";
/**
* For limit/offset, row_number etc limiting of SQL queries.
/**
* For limit/offset, row_number etc limiting of SQL queries.
*/
protected SqlLimiter sqlLimiter = new LimitOffsetSqlLimiter();
/**
* Mapping of JDBC to Database types.
/**
* Mapping of JDBC to Database types.
*/
protected DbTypeMap dbTypeMap = new DbTypeMap();
/**
* DB specific DDL syntax.
/**
* Set to true if the DB has native UUID type support.
*/
protected DbDdlSyntax dbDdlSyntax = new DbDdlSyntax();
protected boolean nativeUuidType;
/**
* Defines DB identity/sequence features.
/**
* Defines DB identity/sequence features.
*/
protected DbIdentity dbIdentity = new DbIdentity();
@@ -85,28 +87,28 @@ public class DatabasePlatform {
*/
protected DbHistorySupport historySupport;
/**
* The JDBC type to map booleans to (by default).
/**
* The JDBC type to map booleans to (by default).
*/
protected int booleanDbType = Types.BOOLEAN;
/**
* The JDBC type to map Blob to.
/**
* The JDBC type to map Blob to.
*/
protected int blobDbType = Types.BLOB;
/**
* The JDBC type to map Clob to.
/**
* The JDBC type to map Clob to.
*/
protected int clobDbType = Types.CLOB;
/**
* For Oracle treat empty strings as null.
/**
* For Oracle treat empty strings as null.
*/
protected boolean treatEmptyStringsAsNull;
/**
* The database platform name.
/**
* The database platform name.
*/
protected String name = "generic";
@@ -125,7 +127,7 @@ public class DatabasePlatform {
* The like clause. Can be overridden to disable default escape character.
*/
protected String likeClause = "like ?";
protected DbEncrypt dbEncrypt;
protected boolean idInExpandedForm;
@@ -145,6 +147,20 @@ public class DatabasePlatform {
*/
protected boolean disallowBatchOnCascade;
protected PlatformDdl platformDdl;
/**
* The maximum length of table names - used specifically when derived
* default table names for intersection tables.
*/
protected int maxTableNameLength = 60;
/**
* A value of 60 is a reasonable default for all databases except
* Oracle (limited to 30) and DB2 (limited to 18).
*/
protected int maxConstraintNameLength = 60;
/**
* Instantiates a new database platform.
*/
@@ -157,13 +173,42 @@ public class DatabasePlatform {
* "generic" is returned when no specific database platform has been set or
* found.
* </p>
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Return the maximum table name length.
* <p>
* This is used when deriving names of intersection tables.
* </p>
*/
public int getMaxTableNameLength() {
return maxTableNameLength;
}
/**
* Return the maximum constraint name allowed for the platform.
*/
public int getMaxConstraintNameLength() {
return maxConstraintNameLength;
}
/**
* Return the platform specific DDL.
*/
public PlatformDdl getPlatformDdl() {
return platformDdl;
}
/**
* Create and return a DDL handler for generating DDL scripts.
*/
public DdlHandler createDdlHandler(ServerConfig serverConfig) {
return platformDdl.createDdlHandler(serverConfig);
}
/**
* Return true if the JDBC driver does not allow additional queries to execute
* when a resultSet is being 'streamed' as is the case with findEach() etc.
@@ -177,16 +222,12 @@ public class DatabasePlatform {
/**
* Return a DB Sequence based IdGenerator.
*
* @param be
* the BackgroundExecutor that can be used to load the sequence if
* desired
* @param ds
* the DataSource
* @param seqName
* the name of the sequence
* @param batchSize
* the number of sequences that should be loaded
*
* @param be the BackgroundExecutor that can be used to load the sequence if
* desired
* @param ds the DataSource
* @param seqName the name of the sequence
* @param batchSize the number of sequences that should be loaded
*/
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
return null;
@@ -234,24 +275,22 @@ public class DatabasePlatform {
this.historySupport = historySupport;
}
/**
* Return true if the DB supports native UUID.
*/
public boolean isNativeUuidType() {
return nativeUuidType;
}
/**
* Return the mapping of JDBC to DB types.
*
*
* @return the db type map
*/
public DbTypeMap getDbTypeMap() {
return dbTypeMap;
}
/**
* Return the DDL syntax for this platform.
*
* @return the db ddl syntax
*/
public DbDdlSyntax getDbDdlSyntax() {
return dbDdlSyntax;
}
/**
* Return the column alias prefix.
*/
@@ -282,7 +321,7 @@ public class DatabasePlatform {
/**
* Return the close quote for quoted identifiers.
*
*
* @return the close quote
*/
public String getCloseQuote() {
@@ -291,7 +330,7 @@ public class DatabasePlatform {
/**
* Return the open quote for quoted identifiers.
*
*
* @return the open quote
*/
public String getOpenQuote() {
@@ -300,7 +339,7 @@ public class DatabasePlatform {
/**
* Return the JDBC type used to store booleans.
*
*
* @return the boolean db type
*/
public int getBooleanDbType() {
@@ -330,7 +369,7 @@ public class DatabasePlatform {
/**
* Return true if empty strings should be treated as null.
*
*
* @return true, if checks if is treat empty strings as null
*/
public boolean isTreatEmptyStringsAsNull() {
@@ -366,7 +405,7 @@ public class DatabasePlatform {
/**
* Return the DB identity/sequence features for this platform.
*
*
* @return the db identity
*/
public DbIdentity getDbIdentity() {
@@ -379,7 +418,7 @@ public class DatabasePlatform {
* <p>
* Basically add the clauses for limit/offset, rownum, row_number().
* </p>
*
*
* @return the sql limiter
*/
public SqlLimiter getSqlLimiter() {
@@ -388,15 +427,12 @@ public class DatabasePlatform {
/**
* Convert backticks to the platform specific open quote and close quote
*
* <p>
* Specific plugins may implement this method to cater for platform specific
* naming rules.
* </p>
*
* @param dbName
* the db name
*
*
* @param dbName the db name
* @return the string
*/
public String convertQuotedIdentifiers(String dbName) {
@@ -461,22 +497,4 @@ public class DatabasePlatform {
return disallowBatchOnCascade;
}
/**
* Generate and return the create sequence DDL.
*/
public String ddlCreateSequence(String sequenceName, int initialValue, int allocationSize) {
StringBuilder sb = new StringBuilder("create sequence ");
sb.append(sequenceName);
if (initialValue > 1) {
sb.append(" start with ").append(initialValue);
}
if (allocationSize > 0 && allocationSize != 50) {
// at this stage ignoring allocationSize 50 as this is the 'default' and
// not consistent with the way Ebean batch fetches sequence values
sb.append(" increment by ").append(allocationSize);
}
sb.append(";");
return sb.toString();
}
}
@@ -1,333 +0,0 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.TableName;
/**
* Used to support DB specific syntax for DDL generation.
*/
public class DbDdlSyntax {
protected boolean renderIndexForFkey = true;
protected boolean inlinePrimaryKeyConstraint = false;
protected boolean addOneToOneUniqueContraint = true;
protected int maxConstraintNameLength = 32;
protected int columnNameWidth = 25;
/**
* Flag set when we want to disable constraints on each table (rather than globally).
*/
protected boolean dropKeyConstraints;
protected String dropTableCascade;
protected String dropIfExists;
protected String newLine = "\n";
protected String identity = "auto_increment";
protected String identitySuffix = "";
protected String pkPrefix = "pk_";
protected String disableReferentialIntegrity;
protected String enableReferentialIntegrity;
protected String foreignKeySuffix;
/**
* Return the primary key name for a given bean descriptor.
*/
public String getPrimaryKeyName(String tableName) {
String pk = pkPrefix + tableName;
if (pk.length() > maxConstraintNameLength) {
// need to trim the primary key name
pk = pk.substring(0, maxConstraintNameLength);
}
return pk;
}
/**
* Return the column definition for an identity column.
*/
public String getIdentityColumnDefn(String columnDefn) {
String identity = getIdentity();
if (identity != null && identity.length() > 0) {
return columnDefn+" "+identity;
}
return columnDefn;
}
/**
* Return the identity clause for DB's that have identities.
*/
public String getIdentity() {
return identity;
}
/**
* Set the identity clause.
*/
public void setIdentity(String identity) {
this.identity = identity;
}
/**
* Typically returns empty string but for SQLite and perhaps others
* the Identity/AutoIncrement clause comes after the primary key clause.
*/
public String getIdentitySuffix() {
return identitySuffix;
}
/**
* Set the identity clause that would appear after the primary key clause.
* <p>
* Only used for SQLite at this stage.
* </p>
*/
public void setIdentitySuffix(String identitySuffix) {
this.identitySuffix = identitySuffix;
}
/**
* Return the width for padding whitespace after column names.
*/
public int getColumnNameWidth() {
return columnNameWidth;
}
/**
* Set the amount of padding to write after the column name.
*/
public void setColumnNameWidth(int columnNameWidth) {
this.columnNameWidth = columnNameWidth;
}
/**
* Return the new line character.
*/
public String getNewLine() {
return newLine;
}
/**
* Set the new line character.
*/
public void setNewLine(String newLine) {
this.newLine = newLine;
}
/**
* Return the prefix used in naming primary keys.
*/
public String getPkPrefix() {
return pkPrefix;
}
/**
* Set the prefix used in naming primary keys.
*/
public void setPkPrefix(String pkPrefix) {
this.pkPrefix = pkPrefix;
}
/**
* Return the DB specific command to disable referential integrity
*/
public String getDisableReferentialIntegrity() {
return disableReferentialIntegrity;
}
/**
* Set the DB specific command to disable referential integrity
*/
public void setDisableReferentialIntegrity(String disableReferentialIntegrity) {
this.disableReferentialIntegrity = disableReferentialIntegrity;
}
/**
* Return the DB specific command to enable referential integrity
*/
public String getEnableReferentialIntegrity() {
return enableReferentialIntegrity;
}
/**
* Set the DB specific command to enable referential integrity
*/
public void setEnableReferentialIntegrity(String enableReferentialIntegrity) {
this.enableReferentialIntegrity = enableReferentialIntegrity;
}
/**
* Return true to is constraints are disabled on each table.
*/
public boolean isDropKeyConstraints() {
return dropKeyConstraints;
}
/**
* Return some DDL to disable constraints on the given table.
*/
public String dropKeyConstraintPrefix(String tableName, String fkName) {
return null;
}
/**
* Return true if indexes should be created for the foreign keys.
*/
public boolean isRenderIndexForFkey() {
return renderIndexForFkey;
}
/**
* Set whether indexes should be created for the foreign keys.
*/
public void setRenderIndexForFkey(boolean renderIndexForFkey) {
this.renderIndexForFkey = renderIndexForFkey;
}
/**
* Typically returns IF EXISTS (if that is supported by the database platform)
* or null.
*/
public String getDropIfExists() {
return dropIfExists;
}
/**
* Set the IF EXISTS clause for dropping tables if that is supported by the
* database platform.
*/
public void setDropIfExists(String dropIfExists) {
this.dropIfExists = dropIfExists;
}
/**
* Return prefix text that goes before drop table.
*/
public String dropTablePrefix(String tableName) {
return "";
}
/**
* Return the cascade option for the drop table command.
*/
public String getDropTableCascade() {
return dropTableCascade;
}
/**
* Set the cascade option for the drop table command.
*/
public void setDropTableCascade(String dropTableCascade) {
this.dropTableCascade = dropTableCascade;
}
/**
* Return the foreign key suffix.
*/
public String getForeignKeySuffix() {
return foreignKeySuffix;
}
/**
* Set the foreign key suffix.
*/
public void setForeignKeySuffix(String foreignKeySuffix) {
this.foreignKeySuffix = foreignKeySuffix;
}
/**
* Return the maximum length that constraint names can be for this database.
*/
public int getMaxConstraintNameLength() {
return maxConstraintNameLength;
}
/**
* Set the maximum length that constraint names can be for this database.
*/
public void setMaxConstraintNameLength(int maxFkeyLength) {
this.maxConstraintNameLength = maxFkeyLength;
}
/**
* Return true if imported side of OneToOne's should have unique constraints
* generated.
*/
public boolean isAddOneToOneUniqueContraint() {
return addOneToOneUniqueContraint;
}
/**
* Set to false for DB's that don't want both a unique and index on the
* imported OneToOne.
*/
public void setAddOneToOneUniqueContraint(boolean addOneToOneUniqueContraint) {
this.addOneToOneUniqueContraint = addOneToOneUniqueContraint;
}
/**
* Return true if primary key constraints should be inlined when they are a
* single column.
*/
public boolean isInlinePrimaryKeyConstraint() {
return inlinePrimaryKeyConstraint;
}
/**
* Set whether to inline primary key constraints.
*/
public void setInlinePrimaryKeyConstraint(boolean inlinePrimaryKeyConstraint) {
this.inlinePrimaryKeyConstraint = inlinePrimaryKeyConstraint;
}
/**
* Builds and returns a fully index name.
*/
public String getIndexName(String table, String propName, int ixCount) {
StringBuilder buffer = new StringBuilder(30);
buffer.append("ix_").append(TableName.parse(table));
buffer.append("_").append(propName);
addSuffix(buffer, ixCount);
return buffer.toString();
}
/**
* Builds and returns a fully qualified foreign key constraint name.
*/
public String getForeignKeyName(String table, String propName, int fkCount) {
StringBuilder buffer = new StringBuilder(30);
buffer.append("fk_").append(TableName.parse(table));
buffer.append("_").append(propName);
addSuffix(buffer, fkCount);
return buffer.toString();
}
/**
* Adds the suffix.
*/
protected void addSuffix(StringBuilder buffer, int count) {
String suffixNr = Integer.toString(count);
int suffixLen = suffixNr.length() + 1;
if (buffer.length() + suffixLen > maxConstraintNameLength) {
buffer.setLength(maxConstraintNameLength - suffixLen);
}
buffer.append("_");
buffer.append(suffixNr);
}
}
@@ -5,6 +5,37 @@ package com.avaje.ebean.config.dbplatform;
*/
public interface DbHistorySupport {
/**
* Return true if the 'As of' predicate is part of the from clause
* (more standard sql2011). So true for Oracle total recall and false
* for Postgres and MySql (where we use views and history tables).
*/
boolean isBindWithFromClause();
/**
* Return the number of columns bound in a 'As Of' predicate.
* <p>
* This is 1 for more standard sql2011 style and Postgres which has the
* special range type and 2 for view based solutions with 2 columns such as
* MySql.
* </p>
*/
int getBindCount();
/**
* For sql2011 style this ignores the passed in view suffix and returns something
* like the ' as of timestamp ?' clause to be appended after the base table name.
*
* @param asOfViewSuffix the configured view suffix (typically "_with_history").
* @return The suffix appended after the base table name in the from and join clauses.
*/
String getAsOfViewSuffix(String asOfViewSuffix);
/**
* Return the 'versions between timestamp' suffix.
*/
String getVersionsBetweenSuffix(String asOfViewSuffix);
/**
* Return the 'as of' predicate added for the given table alias.
*
@@ -18,7 +49,7 @@ public interface DbHistorySupport {
* Return the column for the system period lower bound that will be included in findVersions() queries.
*
* @param tableAlias the table alias which will typically be 't0'
* @param sysPeriod the name of the sys_period column
* @param sysPeriod the name of the sys_period column
*/
String getSysPeriodLower(String tableAlias, String sysPeriod);
@@ -26,7 +57,7 @@ public interface DbHistorySupport {
* Return the column for the system period upper bound that will be included in findVersions() queries.
*
* @param tableAlias the table alias which will typically be 't0'
* @param sysPeriod the name of the sys_period column
* @param sysPeriod the name of the sys_period column
*/
String getSysPeriodUpper(String tableAlias, String sysPeriod);
@@ -1,5 +1,7 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.dbmigration.migration.IdentityType;
/**
* Defines the identity/sequence behaviour for the database.
*/
@@ -114,4 +116,28 @@ public class DbIdentity {
this.idType = idType;
}
/**
* Determine the id type to use based on requested identityType and
* the support for that in the database platform.
*/
public IdType useIdentityType(IdentityType identityType) {
if (identityType == null) {
// use the default
return idType;
}
switch (identityType) {
case GENERATOR:
return IdType.GENERATOR;
case EXTERNAL:
return IdType.EXTERNAL;
case SEQUENCE:
return supportsSequence ? IdType.SEQUENCE : idType;
case IDENTITY:
return supportsIdentity ? IdType.IDENTITY : idType;
}
// use the default
return idType;
}
}
@@ -0,0 +1,47 @@
package com.avaje.ebean.config.dbplatform;
/**
* Built in supported platforms.
*/
public enum DbPlatformName {
/**
* Generic base platform configured via properties or code.
*/
GENERIC,
/**
* H2.
*/
H2,
/**
* Postgres.
*/
POSTGRES,
/**
* MySql.
*/
MYSQL,
/**
* Oracle.
*/
ORACLE,
/**
* Microsoft SQL Server.
*/
SQLSERVER,
/**
* DB2.
*/
DB2,
/**
* SQLite.
*/
SQLITE
}
@@ -0,0 +1,32 @@
package com.avaje.ebean.config.dbplatform;
/**
* SQL2011 based history support using 'as of timestamp' type clause appended as part of the the from or join clause.
*/
public abstract class DbStandardHistorySupport implements DbHistorySupport {
/**
* Return true as with sql2011 the 'as of timestamp' clause included in from or join clause.
*/
@Override
public boolean isBindWithFromClause() {
return true;
}
/**
* Return 1 as the bind count (not 2 for effective start and effective end columns).
*/
@Override
public int getBindCount() {
return 1;
}
/**
* Return null - not used for sql2011 based history.
*/
@Override
public String getAsOfPredicate(String tableAlias, String sysPeriod) {
// not used for sql2011 based history
return null;
}
}
@@ -8,6 +8,11 @@ package com.avaje.ebean.config.dbplatform;
*/
public class DbType {
/**
* DB native UUID type (H2 and Postgres).
*/
public static final int UUID = 5010;
/**
* Type to map Map content to Postgres HSTORE.
*/
@@ -9,16 +9,82 @@ import java.util.Map;
*/
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("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();
loadDefaults(false);
}
private DbTypeMap(boolean logicalTypes) {
loadDefaults(logicalTypes);
}
/**
* Load the standard types. These can be overridden by DB specific platform.
*/
private void loadDefaults() {
private void loadDefaults(boolean logicalTypes) {
put(Types.BOOLEAN, new DbType("boolean"));
put(Types.BIT, new DbType("bit"));
@@ -37,11 +103,25 @@ public class DbTypeMap {
put(Types.BLOB, new DbType("blob"));
put(Types.CLOB, new DbType("clob"));
put(DbType.JSON, new DbType("clob")); // Postgres maps this to JSON
put(DbType.JSONB, new DbType("clob")); // Postgres maps this to JSONB
put(DbType.JSONClob, new DbType("clob"));
put(DbType.JSONBlob, new DbType("blob"));
put(DbType.JSONVarchar, new DbType("varchar", 1000));
// DB native UUID support (H2 and Postgres)
put(DbType.UUID, new DbType("uuid"));
if (logicalTypes) {
// keep it logical for 2 layer DDL generation
put(DbType.HSTORE, new DbType("hstore"));
put(DbType.JSON, new DbType("json"));
put(DbType.JSONB, new DbType("jsonb"));
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"));
@@ -54,24 +134,58 @@ public class DbTypeMap {
}
/**
* Lookup the platform specific DbType given the standard sql type name.
*/
public DbType lookup(String name) {
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);
case DbType.JSONB:
return getJsonType(DbType.JSONB);
default:
return get(typeKey);
}
}
private DbType getJsonType(int type) {
DbType dbType = get(type);
if (dbType == JSON_CLOB_PLACEHOLDER) {
return 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(Integer.valueOf(jdbcType), dbType);
typeMap.put(jdbcType, dbType);
}
/**
* Return the type for a given jdbc type.
*/
public DbType get(int jdbcType) {
DbType dbType = typeMap.get(Integer.valueOf(jdbcType));
if (dbType == null) {
String m = "No DB type for JDBC type " + jdbcType;
throw new RuntimeException(m);
}
return dbType;
return typeMap.get(jdbcType);
}
}
@@ -0,0 +1,82 @@
package com.avaje.ebean.config.dbplatform;
/**
* Database view based implementation of DbHistorySupport.
* <p>
* These implementations have explicit history tables, a view to union the
* base table and history table and triggers to maintain the history.
* </p>
*/
public abstract class DbViewHistorySupport implements DbHistorySupport {
/**
* Return false for view based implementations where we append extra 'as of' predicates to the end.
*/
@Override
public boolean isBindWithFromClause() {
return false;
}
/**
* Returns the configured view suffix.
*
* @param asOfViewSuffix the configured view suffix (typically "_with_history").
*/
@Override
public String getAsOfViewSuffix(String asOfViewSuffix) {
// just return the configured suffix
return asOfViewSuffix;
}
/**
* Returns the configured view suffix (same as getAsOfViewSuffix()).
*
* @param asOfViewSuffix the configured view suffix (typically "_with_history").
*/
@Override
public String getVersionsBetweenSuffix(String asOfViewSuffix) {
// just return the configured asOfViewSuffix (using the view for versions between query)
return asOfViewSuffix;
}
/**
* Return 2 if we have effective start and effective end as 2 columns.
* Note that for postgres we can use a single range type so that returns 1.
*/
@Override
public int getBindCount() {
return 2;
}
/**
* Return the 'as of' predicate clause appended to the end of the normal query predicates.
*/
@Override
public String getAsOfPredicate(String asOfTableAlias, String asOfSysPeriod) {
// (sys_period_start < ? and (sys_period_end is null or sys_period_end > ?));
return "(" + asOfTableAlias + "." + asOfSysPeriod + "_start" + " <= ? and (" + asOfTableAlias + "." + asOfSysPeriod + "_end" + " is null or " + asOfTableAlias + "." + asOfSysPeriod + "_end" + " > ?))";
}
/**
* Return the lower bound column prepended with the table alias.
*
* @param tableAlias the table alias
* @param sysPeriod the name of the sys_period column
*/
@Override
public String getSysPeriodLower(String tableAlias, String sysPeriod) {
return tableAlias + "." + sysPeriod + "_start";
}
/**
* Return the upper bound column prepended with the table alias.
*
* @param tableAlias the table alias
* @param sysPeriod the name of the sys_period column
*/
@Override
public String getSysPeriodUpper(String tableAlias, String sysPeriod) {
return tableAlias + "." + sysPeriod + "_end";
}
}
@@ -0,0 +1,8 @@
package com.avaje.ebean.config.dbplatform;
/**
* Runtime support for @History with H2.
*/
public class H2HistorySupport extends DbViewHistorySupport {
}
@@ -0,0 +1,127 @@
package com.avaje.ebean.config.dbplatform;
import org.h2.api.Trigger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
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.
*/
public class H2HistoryTrigger implements Trigger {
private static final Logger logger = LoggerFactory.getLogger(H2HistoryTrigger.class);
/**
* Hardcoding the column and history table suffix for now. Not sure how to get that
* configuration into the trigger instance nicely as it is instantiated by H2.
*/
private static final String SYS_PERIOD_START = "SYS_PERIOD_START";
private static final String SYS_PERIOD_END = "SYS_PERIOD_END";
private static final String HISTORY_SUFFIX = "_history";
/**
* SQL to insert into the history table.
*/
private String insertHistorySql;
/**
* Position of SYS_PERIOD_START column in the Object[].
*/
private int effectStartPosition;
/**
* Position of SYS_PERIOD_END column in the Object[].
*/
private int effectEndPosition;
@Override
public void init(Connection conn, String schemaName, String triggerName, String tableName, boolean before, int type) throws SQLException {
// get the columns for the table
ResultSet rs = conn.getMetaData().getColumns(null, schemaName, tableName, null);
// build the insert into history table SQL
StringBuilder insertSql = new StringBuilder(150);
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(",");
}
String columnName = rs.getString("COLUMN_NAME");
if (columnName.equalsIgnoreCase(SYS_PERIOD_START)) {
this.effectStartPosition = count - 1;
} else if (columnName.equalsIgnoreCase(SYS_PERIOD_END)) {
this.effectEndPosition = count - 1;
}
insertSql.append(columnName);
columns.add(columnName);
}
insertSql.append(") values (");
for (int i = 0; i < count; i++) {
if (i > 0) {
insertSql.append(",");
}
insertSql.append("?");
}
insertSql.append(");");
this.insertHistorySql = insertSql.toString();
logger.debug("History table insert sql: {}", insertHistorySql);
}
@Override
public void fire(Connection connection, Object[] oldRow, Object[] newRow) throws SQLException {
if (oldRow != null) {
// a delete or update event
Timestamp now = new Timestamp(System.currentTimeMillis());
oldRow[effectEndPosition] = now;
if (newRow != null) {
// update event. Set the effective start timestamp to now.
newRow[effectStartPosition] = now;
}
if (logger.isDebugEnabled()) {
logger.debug("History insert: {}", Arrays.toString(oldRow));
}
insertIntoHistory(connection, oldRow);
}
}
/**
* Insert the data into the history table.
*/
private void insertIntoHistory(Connection connection, Object[] oldRow) throws SQLException {
PreparedStatement stmt = connection.prepareStatement(insertHistorySql);
try {
for (int i = 0; i < oldRow.length; i++) {
stmt.setObject(i + 1, oldRow[i]);
}
stmt.executeUpdate();
} finally {
stmt.close();
}
}
@Override
public void close() throws SQLException {
}
@Override
public void remove() throws SQLException {
}
}
@@ -1,6 +1,7 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.H2Ddl;
import javax.sql.DataSource;
@@ -13,9 +14,9 @@ public class H2Platform extends DatabasePlatform {
super();
this.name = "h2";
this.dbEncrypt = new H2DbEncrypt();
// like ? escape'' not working in the latest version H2 so just using no
// escape clause for now noting that backslash is an escape char for like in H2
this.likeClause = "like ?";
this.platformDdl = new H2Ddl(this.dbTypeMap, dbIdentity);
this.historySupport = new H2HistorySupport();
this.nativeUuidType = true;
// only support getGeneratedKeys with non-batch JDBC
// so generally use SEQUENCE instead of IDENTITY for H2
@@ -24,16 +25,12 @@ public class H2Platform extends DatabasePlatform {
this.dbIdentity.setSupportsSequence(true);
this.dbIdentity.setSupportsIdentity(true);
this.openQuote = "\"";
this.closeQuote = "\"";
// like ? escape'' not working in the latest version H2 so just using no
// escape clause for now noting that backslash is an escape char for like in H2
this.likeClause = "like ?";
// H2 data types match default JDBC types
// so no changes to dbTypeMap required
this.dbDdlSyntax.setDropIfExists("if exists");
this.dbDdlSyntax.setDisableReferentialIntegrity("SET REFERENTIAL_INTEGRITY FALSE");
this.dbDdlSyntax.setEnableReferentialIntegrity("SET REFERENTIAL_INTEGRITY TRUE");
this.dbDdlSyntax.setForeignKeySuffix("on delete restrict on update restrict");
}
/**
@@ -1,6 +1,7 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.HsqldbDdl;
import javax.sql.DataSource;
import java.sql.Types;
@@ -14,32 +15,18 @@ public class HsqldbPlatform extends DatabasePlatform {
super();
this.name = "hsqldb";
this.dbEncrypt = new H2DbEncrypt();
this.platformDdl = new HsqldbDdl(dbTypeMap, dbIdentity);
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsSequence(true);
this.dbIdentity.setSupportsIdentity(true);
this.openQuote = "\"";
this.closeQuote = "\"";
// H2 data types match default JDBC types
// so no changes to dbTypeMap required
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
this.dbDdlSyntax.setDropIfExists("if exists");
this.dbDdlSyntax.setDisableReferentialIntegrity("SET DATABASE REFERENTIAL INTEGRITY FALSE");
this.dbDdlSyntax.setEnableReferentialIntegrity("SET DATABASE REFERENTIAL INTEGRITY TRUE");
this.dbDdlSyntax.setForeignKeySuffix("on delete restrict on update restrict");
this.dbDdlSyntax.setIdentity("GENERATED BY DEFAULT AS IDENTITY (START WITH 1) ");
}
/**
* Return a H2 specific sequence IdGenerator that supports batch fetching
* sequence values.
*/
@Override
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be,
DataSource ds, String seqName, int batchSize) {
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
return new H2SequenceIdGenerator(be, ds, seqName, batchSize);
}
@@ -16,7 +16,7 @@ public interface IdGenerator {
/**
* The name of the default UUID generator.
*/
static final String AUTO_UUID = "auto.uuid";
String AUTO_UUID = "auto.uuid";
/**
* Return the name of the IdGenerator. For sequences this is the sequence
@@ -26,6 +26,15 @@ public enum IdType {
* id properties of type UUID.
* </p>
*/
GENERATOR;
GENERATOR,
/**
* Expected that the identity is externally set (for example a ISO code for
* country or currency or a user defined code for lookup tables).
* <p>
* Used when the key is a compound key or lookup table code.
* </p>
*/
EXTERNAL
}
@@ -1,5 +1,7 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.MsSqlServerDdl;
import java.sql.Types;
/**
@@ -21,8 +23,9 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
// due to lack of support for getGeneratedKeys in batch mode
this.disallowBatchOnCascade = true;
this.idInExpandedForm = true;
this.selectCountWithAlias = true;
this.sqlLimiter = new MsSqlServer2005SqlLimiter();
this.dbDdlSyntax = new MsDdlSyntax();
this.platformDdl = new MsSqlServerDdl(dbTypeMap, dbIdentity);
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsIdentity(true);
@@ -44,35 +47,9 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
dbTypeMap.put(Types.LONGVARBINARY, new DbType("image"));
dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
dbTypeMap.put(Types.DATE, new DbType("datetime"));
dbTypeMap.put(Types.TIME, new DbType("datetime"));
dbTypeMap.put(Types.TIMESTAMP, new DbType("datetime"));
}
/**
* MS SQL Server specific DDL Syntax.
*/
public class MsDdlSyntax extends DbDdlSyntax {
MsDdlSyntax() {
this.identity = "identity(1,1)";
this.dropKeyConstraints = true;
}
/**
* Return some DDL to disable constraints on the given table.
*/
public String dropKeyConstraintPrefix(String tableName, String fkName) {
return "IF OBJECT_ID('"+fkName+"', 'F') IS NOT NULL";
}
/**
* Return prefix text that goes before drop table.
*/
public String dropTablePrefix(String tableName) {
return "IF OBJECT_ID('"+tableName+"', 'U') IS NOT NULL ";
}
dbTypeMap.put(Types.DATE, new DbType("date"));
dbTypeMap.put(Types.TIME, new DbType("time"));
dbTypeMap.put(Types.TIMESTAMP, new DbType("datetime2"));
}
@@ -31,10 +31,11 @@ public class MsSqlServer2005SqlLimiter implements SqlLimiter {
if (firstRow < 1) {
// just use top n
sb.append(" select top ").append(lastRow).append(" ");
sb.append(" select ");
if (request.isDistinct()) {
sb.append("distinct ");
}
sb.append(" top ").append(lastRow).append(" ");
sb.append(request.getDbSql());
return new SqlLimitResponse(sb.toString(), false);
}
@@ -0,0 +1,8 @@
package com.avaje.ebean.config.dbplatform;
/**
* Runtime support for @History with MySql.
*/
public class MySqlHistorySupport extends DbViewHistorySupport {
}
@@ -1,6 +1,7 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.MySqlDdl;
import javax.sql.DataSource;
import java.sql.Types;
@@ -24,6 +25,8 @@ public class MySqlPlatform extends DatabasePlatform {
this.likeClause = "like ? escape''";
this.selectCountWithAlias = true;
this.dbEncrypt = new MySqlDbEncrypt();
this.platformDdl = new MySqlDdl(this.dbTypeMap, this.dbIdentity);
this.historySupport = new MySqlHistorySupport();
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
@@ -43,12 +46,6 @@ public class MySqlPlatform extends DatabasePlatform {
dbTypeMap.put(Types.BLOB, new MySqlBlob());
dbTypeMap.put(Types.BINARY, new DbType("binary", 255));
dbTypeMap.put(Types.VARBINARY, new DbType("varbinary", 255));
dbDdlSyntax.setMaxConstraintNameLength(64);
dbDdlSyntax.setDisableReferentialIntegrity("SET FOREIGN_KEY_CHECKS=0");
dbDdlSyntax.setEnableReferentialIntegrity("SET FOREIGN_KEY_CHECKS=1");
dbDdlSyntax.setForeignKeySuffix("on delete restrict on update restrict");
}
/**
@@ -1,15 +0,0 @@
package com.avaje.ebean.config.dbplatform;
/**
* Since Ebean v2.2.0 Oracle9 is no different from Oracle10.
* <p>
* This will be removed in the future.
* </p>
*/
public class Oracle9Platform extends Oracle10Platform {
public Oracle9Platform() {
super();
}
}
@@ -43,25 +43,25 @@ package com.avaje.ebean.config.dbplatform;
*
* @author rbygrave
*/
public class Oracle10DbEncrypt extends AbstractDbEncrypt {
public class OracleDbEncrypt extends AbstractDbEncrypt {
/**
* Constructs the Oracle10DbEncrypt with default encrypt and decrypt stored procedures.
*/
public Oracle10DbEncrypt() {
public OracleDbEncrypt() {
this("eb_encrypt", "eb_decrypt");
}
/**
* Constructs the Oracle10DbEncrypt specifying encrypt and decrypt stored procedures.
*
* @param encryptfunction the encrypt stored procedure
* @param decryptfunction the decrypt stored procedure
* @param encryptFunction the encrypt stored procedure
* @param decryptFunction the decrypt stored procedure
*/
public Oracle10DbEncrypt(String encryptfunction, String decryptfunction) {
public OracleDbEncrypt(String encryptFunction, String decryptFunction) {
this.varcharEncryptFunction = new OraVarcharFunction(encryptfunction, decryptfunction);
this.dateEncryptFunction = new OraDateFunction(encryptfunction, decryptfunction);
this.varcharEncryptFunction = new OraVarcharFunction(encryptFunction, decryptFunction);
this.dateEncryptFunction = new OraDateFunction(encryptFunction, decryptFunction);
}
/**
@@ -0,0 +1,37 @@
package com.avaje.ebean.config.dbplatform;
/**
* Oracle Total recall based history support.
*/
public class OracleDbHistorySupport extends DbStandardHistorySupport {
/**
* Return the ' as of timestamp ?' clause appended after the table name.
*/
@Override
public String getAsOfViewSuffix(String asOfViewSuffix) {
return " as of TIMESTAMP ?";
}
@Override
public String getVersionsBetweenSuffix(String asOfViewSuffix) {
return " versions between timestamp ? and ?";
}
/**
* Returns the Oracle specific effective start column.
*/
@Override
public String getSysPeriodLower(String tableAlias, String sysPeriod) {
return "versions_starttime";
}
/**
* Returns the Oracle specific effective end column.
*/
@Override
public String getSysPeriodUpper(String tableAlias, String sysPeriod) {
return "versions_endtime";
}
}
@@ -1,6 +1,7 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.Oracle10Ddl;
import javax.sql.DataSource;
import java.sql.Types;
@@ -8,15 +9,19 @@ import java.sql.Types;
/**
* Oracle10 and greater specific platform.
*/
public class Oracle10Platform extends DatabasePlatform {
public class OraclePlatform extends DatabasePlatform {
public Oracle10Platform() {
public OraclePlatform() {
super();
this.name = "oracle";
this.maxTableNameLength = 30;
this.maxConstraintNameLength = 30;
// OnQueryOnly.CLOSE as a performance optimisation on Oracle
this.onQueryOnly = OnQueryOnly.CLOSE;
this.dbEncrypt = new Oracle10DbEncrypt();
this.dbEncrypt = new OracleDbEncrypt();
this.sqlLimiter = new RownumSqlLimiter();
this.platformDdl = new Oracle10Ddl(this.dbTypeMap, this.dbIdentity);
this.historySupport = new OracleDbHistorySupport();
// Not using getGeneratedKeys as instead we will
// batch load sequences which enables JDBC batch execution
@@ -48,15 +53,10 @@ public class Oracle10Platform extends DatabasePlatform {
dbTypeMap.put(Types.BINARY, new DbType("raw", 255));
dbTypeMap.put(Types.TIME, new DbType("timestamp"));
dbDdlSyntax.setDropTableCascade("cascade constraints purge");
dbDdlSyntax.setIdentity(null);
dbDdlSyntax.setMaxConstraintNameLength(30);
}
@Override
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds,
String seqName, int batchSize) {
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
return new OracleSequenceIdGenerator(be, ds, seqName, batchSize);
}
@@ -1,66 +1,20 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.BackgroundExecutor;
import javax.sql.DataSource;
import java.sql.Types;
/**
* Postgres v8.3 specific platform.
* <p>
* No support for getGeneratedKeys.
* </p>
*/
public class Postgres8Platform extends DatabasePlatform {
public class Postgres8Platform extends PostgresPlatform {
public Postgres8Platform() {
super();
this.name = "postgres";
this.selectCountWithAlias = true;
this.blobDbType = Types.LONGVARBINARY;
this.clobDbType = Types.VARCHAR;
this.dbEncrypt = new PostgresDbEncrypt();
this.historySupport = new PostgresHistorySupport();
this.dbIdentity.setSupportsGetGeneratedKeys(false);
this.dbIdentity.setIdType(IdType.SEQUENCE);
this.dbIdentity.setSupportsSequence(true);
this.dbIdentity.setSupportsIdentity(true);
this.columnAliasPrefix = "as c";
this.openQuote = "\"";
this.closeQuote = "\"";
// dbTypeMap.put(Types.BOOLEAN, new DbType("bit default 0"));
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.BINARY, new DbType("bytea", false));
dbTypeMap.put(Types.VARBINARY, new DbType("bytea", false));
dbTypeMap.put(Types.BLOB, new DbType("bytea", false));
dbTypeMap.put(Types.CLOB, new DbType("text"));
dbTypeMap.put(Types.LONGVARBINARY, new DbType("bytea", false));
dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
dbDdlSyntax.setDropTableCascade("cascade");
dbDdlSyntax.setDropIfExists("if exists");
}
/**
* Create a Postgres specific sequence IdGenerator.
*/
@Override
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
return new PostgresSequenceIdGenerator(be, ds, seqName, batchSize);
}
@Override
protected String withForUpdate(String sql) {
return sql + " for update";
}
}
@@ -1,25 +0,0 @@
package com.avaje.ebean.config.dbplatform;
public class PostgresDdlSyntax extends DbDdlSyntax {
/**
* Map bigint, integer and smallint into their equivilent serial types.
*/
@Override
public String getIdentityColumnDefn(String columnDefn) {
//smallserial, serial and bigserial
if ("bigint".equalsIgnoreCase(columnDefn)) {
return "bigserial";
}
if ("integer".equalsIgnoreCase(columnDefn)) {
return "serial";
}
if ("smallint".equalsIgnoreCase(columnDefn)) {
return "smallserial";
}
return columnDefn;
}
}
@@ -3,7 +3,15 @@ package com.avaje.ebean.config.dbplatform;
/**
* Postgres support for history features.
*/
public class PostgresHistorySupport implements DbHistorySupport {
public class PostgresHistorySupport extends DbViewHistorySupport {
/**
* Return 1 as we are using the postgres range type and hence don't need 2 bind variables.
*/
@Override
public int getBindCount() {
return 1;
}
/**
* Build and return the 'as of' predicate for a given table alias.
@@ -16,18 +24,16 @@ public class PostgresHistorySupport implements DbHistorySupport {
// for Postgres we are using the 'timestamp with timezone range' data type
// as our sys_period column so hence the predicate below
StringBuilder sb = new StringBuilder(40);
sb.append(asOfTableAlias).append(".").append(asOfSysPeriod).append(" @> ?::timestamptz");
return sb.toString();
return asOfTableAlias + "." + asOfSysPeriod + " @> ?::timestamptz";
}
@Override
public String getSysPeriodLower(String tableAlias, String sysPeriod) {
return "lower("+tableAlias+"."+sysPeriod+")";
return "lower(" + tableAlias + "." + sysPeriod + ")";
}
@Override
public String getSysPeriodUpper(String tableAlias, String sysPeriod) {
return "upper("+tableAlias+"."+sysPeriod+")";
return "upper(" + tableAlias + "." + sysPeriod + ")";
}
}
@@ -1,6 +1,9 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PostgresDdl;
import javax.sql.DataSource;
import java.sql.Types;
@@ -16,29 +19,32 @@ public class PostgresPlatform extends DatabasePlatform {
public PostgresPlatform() {
super();
this.name = "postgres";
// OnQueryOnly.CLOSE as a performance optimisation on Postgres
this.onQueryOnly = OnQueryOnly.CLOSE;
this.likeClause = "like ? escape''";
this.dbDdlSyntax = new PostgresDdlSyntax();
this.selectCountWithAlias = true;
this.blobDbType = Types.LONGVARBINARY;
this.clobDbType = Types.VARCHAR;
this.dbEncrypt = new PostgresDbEncrypt();
this.historySupport = new PostgresHistorySupport();
this.platformDdl = new PostgresDdl(this.dbTypeMap, this.dbIdentity);
// Use Identity and getGeneratedKeys
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsSequence(true);
this.columnAliasPrefix = "as c";
//this.columnAliasPrefix = "as c";
this.openQuote = "\"";
this.closeQuote = "\"";
DbType dbTypeText = new DbType("text");
DbType dbBytea = new DbType("bytea", false);
dbTypeMap.put(DbType.HSTORE, new DbType("hstore"));
dbTypeMap.put(DbType.JSON, new DbType("json"));
dbTypeMap.put(DbType.JSONB, new DbType("jsonb"));
@@ -48,18 +54,22 @@ public class PostgresPlatform extends DatabasePlatform {
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 38));
dbTypeMap.put(Types.BINARY, new DbType("bytea", false));
dbTypeMap.put(Types.VARBINARY, new DbType("bytea", false));
dbTypeMap.put(Types.BINARY, dbBytea);
dbTypeMap.put(Types.VARBINARY, dbBytea);
dbTypeMap.put(Types.BLOB, new DbType("bytea", false));
dbTypeMap.put(Types.CLOB, new DbType("text"));
dbTypeMap.put(Types.LONGVARBINARY, new DbType("bytea", false));
dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
dbTypeMap.put(Types.BLOB, dbBytea);
dbTypeMap.put(Types.CLOB, dbTypeText);
dbTypeMap.put(Types.LONGVARBINARY, dbBytea);
dbTypeMap.put(Types.LONGVARCHAR, dbTypeText);
dbDdlSyntax.setDropTableCascade("cascade");
dbDdlSyntax.setDropIfExists("if exists");
}
/**
* Return a DdlHandler instance for generating DDL for the specific platform.
*/
public DdlHandler createDdlHandler(ServerConfig serverConfig) {
return this.platformDdl.createDdlHandler(serverConfig);
}
/**
* Create a Postgres specific sequence IdGenerator.
@@ -1,22 +1,20 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.SQLiteDdl;
import java.sql.Types;
import javax.sql.DataSource;
import com.avaje.ebean.BackgroundExecutor;
public class SQLitePlatform extends DatabasePlatform {
public SQLitePlatform() {
super();
this.name = "sqlite";
this.platformDdl = new SQLiteDdl(dbTypeMap, dbIdentity);
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(false);
this.dbIdentity.setSupportsSequence(false);
this.dbIdentity.setSelectLastInsertedIdTemplate("select last_insert_rowid()");
this.openQuote = "\"";
this.closeQuote = "\"";
this.booleanDbType = Types.INTEGER;
@@ -24,25 +22,7 @@ public class SQLitePlatform extends DatabasePlatform {
dbTypeMap.put(Types.BOOLEAN, new DbType("int default 0"));
dbTypeMap.put(Types.BIGINT, new DbType("integer"));
dbTypeMap.put(Types.SMALLINT, new DbType("integer"));
dbDdlSyntax.setInlinePrimaryKeyConstraint(true);
// AutoIncrement goes the primary key declaration
dbDdlSyntax.setIdentity("");
dbDdlSyntax.setIdentitySuffix("AUTOINCREMENT");
dbDdlSyntax.setDisableReferentialIntegrity("PRAGMA foreign_keys = OFF");
dbDdlSyntax.setEnableReferentialIntegrity("PRAGMA foreign_keys = ON");
}
/**
* Return null in case there is a sequence annotation.
*/
@Override
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be,
DataSource ds, String seqName, int batchSize) {
return null;
}
}
@@ -42,7 +42,7 @@ public abstract class SequenceIdGenerator implements IdGenerator {
protected final ArrayList<Long> idList = new ArrayList<Long>(50);
protected int batchSize;
protected final int batchSize;
protected int currentlyBackgroundLoading;
@@ -61,8 +61,7 @@ public class SimpleSequenceIdGenerator implements IdGenerator {
pstmt = c.prepareStatement(sql);
rset = pstmt.executeQuery();
if (rset.next()) {
int val = rset.getInt(1);
return Integer.valueOf(val);
return rset.getInt(1);
} else {
String m = "Always expecting 1 row from " + sql;
throw new PersistenceException(m);
@@ -11,7 +11,6 @@ import java.sql.Types;
* </ul>
* </p>
*/
public class SqlAnywherePlatform extends DatabasePlatform {
public SqlAnywherePlatform() {
@@ -11,12 +11,7 @@ public interface SqlLimiter {
* Note that this is removed for logging sql to the transaction log.
* </p>
*/
static final char NEW_LINE = '\n';
/**
* The carriage return character.
*/
static final char CARRIAGE_RETURN = '\r';
char NEW_LINE = '\n';
/**
* Add the SQL limiting statements around the query.
@@ -0,0 +1,327 @@
package com.avaje.ebean.dbmigration;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.config.DbConstraintNaming;
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.dbplatform.H2Platform;
import com.avaje.ebean.config.dbplatform.MsSqlServer2005Platform;
import com.avaje.ebean.config.dbplatform.MySqlPlatform;
import com.avaje.ebean.config.dbplatform.OraclePlatform;
import com.avaje.ebean.config.dbplatform.PostgresPlatform;
import com.avaje.ebean.config.dbplatform.SQLitePlatform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.migration.Migration;
import com.avaje.ebean.dbmigration.migrationreader.MigrationXmlWriter;
import com.avaje.ebean.dbmigration.model.CurrentModel;
import com.avaje.ebean.dbmigration.model.MConfiguration;
import com.avaje.ebean.dbmigration.model.MigrationModel;
import com.avaje.ebean.dbmigration.model.ModelContainer;
import com.avaje.ebean.dbmigration.model.PlatformDdlWriter;
import com.avaje.ebean.dbmigration.model.ModelDiff;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Generates DB Migration xml and sql scripts.
* <p>
* Reads the prior migrations and compares with the current model of the EbeanServer
* and generates a migration 'diff' in the form of xml document with the logical schema
* changes and a series of sql scripts to apply, rollback the applied changes if necessary
* and drop objects (drop tables, drop columns).
* </p>
* <p>
* This does not run the migration or ddl scripts but just generates them.
* </p>
* <pre>{@code
*
* DbMigration migration = new DbMigration();
* migration.setPathToResources("src/main/resources");
* migration.setPlatform(DbPlatformName.ORACLE);
*
* migration.generateMigration();
*
* }</pre>
*/
public class DbMigration {
protected static final Logger logger = LoggerFactory.getLogger(DbMigration.class);
protected SpiEbeanServer server;
protected DbMigrationConfig migrationConfig;
protected String pathToResources = "src/main/resources";
protected DatabasePlatform databasePlatform;
protected List<Pair> platforms = new ArrayList<Pair>();
protected ServerConfig serverConfig;
protected DbConstraintNaming constraintNaming;
public DbMigration() {
}
/**
* Set the path from the current working directory to the application resources.
*
* This defaults to maven style 'src/main/resources'.
*/
public void setPathToResources(String pathToResources) {
this.pathToResources = pathToResources;
}
/**
* Set the server to use to determine the current model.
* Typically this is not called explicitly.
*/
public void setServer(EbeanServer ebeanServer) {
this.server = (SpiEbeanServer) ebeanServer;
setServerConfig(server.getServerConfig());
}
/**
* Set the serverConfig to use. Typically this is not called explicitly.
*/
public void setServerConfig(ServerConfig config) {
if (this.serverConfig == null) {
this.serverConfig = config;
}
if (migrationConfig == null) {
this.migrationConfig = serverConfig.getMigrationConfig();
}
if (constraintNaming == null) {
this.constraintNaming = serverConfig.getConstraintNaming();
}
}
/**
* Set the specific platform to generate DDL for.
* <p>
* If not set this defaults to the platform of the default server.
* </p>
*/
public void setPlatform(DbPlatformName platform) {
setPlatform(getPlatform(platform));
}
/**
* Set the specific platform to generate DDL for.
* <p>
* If not set this defaults to the platform of the default server.
* </p>
*/
public void setPlatform(DatabasePlatform databasePlatform) {
this.databasePlatform = databasePlatform;
DbOffline.setPlatform(databasePlatform.getName());
}
/**
* Add an additional platform to write the migration DDL.
* <p>
* Use this when you want to generate sql scripts for multiple database platforms
* 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 += "-";
}
platforms.add(new Pair(getPlatform(platform), prefix));
}
/**
* Generate the next migration xml file and associated apply and rollback sql scripts.
* <p>
* This does not run the migration or ddl scripts but just generates them.
* </p>
* <h3>Example: Run for a single specific platform</h3>
* <pre>{@code
*
* DbMigration migration = new DbMigration();
* migration.setPathToResources("src/main/resources");
* migration.setPlatform(DbPlatformName.ORACLE);
*
* migration.generateMigration();
*
* }</pre>
*
* <h3>Example: Run migration generating DDL for multiple platforms</h3>
* <pre>{@code
*
* DbMigration migration = new DbMigration();
* migration.setPathToResources("src/main/resources");
*
* migration.addPlatform(DbPlatformName.POSTGRES, "pg");
* migration.addPlatform(DbPlatformName.MYSQL, "mysql");
* migration.addPlatform(DbPlatformName.ORACLE, "mysql");
*
* migration.generateMigration();
*
* }</pre>
*/
public void generateMigration() throws IOException {
// use this flag to stop other plugins like full DDL generation
DbOffline.setRunningMigration();
setDefaults();
try {
MigrationModel migrationModel = new MigrationModel(migrationConfig.getResourcePath());
ModelContainer migrated = migrationModel.read();
int nextMajorVersion = migrationModel.getNextMajorVersion();
logger.info("next migration version {}", nextMajorVersion);
CurrentModel currentModel = new CurrentModel(server, constraintNaming);
ModelContainer current = currentModel.read();
ModelDiff diff = new ModelDiff(migrated);
diff.compareTo(current);
if (diff.isEmpty()) {
logger.info("no changes detected - no migration written");
return;
}
// there were actually changes to write
Migration dbMigration = diff.getMigration();
File writePath = getWritePath();
logger.info("migration writing version {} to {}", nextMajorVersion, writePath.getAbsolutePath());
writeMigrationXml(dbMigration, writePath, nextMajorVersion);
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(), currentModel.read());
PlatformDdlWriter writer = new PlatformDdlWriter(databasePlatform, serverConfig);
writer.processMigration(dbMigration, write, writePath, nextMajorVersion);
}
writeExtraPlatformDdl(nextMajorVersion, currentModel, dbMigration, writePath);
} finally {
DbOffline.reset();
}
}
/**
* Write any extra platform ddl.
*/
protected void writeExtraPlatformDdl(int nextMajorVersion, CurrentModel currentModel, Migration dbMigration, File writePath) throws IOException {
for (Pair pair : platforms) {
DdlWrite platformBuffer = new DdlWrite(new MConfiguration(), currentModel.read());
PlatformDdlWriter platformWriter = new PlatformDdlWriter(pair.platform, serverConfig, pair.prefix);
platformWriter.processMigration(dbMigration, platformBuffer, writePath, nextMajorVersion);
}
}
/**
* Write the migration xml.
*/
protected void writeMigrationXml(Migration dbMigration, File resourcePath, int migrationVersion) {
File file = new File(resourcePath, "v"+migrationVersion+".0.xml");
MigrationXmlWriter xmlWriter = new MigrationXmlWriter();
xmlWriter.write(dbMigration, file);
}
/**
* Set default server and platform if necessary.
*/
protected void setDefaults() {
if (server == null) {
setServer(Ebean.getDefaultServer());
}
if (databasePlatform == null && platforms.isEmpty()) {
// not explicitly set not set a list of platforms so
// default to the platform of the default server
databasePlatform = server.getDatabasePlatform();
logger.debug("set platform to {}", databasePlatform.getName());
}
}
/**
* Return the file path to write the xml and sql to.
*/
protected File getWritePath() {
// path to src/main/resources in typical maven project
File resourceRootDir = new File(pathToResources);
String resourcePath = migrationConfig.getResourcePath();
// expect to be a path to something like - src/main/resources/dbmigration/myapp
File path = new File(resourceRootDir, resourcePath);
if (!path.exists()) {
if (!path.mkdirs()) {
logger.debug("Unable to ensure migration directory exists at {}", path.getAbsolutePath());
}
}
return path;
}
/**
* Return the DatabasePlatform given the platform key.
*/
protected DatabasePlatform getPlatform(DbPlatformName platform) {
switch (platform) {
case H2:
return new H2Platform();
case POSTGRES:
return new PostgresPlatform();
case MYSQL:
return new MySqlPlatform();
case ORACLE:
return new OraclePlatform();
case SQLSERVER:
return new MsSqlServer2005Platform();
case DB2:
return new DB2Platform();
case SQLITE:
return new SQLitePlatform();
default:
throw new IllegalArgumentException("Platform missing? " + platform);
}
}
/**
* Holds a platform and prefix. Used to generate multiple platform specific DDL
* for a single migration.
*/
public static class Pair {
/**
* The platform to generate the DDL for.
*/
public final DatabasePlatform platform;
/**
* A prefix included into the file/resource names indicating the platform.
*/
public final String prefix;
public Pair(DatabasePlatform platform, String prefix) {
this.platform = platform;
this.prefix = prefix;
}
}
}
@@ -0,0 +1,79 @@
package com.avaje.ebean.dbmigration;
import com.avaje.ebean.config.dbplatform.DbPlatformName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Helper to indicate that an EbeanServer should come up offline
* typically for DDL generation purposes.
*/
public class DbOffline {
private static final Logger logger = LoggerFactory.getLogger(DbOffline.class);
private static final String KEY = "ebean.dboffline";
private static boolean runningMigration;
/**
* Set the platform to use when creating the next EbeanServer instance.
*/
public static void setPlatform(DbPlatformName dbPlatform) {
System.setProperty(KEY, dbPlatform.name());
}
/**
* Set the platform to use when creating the next EbeanServer instance.
*/
public static void setPlatform(String platformName) {
System.setProperty(KEY, platformName);
}
/**
* Return the platform to use when creating the next EbeanServer instance.
*/
public static String getPlatform() {
return System.getProperty(KEY);
}
/**
* Bring up the next EbeanServer instance using the H2 platform.
*/
public static void asH2() {
setPlatform(DbPlatformName.H2);
}
/**
* Return true if the offline platform has been set.
*/
public static boolean isSet() {
return getPlatform() != null;
}
/**
* 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;
}
/**
* 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;
}
/**
* Reset the offline platform and runningMigration flag.
*/
public static void reset() {
runningMigration = false;
System.clearProperty(KEY);
logger.debug("reset");
}
}
@@ -1,5 +1,14 @@
package com.avaje.ebeaninternal.server.ddl;
package com.avaje.ebean.dbmigration;
import com.avaje.ebean.Transaction;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.dbmigration.model.CurrentModel;
import com.avaje.ebeaninternal.api.SpiEbeanPlugin;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
@@ -13,18 +22,6 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.PersistenceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.Transaction;
import com.avaje.ebean.config.NamingConvention;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebeaninternal.api.SpiEbeanPlugin;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
/**
* Controls the generation of DDL and potentially runs the resulting scripts.
*/
@@ -34,24 +31,17 @@ public class DdlGenerator implements SpiEbeanPlugin {
private SpiEbeanServer server;
private DatabasePlatform dbPlatform;
private int summaryLength = 80;
private boolean generateDdl;
private boolean runDdl;
private CurrentModel currentModel;
private String dropContent;
private String createContent;
private NamingConvention namingConvention;
public void setup(SpiEbeanServer server, DatabasePlatform dbPlatform, ServerConfig serverConfig) {
public void setup(SpiEbeanServer server, ServerConfig serverConfig) {
this.server = server;
this.dbPlatform = dbPlatform;
this.generateDdl = serverConfig.isDdlGenerate();
this.runDdl = serverConfig.isDdlRun();
this.namingConvention = serverConfig.getNamingConvention();
}
/**
@@ -103,10 +93,8 @@ public class DdlGenerator implements SpiEbeanPlugin {
try {
String c = generateDropDdl();
writeFile(dropFile, c);
} catch (IOException e) {
String msg = "Error generating Drop DDL";
throw new PersistenceException(msg, e);
throw new PersistenceException("Error generating Drop DDL", e);
}
}
@@ -115,65 +103,44 @@ public class DdlGenerator implements SpiEbeanPlugin {
try {
String c = generateCreateDdl();
writeFile(createFile, c);
} catch (IOException e) {
String msg = "Error generating Create DDL";
throw new PersistenceException(msg, e);
throw new PersistenceException("Error generating Create DDL", e);
}
}
public String generateDropDdl() {
DdlGenContext ctx = createContext();
if (ctx.getDdlSyntax().isDropKeyConstraints()) {
// generate drop foreign key constraint statements (sql server joy)
AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(false, ctx);
VisitorUtil.visit(server, fkeys);
ctx.writeNewLine();
try {
dropContent = currentModel().getDropDdl();
return dropContent;
} catch (IOException e) {
throw new RuntimeException(e);
}
DropTableVisitor drop = new DropTableVisitor(ctx);
VisitorUtil.visit(server, drop);
DropSequenceVisitor dropSequence = new DropSequenceVisitor(ctx);
VisitorUtil.visit(server, dropSequence);
ctx.flush();
dropContent = ctx.getContent();
return dropContent;
}
public String generateCreateDdl() {
DdlGenContext ctx = createContext();
CreateTableVisitor create = new CreateTableVisitor(ctx);
VisitorUtil.visit(server, create);
CreateSequenceVisitor createSequence = new CreateSequenceVisitor(ctx);
VisitorUtil.visit(server, createSequence);
AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(true, ctx);
VisitorUtil.visit(server, fkeys);
CreateIndexVisitor indexes = new CreateIndexVisitor(ctx);
VisitorUtil.visit(server, indexes);
ctx.flush();
createContent = ctx.getContent();
return createContent;
try {
createContent = currentModel().getCreateDdl();
return createContent;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
protected String getDropFileName() {
return server.getName() + "-drop.sql";
return server.getName() + "-drop-all.sql";
}
protected String getCreateFileName() {
return server.getName() + "-create.sql";
return server.getName() + "-create-all.sql";
}
protected DdlGenContext createContext() {
return new DdlGenContext(dbPlatform, namingConvention);
protected CurrentModel currentModel() {
if (currentModel == null) {
currentModel = new CurrentModel(server);
}
return currentModel;
}
protected void writeFile(String fileName, String fileContent) throws IOException {
@@ -201,7 +168,7 @@ public class DdlGenerator implements SpiEbeanPlugin {
FileReader fr = new FileReader(f);
LineNumberReader lr = new LineNumberReader(fr);
try {
String s = null;
String s;
while ((s = lr.readLine()) != null) {
buf.append(s).append("\n");
}
@@ -233,8 +200,7 @@ public class DdlGenerator implements SpiEbeanPlugin {
t.commit();
} catch (Exception e) {
String msg = "Error: " + e.getMessage();
throw new PersistenceException(msg, e);
throw new PersistenceException("Error: " + e.getMessage(), e);
} finally {
t.end();
}
@@ -274,7 +240,7 @@ public class DdlGenerator implements SpiEbeanPlugin {
stmt = stmt.substring(0, stmt.length() - 1);
}
logger.trace("executing " + oneOf + " " + getSummary(stmt));
logger.info("executing " + oneOf + " " + getSummary(stmt));
pstmt = c.prepareStatement(stmt);
pstmt.execute();
@@ -297,6 +263,74 @@ public class DdlGenerator implements SpiEbeanPlugin {
}
}
/**
* Local utility used to detect the end of statements / separate statements.
* This is often just the semicolon character but for trigger/procedures this
* detects the $$ demarcation used in the history DDL generation for MySql and
* Postgres.
*/
static class StatementsSeparator {
ArrayList<String> statements = new ArrayList<String>();
boolean trimDelimiter;
boolean inDbProcedure;
StringBuilder sb = new StringBuilder();
void lineContainsDollars(String line) {
if (inDbProcedure) {
if (trimDelimiter) {
line = line.replace("$$","");
}
endOfStatement(line);
} else {
// MySql style delimiter needs to be trimmed/removed
trimDelimiter = line.equals("delimiter $$");
if (!trimDelimiter) {
sb.append(line).append(" ");
}
}
inDbProcedure = !inDbProcedure;
}
void endOfStatement(String line) {
// end of Db procedure
sb.append(line);
statements.add(sb.toString().trim());
sb = new StringBuilder();
}
void nextLine(String line) {
if (line.contains("$$")) {
lineContainsDollars(line);
return;
}
if (inDbProcedure) {
sb.append(line).append(" ");
return;
}
int semiPos = line.indexOf(';');
if (semiPos == -1) {
sb.append(line).append(" ");
} else if (semiPos == line.length() - 1) {
// semicolon at end of line
endOfStatement(line);
} else {
// semicolon in middle of line
String preSemi = line.substring(0, semiPos);
endOfStatement(preSemi);
sb.append(line.substring(semiPos + 1));
}
}
}
/**
* Break up the sql in reader into a list of statements using the semi-colon
* character;
@@ -305,43 +339,24 @@ public class DdlGenerator implements SpiEbeanPlugin {
try {
BufferedReader br = new BufferedReader(reader);
StatementsSeparator statements = new StatementsSeparator();
ArrayList<String> statements = new ArrayList<String>();
StringBuilder sb = new StringBuilder();
String s;
while ((s = br.readLine()) != null) {
s = s.trim();
int semiPos = s.indexOf(';');
if (semiPos == -1) {
sb.append(s).append(" ");
} else if (semiPos == s.length() - 1) {
// semicolon at end of line
sb.append(s);
statements.add(sb.toString().trim());
sb = new StringBuilder();
} else {
// semicolon in middle of line
String preSemi = s.substring(0, semiPos);
sb.append(preSemi);
statements.add(sb.toString().trim());
sb = new StringBuilder();
sb.append(s.substring(semiPos + 1));
}
statements.nextLine(s);
}
return statements;
return statements.statements;
} catch (IOException e) {
throw new PersistenceException(e);
}
}
private String getSummary(String s) {
if (s.length() > summaryLength) {
return s.substring(0, summaryLength).trim() + "...";
if (s.length() > 80) {
return s.substring(0, 80).trim() + "...";
}
return s;
}
@@ -0,0 +1,108 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.BaseTableDdl;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
import com.avaje.ebean.dbmigration.migration.AddColumn;
import com.avaje.ebean.dbmigration.migration.AddHistoryTable;
import com.avaje.ebean.dbmigration.migration.AlterColumn;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.migration.CreateIndex;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import com.avaje.ebean.dbmigration.migration.DropHistoryTable;
import com.avaje.ebean.dbmigration.migration.DropIndex;
import com.avaje.ebean.dbmigration.migration.DropTable;
import java.io.IOException;
import java.util.List;
/**
*
*/
public class BaseDdlHandler implements DdlHandler {
protected final TableDdl tableDdl;
public BaseDdlHandler(ServerConfig serverConfig, PlatformDdl platformDdl) {
this.tableDdl = new BaseTableDdl(serverConfig, platformDdl);
}
@Override
public void generate(DdlWrite writer, ChangeSet changeSet) throws IOException {
List<Object> changeSetChildren = changeSet.getChangeSetChildren();
for (Object change : changeSetChildren) {
if (change instanceof CreateTable) {
generate(writer, (CreateTable) change);
} else if (change instanceof DropTable) {
generate(writer, (DropTable) change);
} else if (change instanceof CreateIndex) {
generate(writer, (CreateIndex) change);
} else if (change instanceof DropIndex) {
generate(writer, (DropIndex) change);
} else if (change instanceof AddColumn) {
generate(writer, (AddColumn) change);
} else if (change instanceof DropColumn) {
generate(writer, (DropColumn) change);
} else if (change instanceof AlterColumn) {
generate(writer, (AlterColumn) change);
} else if (change instanceof AddHistoryTable) {
generate(writer, (AddHistoryTable) change);
} else if (change instanceof DropHistoryTable) {
generate(writer, (DropHistoryTable) change);
}
}
}
@Override
public void generateExtra(DdlWrite write) throws IOException {
tableDdl.generateExtra(write);
}
@Override
public void generate(DdlWrite writer, CreateTable createTable) throws IOException {
tableDdl.generate(writer, createTable);
}
@Override
public void generate(DdlWrite writer, DropTable dropTable) throws IOException {
tableDdl.generate(writer, dropTable);
}
@Override
public void generate(DdlWrite writer, AddColumn addColumn) throws IOException {
tableDdl.generate(writer, addColumn);
}
@Override
public void generate(DdlWrite writer, DropColumn dropColumn) throws IOException {
tableDdl.generate(writer, dropColumn);
}
@Override
public void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException {
tableDdl.generate(writer, alterColumn);
}
@Override
public void generate(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException {
tableDdl.generate(writer, addHistoryTable);
}
@Override
public void generate(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException {
tableDdl.generate(writer, dropHistoryTable);
}
@Override
public void generate(DdlWrite writer, CreateIndex createIndex) throws IOException {
tableDdl.generate(writer, createIndex);
}
@Override
public void generate(DdlWrite writer, DropIndex dropIndex) throws IOException {
tableDdl.generate(writer, dropIndex);
}
}
@@ -0,0 +1,28 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.dbmigration.migration.AddColumn;
import com.avaje.ebean.dbmigration.migration.AlterColumn;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import java.io.IOException;
/**
* Write DDL for AddColumn , DropColumn or AlterColumn.
*/
public interface ColumnDdl {
/**
* Write the add column change.
*/
void generate(DdlWrite writer, AddColumn addColumn) throws IOException;
/**
* Write the drop column change.
*/
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
/**
* Write the alter column changes.
*/
void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException;
}
@@ -0,0 +1,57 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.dbmigration.model.MConfiguration;
import java.io.IOException;
/**
* Buffer to append generated DDL to.
*/
public interface DdlBuffer {
/**
* Return the configuration (default tablespaces etc).
*/
MConfiguration getConfiguration();
/**
* Return true if the buffer is empty.
*/
boolean isEmpty();
/**
* Append DDL content to the buffer.
*/
DdlBuffer append(String content) throws IOException;
/**
* Append DDL content to the buffer with space padding.
*/
DdlBuffer append(String type, int space) throws IOException;
/**
* Append a value that is potentially null or empty and proceed it with a space if so.
*/
DdlBuffer appendWithSpace(String foreignKeyRestrict) throws IOException;
/**
* Append new line character to the buffer.
*/
DdlBuffer newLine() throws IOException;
/**
* Append the end of statement content.
*/
DdlBuffer endOfStatement() throws IOException;
/**
* End of a change - add some whitespace.
*/
DdlBuffer end() throws IOException;
/**
* Return the buffer content.
*/
String getBuffer();
}
@@ -0,0 +1,41 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.dbmigration.migration.AddColumn;
import com.avaje.ebean.dbmigration.migration.AddHistoryTable;
import com.avaje.ebean.dbmigration.migration.AlterColumn;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.migration.CreateIndex;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import com.avaje.ebean.dbmigration.migration.DropHistoryTable;
import com.avaje.ebean.dbmigration.migration.DropIndex;
import com.avaje.ebean.dbmigration.migration.DropTable;
import java.io.IOException;
/**
*/
public interface DdlHandler {
void generate(DdlWrite writer, ChangeSet changeSet) throws IOException;
void generate(DdlWrite writer, CreateTable createTable) throws IOException;
void generate(DdlWrite writer, DropTable dropTable) throws IOException;
void generate(DdlWrite writer, AddColumn addColumn) throws IOException;
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException;
void generate(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException;
void generate(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException;
void generate(DdlWrite writer, CreateIndex createIndex) throws IOException;
void generate(DdlWrite writer, DropIndex dropIndex) throws IOException;
void generateExtra(DdlWrite write) throws IOException;
}
@@ -0,0 +1,160 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.BaseDdlBuffer;
import com.avaje.ebean.dbmigration.model.MConfiguration;
import com.avaje.ebean.dbmigration.model.MTable;
import com.avaje.ebean.dbmigration.model.ModelContainer;
/**
* Write context holding the buffers for both apply and rollback DDL.
*/
public class DdlWrite {
private final ModelContainer currentModel;
private final DdlBuffer apply;
private final DdlBuffer applyForeignKeys;
private final DdlBuffer applyHistory;
private final DdlBuffer rollbackForeignKeys;
private final DdlBuffer rollback;
/**
* For DDL that drops tables and columns etc.
*
* This DDL typically can not run automatically in production as there is most commonly
* existing servers running the application using these tables and columns. Typically
* these drop statements may be executed AFTER all the servers in the application have
* migrated onto new code.
*/
private final DdlBuffer drop;
/**
* For use when History is turned off for a base table or history is no longer
* desired on specific columns. This DDL should typically execute manually after review
* by DBA's.
*/
private final DdlBuffer dropHistory;
/**
* Create without any configuration or current model (no history support).
*/
public DdlWrite() {
this(new MConfiguration(), new ModelContainer());
}
/**
* Create with a configuration.
*/
public DdlWrite(MConfiguration configuration, ModelContainer currentModel) {
this.currentModel = currentModel;
this.apply = new BaseDdlBuffer(configuration);
this.applyForeignKeys = new BaseDdlBuffer(configuration);
this.applyHistory = new BaseDdlBuffer(configuration);
this.rollbackForeignKeys = new BaseDdlBuffer(configuration);
this.rollback = new BaseDdlBuffer(configuration);
this.drop = new BaseDdlBuffer(configuration);
this.dropHistory = new BaseDdlBuffer(configuration);
}
/**
* Return the Table information from the current model.
* <p>
* This is typically required for the history support (used to determine the list of columns
* included in the history when creating or recreating the associated trigger/stored procedure).
* </p>
*/
public MTable getTable(String tableName) {
return currentModel.getTable(tableName);
}
/**
* Return true if the apply buffers are all empty.
*/
public boolean isApplyEmpty() {
return apply.getBuffer().isEmpty()
&& applyForeignKeys.getBuffer().isEmpty()
&& applyHistory.getBuffer().isEmpty();
}
/**
* Return true if the apply rollback buffers are all empty.
*/
public boolean isApplyRollbackEmpty() {
return rollback.getBuffer().isEmpty()
&& rollbackForeignKeys.getBuffer().isEmpty();
}
/**
* Return true the drop buffers are empty.
*/
public boolean isDropEmpty() {
return drop.getBuffer().isEmpty() && dropHistory.getBuffer().isEmpty();
}
/**
* Return the buffer that APPLY DDL is written to.
*/
public DdlBuffer apply() {
return apply;
}
/**
* Return the buffer that APPLY DDL is written to for foreign keys and their associated indexes.
* <p>
* Statements added to this buffer are executed after all the normal apply statements and
* typically 'add foreign key' is added to this buffer.
*/
public DdlBuffer applyForeignKeys() {
return applyForeignKeys;
}
/**
* Return the buffer that apply history DDL is written to.
*/
public DdlBuffer applyHistory() {
return applyHistory;
}
/**
* Return the buffer that ROLLBACK DDL is written to for foreign keys and associated indexes.
*/
public DdlBuffer rollbackForeignKeys() {
return rollbackForeignKeys;
}
/**
* Return the buffer that ROLLBACK DDL is written to which is considered safe to run when
* apply changes fail to execute. This will reverse the apply changes typically dropping
* newly created tables, foreign keys etc.
* <p>
* When apply changes are made against DB's that support transactional DDL you could argue
* that these rollback statements are not necessary.
* <p>
* Note that statements added to this rollback buffer are executed after foreign key rollback
* has been executed.
*/
public DdlBuffer rollback() {
return rollback;
}
/**
* Return the buffer that destructive changes are written to. This is typically drop table and
* drop column.
*/
public DdlBuffer drop() {
return drop;
}
/**
* Return the buffer that is used when history is no longer required on a table or specific columns.
*/
public DdlBuffer dropHistory() {
return dropHistory;
}
}

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