Compare commits

...
Author SHA1 Message Date
Robin Bygrave a70e289b00 [maven-release-plugin] prepare release avaje-ebeanorm-6.16.2 2016-01-28 08:36:18 +13:00
Robin Bygrave 4ad0e06aab Testing CI - TestEncrypt change to only run against H2 for now 2016-01-27 22:53:06 +13:00
Robin Bygrave 86de7e845e Testing CI - add sql logging for TestEncrypt run on CI server 2016-01-27 22:39:03 +13:00
Robin Bygrave 38501ca372 Modify .travis.yml - add postgres pgcrypto extension 2016-01-27 22:15:39 +13:00
Robin Bygrave 4790c83fa1 Modify .travis.yml - cache .m2 directory 2016-01-27 21:56:00 +13:00
Robin Bygrave b410c83492 Modify .travis.yml for postgres - add hstore and postgis extensions 2016-01-27 21:50:43 +13:00
Robin Bygrave b19145f16f Modify .travis.yml for postgres - add hstore and postgis extensions 2016-01-27 21:46:30 +13:00
Robin Bygrave c28cff2f40 Modify .travis.yml for h2 and postgres runs using EBEAN_DB environment variable 2016-01-27 21:37:57 +13:00
Robin Bygrave 0c8cf78ecc Modify .travis.yml for h2 and postgres runs using EBEAN_DB environment variable 2016-01-27 21:21:01 +13:00
Robin Bygrave df112815ff #545 - ENH: Read environment variable "EBEAN_DB" to set default datasource - typically for CI builds 2016-01-27 21:20:13 +13:00
Robin Bygrave 85522ed8bc Modify .travis.yml for h2 and postgres runs 2016-01-27 20:39:53 +13:00
Robin Bygrave cf88f2375b #544 - Postgres @History DB trigger using current_timestamp (transaction) and should instead use statement_timestamp() 2016-01-27 20:34:51 +13:00
Robin Bygrave 24151f11fd #543 - Tidy up test logging - adjust test LoggedSqlCollector - remove logging noise when running tests 2016-01-27 20:12:36 +13:00
Robin Bygrave 424a83fa0a #543 - Tidy up test logging - adjust test LoggedSqlCollector - remove logging noise when running tests 2016-01-27 19:10:52 +13:00
Robin Bygrave 53dd91416c #543 - Tidy up test logging - adjust test LoggedSqlCollector - remove logging noise when running tests 2016-01-27 19:05:19 +13:00
Robin Bygrave 5a463c5071 #543 - Tidy up test logging - adjust test LoggedSqlCollector - remove trace level logging when running tests 2016-01-27 18:25:54 +13:00
Robin Bygrave bc3cf1348a #543 - Tidy up test logging - adjust test LoggedSqlCollector 2016-01-27 18:25:16 +13:00
Robin Bygrave f3b1024283 Fix for test asserts to run against Postgres with escape clause on LIKE expression 2016-01-27 17:22:55 +13:00
Robin Bygrave 7ba35d7a62 Update .travis - postgres service 2016-01-27 16:17:45 +13:00
Robin Bygrave 990ca2980b Add initial .travis.yml 2016-01-27 16:05:33 +13:00
Robin Bygrave 38dd3d82fc #536 - @ManyToOne with @JoinColumn throw error - Update tests 2016-01-26 16:41:15 +13:00
Robin Bygrave 6be26aaff2 #537 - Change PersistenceException: Mapping limitation on @JoinColumn such that it includes the bean type 2016-01-26 15:30:57 +13:00
Robin Bygrave d1462b032a #535 - Bean lazy loading can execute an extra query when one of the lazy loaded beans has been deleted 2016-01-21 20:51:45 +13:00
Robin Bygrave 6ab974a330 #535 - Bean lazy loading can execute an extra query when one of the lazy loaded beans has been deleted 2016-01-21 20:51:32 +13:00
Robin Bygrave 64618da6a7 #534 - REFACTOR: Internals for lazy loading specifically improving errors/logging in cases of lazy load errors due to deletes - Update debug logging for LoadManyRequest when empty collection found (expected frequently) 2016-01-21 17:52:23 +13:00
Robin Bygrave d242ff7351 #534 - REFACTOR: Internals for lazy loading specifically improving errors/logging in cases of lazy load errors due to deletes - Initial refactor for LoadManyRequest 2016-01-21 17:30:49 +13:00
Robin Bygrave 7d54aaa9a7 #534 - REFACTOR: Internals for lazy loading specifically improving errors/logging in cases of lazy load errors due to deletes - Initial refactor 2016-01-21 16:50:51 +13:00
Robin Bygrave 0e46184656 No effective change - Rename test class 2016-01-21 16:03:51 +13:00
Robin Bygrave c9e1a6edbd Bump agent to 4.9.1 2016-01-20 15:13:11 +13:00
Robin Bygrave 3c0cffd146 [maven-release-plugin] prepare for next development iteration 2016-01-19 19:49:31 +13:00
Robin Bygrave d31547fb69 [maven-release-plugin] prepare release avaje-ebeanorm-6.16.1 2016-01-19 19:49:08 +13:00
Robin Bygrave 93adaa12bc Bump pom to 6.16.1-SNAPSHOT 2016-01-19 19:48:22 +13:00
Robin Bygrave d1cdbe94de #529 - @OneToOne with @JoinColumn to non primary key throws Data conversion error 2016-01-19 19:46:41 +13:00
Robin Bygrave e7c6223799 #530 - Bad join with raw() expression on a @ManyToMany path. 2016-01-19 13:18:28 +13:00
Robin Bygrave d33afd85de #533 - DDL - Invalid foreign key constraint name for @ManyToMany when using explicit schema in @Table - Temp testing removed 2016-01-19 10:01:04 +13:00
Robin Bygrave 77bcb4aef9 #533 - DDL - Invalid foreign key constraint name for @ManyToMany when using explicit schema in @Table - Temp testing 2016-01-19 09:57:49 +13:00
Robin Bygrave a70fe184c2 #533 - DDL - Invalid foreign key constraint name for @ManyToMany when using explicit schema in @Table - Fix 2016-01-19 09:56:27 +13:00
Robin Bygrave 7238f39be5 #531 - AutoTune - On shutdown provide ability to saving profiling without garbage collection 2016-01-19 08:16:17 +13:00
Robin Bygrave ae44b59c5f #532 - Change example expression such that it supports nested beans 2016-01-18 23:52:28 +13:00
Robin Bygrave ced4e71307 [maven-release-plugin] prepare for next development iteration 2016-01-13 16:13:59 +13:00
Robin Bygrave 9cb43bd5dd [maven-release-plugin] prepare release avaje-ebeanorm-6.15.2 2016-01-13 16:13:30 +13:00
Robin Bygrave 9665de2dbe #502 - jsonContext.toJson(o, generator, path) can not apply path on @Transient field that is an entity bean 2016-01-13 13:29:06 +13:00
Robin Bygrave e2666f0c4c No effective change - turn off autotune profiling/tuning flags for test running 2016-01-13 12:38:04 +13:00
Robin Bygrave 89c83c90d1 No effective change - add test to show findRowCount with joins 2016-01-13 12:35:52 +13:00
Robin Bygrave cdd25351a6 No effective change - test code static imports 2016-01-13 11:40:23 +13:00
Robin Bygrave 17e0413837 No effective change - code format 2016-01-13 11:38:53 +13:00
Robin Bygrave b04419d9c7 #527 - @OrderBy on child-of-child property 2016-01-13 11:37:38 +13:00
Robin Bygrave 0453892ebd #526 - findPagedList with @EmbeddedId broken - automatically adds orderby t0.null 2016-01-13 10:43:56 +13:00
Robin Bygrave 55493c5b7d #524 - ExplicitJdbcTransaction leaves dangling “begin” - comment update 2016-01-13 00:17:22 +13:00
Robin Bygrave eb2f7cd852 #525 - Automatic autotune data 2016-01-13 00:08:00 +13:00
Robin Bygrave f44eb234c8 #525 - Automatic autotune data - initial wip 2016-01-12 11:45:24 +13:00
Robin Bygrave 404b57ab21 #524 - ExplicitJdbcTransaction leaves dangling “begin” - expected fix 2016-01-12 08:37:12 +13:00
Robin Bygrave a54f09ca4b #524 - ExplicitJdbcTransaction leaves dangling “begin” - expected fix 2016-01-11 14:04:14 +13:00
Robin Bygrave a3bb909308 [maven-release-plugin] prepare for next development iteration 2016-01-08 00:22:06 +13:00
Robin Bygrave 7eb443859e [maven-release-plugin] prepare release avaje-ebeanorm-6.15.1 2016-01-08 00:21:44 +13:00
Robin Bygrave 8b39788ae3 Bump pom to 6.15.1-SNAPSHOT 2016-01-08 00:20:27 +13:00
Robin Bygrave 1ec132b7dd #508 - Upgrading to 6.13.5 causes "No suitable driver found for jdbc:mysql" error 2016-01-08 00:18:20 +13:00
Robin Bygrave 343a975073 #520 - SPI - Deprecate SpiEbeanPlugin in favor of SpiServerPlugin. - Deprecate SpiEbeanPlugin 2016-01-07 23:24:57 +13:00
Robin Bygrave 944f7bd086 #520 - SPI - Deprecate SpiEbeanPlugin in favor of SpiServerPlugin. - Add ServiceLoading for SpiServerPlugin 2016-01-07 16:45:24 +13:00
Robin Bygrave 3639c2a540 #518 - Refactor: Remove getDdlGenerator() from SpiEbeanServer. 2016-01-07 14:27:27 +13:00
Robin Bygrave a9cc8ed702 #517 - Refactor DdlGenerator such that it is not an SpiEbeanPlugin 2016-01-07 14:22:37 +13:00
Robin Bygrave 0351a15067 #516 - DdlParser for seed and init sql is not ignoring sql comment lines (starting with --) 2016-01-07 14:03:17 +13:00
Robin Bygrave c7300a1707 #246 - ENH: Add ebean.ddl.initsql=.... to support executing a sql script prior to running the create all DDL - was - When the scripts generates the evolution, it should generate the create schema too. 2016-01-07 13:12:43 +13:00
Robin Bygrave c48008c4b2 #515 - ENH: Add ebean.ddl.seedSql=xxx.sql ... such that a sql script will execute to insert seed data typically for testing 2016-01-07 12:48:55 +13:00
Robin Bygrave e5d8804591 #514 - ENH: Add ebean.ddl.createOnly=true ... such that all the drop table statements are skipped (for running tests against H2 usually) 2016-01-07 10:06:35 +13:00
Robin Bygrave f6dc294bc2 No effective change - update public project url in pom 2016-01-05 21:38:25 +13:00
Robin Bygrave 692baf8bb6 [maven-release-plugin] prepare for next development iteration 2016-01-05 21:28:03 +13:00
Robin Bygrave e1c00f3856 [maven-release-plugin] prepare release avaje-ebeanorm-6.14.1 2016-01-05 21:27:41 +13:00
Robin Bygrave cf173d0695 Bump pom to 6.14.1-SNAPSHOT 2016-01-05 21:26:20 +13:00
Robin Bygrave a3798c6ca3 #506 - Changes to DB Migration, support run on startup and external version numbering - suffix/subdirectory refactor 2016-01-05 21:25:07 +13:00
Robin Bygrave 7bcf1da823 #506 - Changes to DB Migration, support run on startup and external version numbering - suffix/subdirectory refactor 2016-01-05 21:21:16 +13:00
Rob Bygrave 2ccd8dabeb Merge pull request #510 from apuckey/master
Added support for custom database functions that have multiple arguments
2016-01-05 10:25:19 +13:00
Robin Bygrave f9800dd59e #509 - ExpressList.notIn method does not work 2016-01-05 09:11:14 +13:00
Robin Bygrave fb3e8b9fc4 #511 - PagedList getTotalRowCount() includes soft deleted rows in its count 2016-01-05 07:37:17 +13:00
Antony Puckey 18be5989c7 Added support for custom database functions that have multiple arguments
seperated by commas inside brackets.
2015-12-29 11:06:22 +10:00
Robin Bygrave be91e3f3f7 #506 - Changes to DB Migration, support run on startup and external version numbering 2015-12-24 16:41:06 +13:00
Robin Bygrave 03a9aa3dec #507 - PropertiesWrapper support null enum values with getEnum() 2015-12-24 15:23:25 +13:00
Robin Bygrave a2a301beda No effective change - remove commented out lines 2015-12-23 09:13:31 +13:00
Robin Bygrave 695e4f653b No effective change - typo in comment 2015-12-23 07:38:58 +13:00
Robin Bygrave e84c75929c #505 - Remove unused method - EntityBean._ebean_createCopy(); 2015-12-22 17:04:51 +13:00
Robin Bygrave 7592178b6b No effective change - update tests to ensure query does not hit L2 cache 2015-12-22 17:02:35 +13:00
Robin Bygrave 70d65b734f #504 - @Draft treated as transient such that it doesn't invoke lazy loading in 4.8.1 enhancement agent 2015-12-22 16:48:42 +13:00
Robin Bygrave f9a3dfeda0 #503 - @DraftDirty should be marked as not null automatically 2015-12-22 07:52:05 +13:00
Robin Bygrave eb85931fe2 #500 - Change raw(String, Object[]) expression to varargs raw(String, Object...) 2015-12-16 08:11:32 +13:00
Robin Bygrave 1745334737 No effective change - add extra test 2015-12-16 08:06:12 +13:00
Robin Bygrave ea92ddfd89 [maven-release-plugin] prepare for next development iteration 2015-12-15 15:46:21 +13:00
Robin Bygrave 3400928798 [maven-release-plugin] prepare release avaje-ebeanorm-6.13.5 2015-12-15 15:45:55 +13:00
Robin Bygrave 4e665fd66f #499 - DDL issue for entity bean that is both @Draftable with @History - draft only columns included in history table 2015-12-15 15:44:22 +13:00
Robin Bygrave 09cd2c12e2 Add tests for @Draftable from example application 2015-12-15 15:25:19 +13:00
Robin Bygrave e3e45929f0 #498 - @Draftable - lazy loading after stateless update results in - EntityNotFoundException: Bean not found during lazy load or refresh 2015-12-15 15:15:20 +13:00
Robin Bygrave 2caeafaaa2 #498 - @Draftable - lazy loading after stateless update results in - EntityNotFoundException: Bean not found during lazy load or refresh 2015-12-15 14:38:39 +13:00
Robin Bygrave 5cd21de174 #496 - @EnumValue is being trimmed, may result in unexpected behaviour with CHAR columns for some database systems 2015-12-14 17:21:01 +13:00
Robin Bygrave 78df595861 [maven-release-plugin] prepare for next development iteration 2015-12-11 10:28:21 +13:00
Robin Bygrave 3c89a0537f [maven-release-plugin] prepare release avaje-ebeanorm-6.13.4 2015-12-11 10:28:01 +13:00
Robin Bygrave 282463c2e8 #247 - @AttributeOverride at class level not read - was: @AttributeOverride annotation does not seem to work (Play 2.2.0 - ebean 3.2.2) 2015-12-11 10:23:34 +13:00
Robin Bygrave 03bb7a4aaf #494 - ENH: Support findPagingList() ... that uses firstRow & maxRows (rather than pageIndex, pageSize) 2015-12-11 10:20:53 +13:00
Robin Bygrave e4fa031cd3 #494 - ENH: Support findPagingList() ... that uses firstRow & maxRows (rather than pageIndex, pageSize) 2015-12-10 14:52:27 +13:00
Robin Bygrave 00d227c598 #491 - RawSqlParser doesn't seem to understand new lines directly after the SELECT keyword 2015-12-09 17:24:58 +13:00
Robin Bygrave fb86cb91bc #492 - MS Sql Server DDL - Fix for drop constraint syntax (remove extra IF EXISTS) and ignore table and column comments 2015-12-09 16:59:51 +13:00
Robin Bygrave f11ee20b73 #365 - ENH: Add @DbComment with DDL generation of table and column comments 2015-12-09 16:56:29 +13:00
Robin Bygrave 3665c5bfaf No effective change - adjust test connection properties for sql server 2015-12-09 16:53:26 +13:00
Robin Bygrave 638446680c #365 - ENH: Add @DbComment with DDL generation of table and column comments 2015-12-09 16:52:58 +13:00
Robin Bygrave bd9bfa25be No effective change - rename test property from 'top' as that is ms sql server keyword 2015-12-09 16:49:35 +13:00
Robin Bygrave 753d17a8d2 [maven-release-plugin] prepare for next development iteration 2015-12-09 12:46:40 +13:00
Robin Bygrave f5cfce3f44 [maven-release-plugin] prepare release avaje-ebeanorm-6.13.3 2015-12-09 12:46:18 +13:00
Robin Bygrave 1c6363e85c #490 - Invalid SQL for generating ID from sequence on DB2 2015-12-09 12:44:27 +13:00
Robin Bygrave b8bcbd8af9 #489 - @Draftable - insert does not set 'draft' to true ... so subsequent update fails 2015-12-09 11:06:48 +13:00
Robin Bygrave d70768277b #488 - BeanPropertyAssocManyJsonHelp error when Jackson not in classPath 2015-12-09 11:00:21 +13:00
Robin Bygrave b39b4a2e8c #487 - DDL - @SoftDelete deleted column should have NOT NULL constraint in create table DDL 2015-12-09 10:27:04 +13:00
Robin Bygrave 93b2f4035c #485 - @SoftDelete with join to nullable relation (optional @ManyToOne for example) ... will incorrectly filter out row from result when FK value is null. 2015-12-09 10:12:25 +13:00
Robin Bygrave 31ee0c4582 #486 - Postgres DDL - Add "if exists" to alter table [if exists] drop constraint if exists .... 2015-12-09 10:06:03 +13:00
Robin Bygrave 6c2dad4851 [maven-release-plugin] prepare for next development iteration 2015-12-07 22:20:54 +13:00
Robin Bygrave ed190ede03 [maven-release-plugin] prepare release avaje-ebeanorm-6.13.2 2015-12-07 22:20:25 +13:00
Robin Bygrave f252b80c2d #476 - ENH: Enable ServiceConfig to use alternate ClassLoader - was ServiceConfig add setClassloader api --- part 3: Refactor with ClassLoadConfig 2015-12-07 22:13:27 +13:00
Robin Bygrave 2859ea657e #484 - JDBC4+ drivers do not need Class.forName() registration - removing that call 2015-12-07 21:02:00 +13:00
Robin Bygrave 664b1cbd75 #476 - ENH: Enable ServiceConfig to use alternate ClassLoader - was ServiceConfig add setClassloader api --- part 2 : Use current context classLoader 2015-12-07 17:41:56 +13:00
Robin Bygrave 8bc283fef4 #476 - ENH: Enable ServiceConfig to use alternate ClassLoader - was ServiceConfig add setClassloader api --- part 1 : protected methods 2015-12-07 17:37:59 +13:00
Robin Bygrave 7d85398139 #483 - ENH: Draftable - Add FK from live table back to draft table (for top level @Draftable tables) 2015-12-07 15:21:22 +13:00
Robin Bygrave f42be3d65a #482 - ENH: @Draftable - Save or update is not allowed on a 'live' bean - only draft beans ... add this check when @Draft property is used 2015-12-07 12:09:10 +13:00
Robin Bygrave ff8e5af4e5 #481 - ENH: @Draftable ... add support for transient @Draft boolean draft; property ... used to distinguish a 'live' instance from a 'draft' instance. 2015-12-07 11:11:22 +13:00
Robin Bygrave 526d67eeb4 No effective change - whitespace 2015-12-07 11:02:32 +13:00
Robin Bygrave 374fc8d702 #480 - @History trigger on @Draftable does not exclude the @DraftOnly and @DraftDirty properties - ERROR: column "dirty" of relation "link_history" does not exist Where: PL/pgSQL function link_history_version() 2015-12-07 09:44:34 +13:00
Robin Bygrave 9c6c59afab #479 - Insert of @Draftable with getGeneratedKeys ... PersistenceException executing insert 2015-12-07 09:21:26 +13:00
Robin Bygrave c3eae0d3a5 #477 - findUnique() should throw NonUniqueResultException and not PersistenceException 2015-12-04 11:12:45 +13:00
Robin Bygrave 25ec73364e [maven-release-plugin] prepare for next development iteration 2015-12-03 21:41:41 +13:00
Robin Bygrave c7818e7f23 [maven-release-plugin] prepare release avaje-ebeanorm-6.13.1 2015-12-03 21:41:20 +13:00
Robin Bygrave 8318bbc4ca #118 - Additional: Add query includeSoftDeletes() asDraft() to ExpressionList (for fluid style when added after predicates) 2015-12-03 17:42:26 +13:00
Robin Bygrave 337646a6ce No effective change - javadoc update 2015-12-03 16:47:19 +13:00
Robin Bygrave fa6ee93e5b Bump pom to 6.13.1-SNAPSHOT 2015-12-03 16:35:43 +13:00
Robin Bygrave 0fe691112f Merge branch 'softDelete1' into softDelete2 2015-12-03 00:33:47 +13:00
Robin Bygrave 6946ff07e0 [maven-release-plugin] prepare for next development iteration 2015-12-02 23:48:15 +13:00
Robin Bygrave 7c3d052da0 [maven-release-plugin] prepare release avaje-ebeanorm-6.12.3 2015-12-02 23:47:49 +13:00
Robin Bygrave aea7a7fd65 #118 - ENH: Add support for for Soft Deletes (Logical Deletion) ... 2015-12-02 23:46:26 +13:00
Robin Bygrave f39a684c8e #118 - ENH: Add support for for Soft Deletes (Logical Deletion) ... 2015-12-02 21:38:34 +13:00
Robin Bygrave 3cb5854786 #475 - Unique constraint name not unique when using @Draftable 2015-12-02 07:57:27 +13:00
Robin Bygrave e8192723cc [maven-release-plugin] prepare for next development iteration 2015-12-01 23:25:26 +13:00
Robin Bygrave 3787748eae [maven-release-plugin] prepare release avaje-ebeanorm-6.12.2 2015-12-01 23:25:00 +13:00
Robin Bygrave 0ad52cf6a7 #118 - ENH: Add support for for Soft Deletes (Logical Deletion) ... - initial 2015-12-01 23:21:11 +13:00
Robin Bygrave 51bee836d4 #472 - DDL column ordering for @WhoCreated / @WhoModified. These columns should appear in the DDL with the @WhenCreated/@WhenModified columns. 2015-12-01 10:19:36 +13:00
Robin Bygrave 9193b6b971 No effective change - remove whitespace 2015-12-01 09:32:09 +13:00
Robin Bygrave e48b9fab0f No effective change - spelling in javadoc 2015-12-01 08:08:14 +13:00
Robin Bygrave a14ca24b33 [maven-release-plugin] prepare for next development iteration 2015-11-30 23:25:13 +13:00
Robin Bygrave 761f43d6a1 [maven-release-plugin] prepare release avaje-ebeanorm-6.12.1 2015-11-30 23:24:46 +13:00
Robin Bygrave 737f9a893e Bump pom - 6.12.1-SNAPSHOT 2015-11-30 23:23:58 +13:00
Robin Bygrave 579812d717 #455 - Should not generate "FOR UPDATE" for delete query 2015-11-30 16:50:26 +13:00
Robin Bygrave fae39fe650 #291 - ENH: Add ability to validate a query or property expression - Was Please check column exist on entity 2015-11-30 15:10:22 +13:00
Robin Bygrave debd8ad617 #465 - The encrypt key is logged out in sql statement - when included in where predicate 2015-11-30 12:25:25 +13:00
Robin Bygrave 6450ba219c #469 - Embedded bean made dirty after a prior insert does not trigger dirty state on 'outer' bean 2015-11-27 18:19:59 +13:00
Robin Bygrave a578eda2b1 #467 - Delete bean with unloaded version property throws OptimisticLockException - API Change, return boolean 2015-11-26 16:09:25 +13:00
Robin Bygrave a2ee0bfdbe #467 - Delete bean with unloaded version property throws OptimisticLockException 2015-11-26 15:12:59 +13:00
Robin Bygrave 872f0e21cb #466 - Delete of @Draftable bean ... means also delete matching live bean (aka delete has automatic publish behavior) 2015-11-26 00:49:18 +13:00
Robin Bygrave 8620dbf337 #464 - ENH: Add draftRestore(Class<?> beanType, Object id) ... to refresh a draft from the live (@Draftable feature) 2015-11-25 23:36:17 +13:00
Robin Bygrave 4f51a3b130 #463 - ENH: Add @DraftReset support - property that is set to null on the draft been when it is published (@Draftable feature) 2015-11-25 11:06:14 +13:00
Robin Bygrave 5f194f066a [maven-release-plugin] prepare for next development iteration 2015-11-24 01:04:26 +13:00
Robin Bygrave 31f6e56333 [maven-release-plugin] prepare release avaje-ebeanorm-6.11.1 2015-11-24 01:04:04 +13:00
Robin Bygrave 0efbe061ab #461 - ENH: Add @Draftable support - optimise publish query 2015-11-24 01:01:37 +13:00
Robin Bygrave 555e5ba6fd #461 - ENH: Add @Draftable support - API sans transaction 2015-11-24 01:01:14 +13:00
Robin Bygrave 5d3da60828 #461 - ENH: Add @Draftable support - delete 2015-11-24 00:46:45 +13:00
Robin Bygrave 2ac0d136e6 Bump pom to 6.11.1-SNAPSHOT 2015-11-24 00:02:35 +13:00
Robin Bygrave 97462cb21a #461 - ENH: Add @Draftable support - delete 2015-11-24 00:01:28 +13:00
Robin Bygrave afaacd4eeb #461 - ENH: Add @Draftable support - javadoc 2015-11-23 23:26:09 +13:00
Robin Bygrave 5e8afbe50d #461 - ENH: Add @Draftable support - @DraftDirty 2015-11-23 23:11:15 +13:00
Robin Bygrave db371cbc6a #461 - ENH: Add @Draftable support - publish 2015-11-23 21:28:58 +13:00
Robin Bygrave fd9a5167b1 #461 - ENH: Add @Draftable support - load context 2015-11-23 10:07:09 +13:00
Robin Bygrave 7b76e13bce #461 - ENH: Add @Draftable support - phase 1 2015-11-19 20:44:25 +13:00
Robin Bygrave 42e7103aa6 #458 - Support use of test-ebean.properties without an existing ebean.properties 2015-11-12 10:17:30 +13:00
Robin Bygrave 29ca678f01 No effective change - remove unused code 2015-11-12 09:59:36 +13:00
Robin Bygrave cca6143420 No effective change - code format 2015-11-12 09:48:18 +13:00
Robin Bygrave fe7b110577 #457 - When ebean.properties does not exist do not log error message 2015-11-10 09:47:33 +13:00
Robin Bygrave 16df55eafa [maven-release-plugin] prepare for next development iteration 2015-11-09 14:44:45 +13:00
Robin Bygrave 905a0ce9ec [maven-release-plugin] prepare release avaje-ebeanorm-6.10.4 2015-11-09 14:44:05 +13:00
Robin Bygrave bfa8837e61 #451 - avaje-ebeanorm-jackson - com.fasterxml.jackson.core.JsonParseException: Expecting start_array event but got START_OBJECT at 2015-11-05 16:38:22 +13:00
Robin Bygrave 8d5845b9a2 [maven-release-plugin] prepare for next development iteration 2015-11-04 22:10:38 +13:00
Robin Bygrave 87a7d4958e [maven-release-plugin] prepare release avaje-ebeanorm-6.10.3 2015-11-04 22:10:13 +13:00
Robin Bygrave 511ebd8a29 #450 - @ManyToMany with cascade and jdbc batch - ensure flush occurs 2015-11-03 16:31:27 +13:00
Robin Bygrave 11f4c8d7a3 #449 - Remove whitespace from generated Postgres trigger DDL (as Play evolution not parsing it) 2015-11-03 16:28:00 +13:00
Robin Bygrave d417a92843 [maven-release-plugin] prepare for next development iteration 2015-11-02 16:42:33 +13:00
Robin Bygrave 4bd5e52df3 [maven-release-plugin] prepare release avaje-ebeanorm-6.10.2 2015-11-02 16:42:10 +13:00
Robin Bygrave 788a200d16 #445 - Multiple @*ToMany relations referencing the same type 2015-11-02 14:11:23 +13:00
Robin Bygrave e18d2004dc #448 - ENH: Postgres Support for UUID mapping to native DB UUID type (relating to #430) 2015-11-02 12:57:47 +13:00
Robin Bygrave b326724139 #443 - ENH: Enum mapping - Add annotation @DbEnumValue that can be used to on a enum method which provides DB values 2015-10-30 21:42:21 +13:00
Robin Bygrave fc0b47342b #436 - @DiscriminatorColumn mapped also as @Column leads to NullPointerException 2015-10-29 22:01:28 +13:00
Robin Bygrave ec1a68a133 #435 - Duplicate foreign key name with ManyToMany relations 2015-10-29 17:44:29 +13:00
Robin Bygrave 8ca12521d7 No effective change - reduce debug level 2015-10-29 17:43:54 +13:00
Robin Bygrave 2362ef4130 [maven-release-plugin] prepare for next development iteration 2015-10-29 09:01:17 +13:00
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
1185 changed files with 70712 additions and 25831 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
+23
View File
@@ -0,0 +1,23 @@
language: java
jdk:
- oraclejdk8
addons:
postgresql: "9.4"
services:
- postgresql
before_script:
- psql -c 'create extension pgcrypto;' -U postgres
- psql -c 'create extension hstore;' -U postgres
- psql -c 'create extension postgis;' -U postgres
- psql -c 'create database unit;' -U postgres
env:
- EBEAN_DB=h2
- EBEAN_DB=pg
cache:
directories:
- $HOME/.m2
+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,11 +9,11 @@
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>6.2.2</version>
<version>6.16.2</version>
<packaging>jar</packaging>
<name>avaje-ebeanorm</name>
<url>http://www.avaje.org</url>
<url>http://ebean-orm.github.io/</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -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.9.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.8.1</version>
<executions>
<!-- Not going to enhance Model bean -->
<execution>
@@ -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,24 @@
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();
/**
* Output the profiling.
* <p>
* When profiling updates are applied to tuning at runtime this reports all tuning and profiling combined.
* When profiling is not applied at runtime then this reports the diff report with new and diff entries relative
* to the existing tuning.
* </p>
*/
void reportProfiling();
}
@@ -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.
@@ -45,7 +45,7 @@ final class DRawSqlColumnsParser {
String colInfo = sqlSelect.substring(start, pos++);
colInfo = colInfo.trim();
String[] split = colInfo.split(" ");
String[] split = colInfo.split("\\s(?=[^\\)]*(?:\\(|$))");
if (split.length > 1) {
ArrayList<String> tmp = new ArrayList<String>(split.length);
for (int i = 0; i < split.length; i++) {
@@ -80,17 +80,18 @@ final class DRawSqlColumnsParser {
return new ColumnMapping.Column(indexPos++, sb.toString(), split[split.length - 1]);
}
private int nextComma() {
private void nextComma() {
boolean inQuote = false;
int inbrackets = 0;
while (pos < end) {
char c = sqlSelect.charAt(pos);
if (c == '\'') {
inQuote = !inQuote;
} else if (!inQuote && c == ',') {
return pos;
if (c == '\'') inQuote = !inQuote;
else if (c == '(') inbrackets++;
else if (c == ')') inbrackets--;
else if (!inQuote && inbrackets == 0 && c == ',') {
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;
@@ -46,6 +46,7 @@ class DRawSqlParser {
private DRawSqlParser(String sqlString) {
sqlString = sqlString.trim();
sqlString = sqlString.replace('\n',' ');
this.sql = sqlString;
this.hasPlaceHolders = findAndRemovePlaceHolders();
this.textParser = new SimpleTextParser(sqlString);
@@ -98,19 +99,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;
}
/**
@@ -132,8 +121,7 @@ class DRawSqlParser {
// trim of distinct keyword
String distinct = preWhereExprSql.substring(0, 9);
if (!distinct.equalsIgnoreCase("distinct ")) {
throw new RuntimeException("Expecting [" + preWhereExprSql
+ "] to start with \"select distinct\"");
throw new RuntimeException("Expecting [" + preWhereExprSql + "] to start with \"select distinct\"");
}
preWhereExprSql = preWhereExprSql.substring(9);
}
+34 -8
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) {
@@ -697,12 +697,31 @@ public final class Ebean {
/**
* Delete the bean.
* <p>
* This will return true if the bean was deleted successfully or JDBC batch is being used.
* </p>
* <p>
* If there is no current transaction one will be created and committed for
* you automatically.
* </p>
* <p>
* If the bean is configured with <code>@SoftDelete</code> then this will perform a soft
* delete rather than a hard/permanent delete.
* </p>
* <p>
* If the Bean does not have a version property (or loaded version property) and
* the bean does not exist then this returns false indicating that nothing was
* deleted. Note that, if JDBC batch mode is used then this always returns true.
* </p>
*/
public static void delete(Object bean) throws OptimisticLockException {
serverMgr.getDefaultServer().delete(bean);
public static boolean delete(Object bean) throws OptimisticLockException {
return serverMgr.getDefaultServer().delete(bean);
}
/**
* Delete the bean in permanent fashion (will not use soft delete).
*/
public static boolean deletePermanent(Object bean) throws OptimisticLockException {
return serverMgr.getDefaultServer().deletePermanent(bean);
}
/**
@@ -726,6 +745,13 @@ public final class Ebean {
return serverMgr.getDefaultServer().deleteAll(beans);
}
/**
* Delete permanent all the beans in the Collection (will not use soft delete).
*/
public static int deleteAllPermanent(Collection<?> beans) throws OptimisticLockException {
return serverMgr.getDefaultServer().deleteAllPermanent(beans);
}
/**
* Refresh the values of a bean.
* <p>
+231 -26
View File
@@ -1,21 +1,22 @@
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.NonUniqueResultException;
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 +107,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 +128,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>
@@ -1015,7 +1020,7 @@ public interface EbeanServer {
SqlFutureList findFutureList(SqlQuery query, Transaction transaction);
/**
* Return a PagedList for this query.
* Return a PagedList for this query using pageIndex and pageSize.
* <p>
* The benefit of using this over just using the normal {@link Query#setFirstRow(int)} and
* {@link Query#setMaxRows(int)} is that it additionally wraps an optional call to
@@ -1037,6 +1042,38 @@ public interface EbeanServer {
*/
<T> PagedList<T> findPagedList(Query<T> query, Transaction transaction, int pageIndex, int pageSize);
/**
* Return a PagedList for this query using firstRow and maxRows.
* <p>
* The benefit of using this over findList() is that it provides functionality to get the
* total row count etc.
* </p>
* <p>
* If maxRows is not set on the query prior to calling findPagedList() then a
* PersistenceException is thrown.
* </p>
*
* <pre>{@code
*
* PagedList<Order> pagedList = Ebean.find(Order.class)
* .setFirstRow(50)
* .setMaxRows(20)
* .findPagedList();
*
* // fetch the total row count in the background
* pagedList.loadRowCount();
*
* List<Order> orders = pagedList.getList();
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*
* @return The PagedList
*
* @see Query#findPagedList()
*/
<T> PagedList<T> findPagedList(Query<T> query, Transaction transaction);
/**
* Execute the query returning a set of entity beans.
* <p>
@@ -1087,14 +1124,17 @@ public interface EbeanServer {
<T> Map<?, T> findMap(Query<T> query, Transaction transaction);
/**
* Execute the query returning at most one entity bean. This will throw a
* PersistenceException if the query finds more than one result.
* Execute the query returning at most one entity bean or null (if no matching
* bean is found).
* <p>
* This will throw a NonUniqueResultException if the query finds more than one result.
* </p>
* <p>
* Generally you are able to use {@link Query#findUnique()} rather than
* explicitly calling this method. You could use this method if you wish to
* explicitly control the transaction used for the query.
* </p>
*
*
* @param <T>
* the type of entity bean to fetch.
* @param query
@@ -1102,12 +1142,28 @@ public interface EbeanServer {
* @param transaction
* the transaction to use (can be null).
* @return the list of fetched beans.
* @throws NonUniqueResultException if more than one result was found
*
* @see Query#findUnique()
*/
@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 +1261,6 @@ public interface EbeanServer {
* public class Order { ...
*
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
* @JoinColumn(name="order_id")
* List<OrderDetail> details;
* ...
* }
@@ -1228,16 +1283,52 @@ public interface EbeanServer {
/**
* Delete the bean.
* <p>
* This will return true if the bean was deleted successfully or JDBC batch is being used.
* </p>
* <p>
* If there is no current transaction one will be created and committed for
* you automatically.
* </p>
* <p>
* If the Bean does not have a version property (or loaded version property) and
* the bean does not exist then this returns false indicating that nothing was
* deleted. Note that, if JDBC batch mode is used then this always returns true.
* </p>
*/
void delete(Object bean) throws OptimisticLockException;
boolean delete(Object bean) throws OptimisticLockException;
/**
* Delete all the beans in the collection.
* Delete the bean with an explicit transaction.
* <p>
* This will return true if the bean was deleted successfully or JDBC batch is being used.
* </p>
* <p>
* If the Bean does not have a version property (or loaded version property) and
* the bean does not exist then this returns false indicating that nothing was
* deleted. However, if JDBC batch mode is used then this always returns true.
* </p>
*/
int deleteAll(Collection<?> beans) throws OptimisticLockException;
boolean delete(Object bean, Transaction transaction) throws OptimisticLockException;
/**
* Delete a bean permanently without soft delete.
*/
boolean deletePermanent(Object bean) throws OptimisticLockException;
/**
* Delete a bean permanently without soft delete using an explicit transaction.
*/
boolean deletePermanent(Object bean, Transaction transaction) throws OptimisticLockException;
/**
* Delete all the beans in the collection permanently without soft delete.
*/
int deleteAllPermanent(Collection<?> beans) throws OptimisticLockException;
/**
* Delete all the beans in the collection permanently without soft delete using an explicit transaction.
*/
int deleteAllPermanent(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
/**
* Delete the bean given its type and id.
@@ -1249,6 +1340,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 +1361,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
@@ -1433,7 +1529,7 @@ public interface EbeanServer {
void markAsDirty(Object bean);
/**
* Saves the bean using an update. If you know you are updating a bean then it is preferrable to
* Saves the bean using an update. If you know you are updating a bean then it is preferable to
* use this update() method rather than save().
* <p>
* <b>Stateless updates:</b> Note that the bean does not have to be previously fetched to call
@@ -1485,7 +1581,6 @@ public interface EbeanServer {
* @param deleteMissingChildren
* specify false if you do not want 'missing children' of a OneToMany
* or ManyToMany to be automatically deleted.
*/
void update(Object bean, Transaction transaction, boolean deleteMissingChildren) throws OptimisticLockException;
@@ -1796,4 +1891,114 @@ public interface EbeanServer {
*/
JsonContext json();
/**
* Publish a single bean given its type and id returning the resulting live bean.
* <p>
* The values are published from the draft to the live bean.
* </p>
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
* @param id the id of the entity bean
* @param transaction the transaction the publish process should use (can be null)
*/
<T> T publish(Class<T> beanType, Object id, Transaction transaction);
/**
* Publish a single bean given its type and id returning the resulting live bean.
* This will use the current transaction or create one if required.
* <p>
* The values are published from the draft to the live bean.
* </p>
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
* @param id the id of the entity bean
*/
<T> T publish(Class<T> beanType, Object id);
/**
* Publish the beans that match the query returning the resulting published beans.
* <p>
* The values are published from the draft beans to the live beans.
* </p>
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to publish
* @param transaction the transaction the publish process should use (can be null)
*/
<T> List<T> publish(Query<T> query, Transaction transaction);
/**
* Publish the beans that match the query returning the resulting published beans.
* This will use the current transaction or create one if required.
* <p>
* The values are published from the draft beans to the live beans.
* </p>
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to publish
*/
<T> List<T> publish(Query<T> query);
/**
* Restore the draft bean back to the live state.
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
* </p>
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
* @param id the id of the entity bean to restore
* @param transaction the transaction the restore process should use (can be null)
*/
<T> T draftRestore(Class<T> beanType, Object id, Transaction transaction);
/**
* Restore the draft bean back to the live state.
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
* </p>
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
* @param id the id of the entity bean to restore
*/
<T> T draftRestore(Class<T> beanType, Object id);
/**
* Restore the draft beans matching the query back to the live state.
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
* </p>
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to restore
* @param transaction the transaction the restore process should use (can be null)
*/
<T> List<T> draftRestore(Query<T> query, Transaction transaction);
/**
* Restore the draft beans matching the query back to the live state.
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
* </p>
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to restore
*/
<T> List<T> draftRestore(Query<T> query);
/**
* Returns the set of properties/paths that are unknown (do not map to known properties or paths).
* <p>
* Validate the query checking the where and orderBy expression paths to confirm if
* they represent valid properties/path for the given bean type.
* </p>
*/
<T> Set<String> validateQuery(Query<T> query);
}
@@ -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.
*/
+250 -21
View File
@@ -3,6 +3,7 @@ package com.avaje.ebean;
import com.avaje.ebean.text.PathProperties;
import org.jetbrains.annotations.Nullable;
import javax.persistence.NonUniqueResultException;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Collection;
@@ -107,6 +108,28 @@ public interface ExpressionList<T> extends Serializable {
*/
Query<T> asOf(Timestamp asOf);
/**
* Execute the query against the draft set of tables.
*/
Query<T> asDraft();
/**
* Execute the query including soft deleted rows.
*/
Query<T> includeSoftDeletes();
/**
* 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.
*
@@ -171,8 +194,15 @@ public interface ExpressionList<T> extends Serializable {
<K> Map<K, T> findMap(String keyProperty, Class<K> keyType);
/**
* Execute the query returning a single bean.
*
* Execute the query returning a single bean or null (if no matching
* bean is found).
* <p>
* If more than 1 row is found for this query then a NonUniqueResultException is
* thrown.
* </p>
*
* @throws NonUniqueResultException if more than one result was found
*
* @see Query#findUnique()
*/
@Nullable
@@ -215,7 +245,7 @@ public interface ExpressionList<T> extends Serializable {
FutureList<T> findFutureList();
/**
* Return a PagedList for this query.
* Return a PagedList for this query using pageIndex and pageSize.
* <p>
* The benefit of using this over just using the normal {@link Query#setFirstRow(int)} and
* {@link Query#setMaxRows(int)} is that it additionally wraps an optional call to
@@ -235,6 +265,38 @@ public interface ExpressionList<T> extends Serializable {
*/
PagedList<T> findPagedList(int pageIndex, int pageSize);
/**
* Return a PagedList for this query using firstRow and maxRows.
* <p>
* The benefit of using this over findList() is that it provides functionality to get the
* total row count etc.
* </p>
* <p>
* If maxRows is not set on the query prior to calling findPagedList() then a
* PersistenceException is thrown.
* </p>
*
* <pre>{@code
*
* PagedList<Order> pagedList = Ebean.find(Order.class)
* .setFirstRow(50)
* .setMaxRows(20)
* .findPagedList();
*
* // fetch the total row count in the background
* pagedList.loadRowCount();
*
* List<Order> orders = pagedList.getList();
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*
* @return The PagedList
*
* @see Query#findPagedList()
*/
PagedList<T> findPagedList();
/**
* Return versions of a @History entity bean.
* <p>
@@ -244,6 +306,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 +328,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 +374,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 +395,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 +605,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 +762,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);
@@ -562,7 +785,7 @@ public interface ExpressionList<T> extends Serializable {
* qualified) will still be translated to their physical name.
* </p>
*/
ExpressionList<T> raw(String raw, Object[] values);
ExpressionList<T> raw(String raw, Object... values);
/**
* Add raw expression with no parameters.
@@ -571,6 +794,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;
+47 -9
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.
*
@@ -226,12 +251,24 @@ public abstract class Model {
}
/**
* Delete this entity.
* Delete this bean.
* <p>
* This will return true if the bean was deleted successfully or JDBC batch is being used.
* </p>
* <p>
* If there is no current transaction one will be created and committed for
* you automatically.
* </p>
* <p>
* If the Bean does not have a version property (or loaded version property) and
* the bean does not exist then this returns false indicating that nothing was
* deleted. Note that, if JDBC batch mode is used then this always returns true.
* </p>
*
* @see EbeanServer#delete(Object)
*/
public void delete() {
db().delete(this);
public boolean delete() {
return db().delete(this);
}
/**
@@ -251,8 +288,8 @@ public abstract class Model {
/**
* Perform a delete using this entity against the specified server.
*/
public void delete(String server) {
db(server).delete(this);
public boolean delete(String server) {
return db(server).delete(this);
}
/**
@@ -441,6 +478,7 @@ public abstract class Model {
*
* }</pre>
*/
@SuppressWarnings("unchecked")
public Find() {
this.serverName = null;
this.type = (Class<T>)ClassUtil.getSecondArgumentType(getClass());
@@ -835,10 +873,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.
*/
@@ -17,6 +17,33 @@ import java.util.concurrent.Future;
* limit the result set.
* </p>
*
*
* <h4>Example: typical use including total row count</h4>
* <pre>{@code
*
* // We want to find the first 50 new orders
* // ... so we don't really need setFirstRow(0)
*
* PagedList<Order> pagedList
* = ebeanServer.find(Order.class)
* .where().eq("status", Order.Status.NEW)
* .order().asc("id")
* .setFirstRow(0)
* .setMaxRows(50)
* .findPagedList();
*
* // Optional: initiate the loading of the total
* // row count in a background thread
* pagedList.loadRowCount();
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* // get the total row count (from the future)
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*
* <h4>Example: typical use including total row count</h4>
* <pre>{@code
*
@@ -156,9 +183,18 @@ public interface PagedList<T> {
/**
* Return the index position of this page. Zero based.
* <p>
* Note that if firstRows/maxRows is used rather than pageIndex/pageSize then
* this always returns 0.
* </p>
*/
int getPageIndex();
/**
* Return the page size used for this query. This is the same value as maxRows used by the query.
*/
int getPageSize();
/**
* Return true if there is a next page.
* <p>
@@ -58,15 +58,18 @@ class PrimaryServer {
*/
private static String determineDefaultServerName() {
String defaultServerName = System.getProperty("datasource.default");
String defaultServerName = System.getenv("EBEAN_DB");
if (isEmpty(defaultServerName)) {
defaultServerName = System.getProperty("ebean.default.datasource");
}
if (isEmpty(defaultServerName)) {
defaultServerName = globalProperties.getProperty("datasource.default");
}
if (isEmpty(defaultServerName)) {
defaultServerName = globalProperties.getProperty("ebean.default.datasource");
defaultServerName = System.getProperty("datasource.default");
if (isEmpty(defaultServerName)) {
defaultServerName = System.getProperty("ebean.default.datasource");
if (isEmpty(defaultServerName)) {
defaultServerName = globalProperties.getProperty("datasource.default");
if (isEmpty(defaultServerName)) {
defaultServerName = globalProperties.getProperty("ebean.default.datasource");
}
}
}
}
return defaultServerName;
}
+114 -13
View File
@@ -3,6 +3,7 @@ package com.avaje.ebean;
import com.avaje.ebean.text.PathProperties;
import org.jetbrains.annotations.Nullable;
import javax.persistence.NonUniqueResultException;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.List;
@@ -67,9 +68,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 +79,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.
@@ -297,6 +298,16 @@ public interface Query<T> extends Serializable {
*/
Query<T> asOf(Timestamp asOf);
/**
* Execute the query against the draft set of tables.
*/
Query<T> asDraft();
/**
* Execute the query including soft deleted rows.
*/
Query<T> includeSoftDeletes();
/**
* Cancel the query execution if supported by the underlying database and
* driver.
@@ -338,23 +349,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 +377,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
@@ -680,7 +701,7 @@ public interface Query<T> extends Serializable {
* Execute the query returning either a single bean or null (if no matching
* bean is found).
* <p>
* If more than 1 row is found for this query then a PersistenceException is
* If more than 1 row is found for this query then a NonUniqueResultException is
* thrown.
* </p>
* <p>
@@ -716,6 +737,8 @@ public interface Query<T> extends Serializable {
* List<OrderDetail> details = order.getDetails();
* ...
* }</pre>
*
* @throws NonUniqueResultException if more than one result was found
*/
@Nullable
T findUnique();
@@ -723,12 +746,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>
@@ -773,7 +822,7 @@ public interface Query<T> extends Serializable {
FutureList<T> findFutureList();
/**
* Return a PagedList for this query.
* Return a PagedList for this query using pageIndex and pageSize.
* <p>
* The benefit of using this over just using the normal {@link Query#setFirstRow(int)} and
* {@link Query#setMaxRows(int)} is that it additionally wraps an optional call to
@@ -818,6 +867,36 @@ public interface Query<T> extends Serializable {
*/
PagedList<T> findPagedList(int pageIndex, int pageSize);
/**
* Return a PagedList for this query using firstRow and maxRows.
* <p>
* The benefit of using this over findList() is that it provides functionality to get the
* total row count etc.
* </p>
* <p>
* If maxRows is not set on the query prior to calling findPagedList() then a
* PersistenceException is thrown.
* </p>
*
* <pre>{@code
*
* PagedList<Order> pagedList = Ebean.find(Order.class)
* .setFirstRow(50)
* .setMaxRows(20)
* .findPagedList();
*
* // fetch the total row count in the background
* pagedList.loadRowCount();
*
* List<Order> orders = pagedList.getList();
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*
* @return The PagedList
*/
PagedList<T> findPagedList();
/**
* Set a named bind parameter. Named parameters have a colon to prefix the name.
*
@@ -1129,6 +1208,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);
@@ -1264,4 +1356,13 @@ public interface Query<T> extends Serializable {
* </p>
*/
Query<T> setDisableLazyLoading(boolean disableLazyLoading);
/**
* Returns the set of properties or paths that are unknown (do not map to known properties or paths).
* <p>
* Validate the query checking the where and orderBy expression paths to confirm if
* they represent valid properties or paths for the given bean type.
* </p>
*/
Set<String> validate();
}
+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
}
@@ -9,6 +9,10 @@ import java.lang.annotation.Target;
* For a timestamp property that is set to the datetime when the entity is
* created/inserted.
* <p>
* This is effectively an alias for @WhenCreated which was added as it hints
* towards a better naming convention (WhenCreated, WhenModified).
* </p>
* <p>
* An alternative to using this annotation would be to use insertable=false,
* updateable=false with @Column and have the DB insert the current time
* (default value on the DB column is SYSTIME etc).
@@ -0,0 +1,19 @@
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;
/**
* A database table or column comment.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
public @interface DbComment {
/**
* The database table or column comment.
*/
String value();
}
@@ -0,0 +1,17 @@
package com.avaje.ebean.annotation;
/**
* Specify the DB storage type used to with <code>@DbEnumValue</code>.
*/
public enum DbEnumType {
/**
* Store values as database INTEGER.
*/
INTEGER,
/**
* Store values as database VARCHAR.
*/
VARCHAR
}
@@ -0,0 +1,44 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify a method on an Enum that returns the value that should be stored in the DB.
* <p>
* This is the preferred option for mapping Enum's to DB values (preferred over the JPA
* standard @Enumerated and Ebean's @EnumValue annotations).
* </p>
* <h3>Example:</h3>
* <pre>{@code
*
* public enum Status {
* NEW("N"),
* ACTIVE("A"),
* INACTIVE("I");
*
* String dbValue;
* Status(String dbValue) {
* this.dbValue = dbValue;
* }
*
* @DbEnumValue
* public String getValue() {
* return dbValue;
* }
* }
*
* }</pre>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DbEnumValue {
/**
* Specify the database type used to store the values (VARCHAR or INTEGER).
*/
DbEnumType storage() default DbEnumType.VARCHAR;
}
@@ -0,0 +1,19 @@
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 a boolean property on a @Draftable bean that indicates if the bean instance is a 'draft' or 'live' bean.
* The property is transient and has no underlying DB column.
* <p>
* For beans returned from an <code>asDraft()</code> query this property will be set to true.
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Draft {
}
@@ -0,0 +1,20 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marks a boolean property on a @Draftable bean that only exists on the 'draft' table
* and is used to detect when a draft has unpublished changes.
* <p>
* This property will automatically have it's value set to true when a draft is saved and
* automatically have it's value set to false when the bean is published.
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DraftDirty {
}
@@ -0,0 +1,19 @@
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 a property on a @Draftable bean that only exists on the 'draft' and not the 'live' table.
* <p>
* Typically this would be used on a property that is used as part of application 'workflow' such as
* a publish workflow status or when publish timestamp.
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DraftOnly {
}
@@ -0,0 +1,19 @@
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 a property on a @Draftable bean that is set to null on the 'draft bean' on publish.
* <p>
* This is expected to be put on properties that get 'reset' or 'cleared' after a publish.
* These properties might represent a publish comment or publish timestamp.
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DraftReset {
}
@@ -0,0 +1,29 @@
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;
/**
* Used to indicate an entity bean that has 'draftable' support.
* <p>
* This means that a second set of tables is created to hold draft versions of
* the rows and that these can then be published which effectively copies/transfers
* the values from the 'draft' table to the 'live' table.
* </p>
* <p>
* Ebean Query supports 'find as draft' which builds the resulting object graph using
* the draft tables. This object graph is typically edited, approved in some application
* specific manor and then published.
* </p>
* <p>
* EbeanServer has a publish method which transfers/copies the draft object graph to
* the 'live' tables.
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Draftable {
}
@@ -0,0 +1,20 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used to indicate an entity bean that has 'draftable' support but it not a 'top level'
* (or root level) bean but instead child related to another @Draftable entity bean.
* <p>
* Relationships to @DraftableElements (@OneToMany, @ManyToMany etc) are automatically
* deemed to have Cascade.ALL for save and delete (as well as orphan removal mode).
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DraftableElement {
}
@@ -25,7 +25,7 @@ import java.lang.annotation.Target;
* }</pre>
* <p>
* This is an alternative to using the JPA standard approach or Ebean's
* {@link EnumMapping} annotation.
* {@link DbEnumValue} annotation.
* </p>
* <p>
* Note that if all the EnumValue values are parsable as Integers then Ebean
@@ -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 {
}
@@ -0,0 +1,25 @@
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;
/**
* Used to indicate a property on an entity bean used to control 'soft delete'
* (also known as 'logical delete').
* <p>
* The property should be of type boolean.
* </p>
* <pre>{@code
*
* @SoftDelete
* boolean deleted;
*
* }</pre>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SoftDelete {
}
@@ -8,6 +8,10 @@ import java.lang.annotation.Target;
/**
* For a timestamp property that is set to the datetime when the entity was last
* updated.
* <p>
* This is effectively an alias for @WhenModified which was added as it hints
* towards a better naming convention (WhenCreated, WhenModified).
* </p>
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@@ -11,7 +11,6 @@ import java.lang.annotation.Target;
* This is effectively an alias for @UpdatedTimestamp and added to hint
* towards a better naming convention (WhenCreated, WhenModified).
* </p>
* </p>
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@@ -31,6 +31,16 @@ public interface BeanCollection<E> extends Serializable {
ALL
}
/**
* Add a bean to the list/set with modifyListen notification.
*/
void addBean(E bean);
/**
* Remove a bean to the list/set with modifyListen notification.
*/
void removeBean(E bean);
/**
* Reset the collection back to an empty state ready for reloading.
* <p>
@@ -12,5 +12,5 @@ public interface BeanCollectionAdd {
/**
* Add a loaded bean to the collection.
*/
void addBean(EntityBean bean);
void addEntityBean(EntityBean bean);
}
@@ -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;
@@ -73,16 +73,6 @@ public interface EntityBean extends Serializable {
*/
EntityBeanIntercept _ebean_intercept();
/**
* Create a copy of this entity bean.
* <p>
* This occurs when a bean is changed. The copy represents the bean as it was
* initially (oldValues) before any changes where made. This is used for
* optimistic concurrency control.
* </p>
*/
Object _ebean_createCopy();
/**
* Set the value of a field of an entity bean of this type.
* <p>
@@ -1,5 +1,10 @@
package com.avaje.ebean.bean;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.ValuePair;
import javax.persistence.EntityNotFoundException;
import javax.persistence.PersistenceException;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
@@ -11,12 +16,6 @@ import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityNotFoundException;
import javax.persistence.PersistenceException;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.ValuePair;
/**
* This is the object added to every entity bean using byte code enhancement.
* <p>
@@ -45,7 +44,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 +71,7 @@ public final class EntityBeanIntercept implements Serializable {
/**
* Used when a bean is partially filled.
*/
private boolean[] loadedProps;
private final boolean[] loadedProps;
private boolean fullyLoadedBean;
@@ -92,6 +91,8 @@ public final class EntityBeanIntercept implements Serializable {
private int lazyLoadProperty = -1;
private Object ownerId;
/**
* Create a intercept with a given entity.
* <p>
@@ -349,11 +350,22 @@ public final class EntityBeanIntercept implements Serializable {
* lazy loading and this bean might not be used by the client code at all.
* Instead we will fail as soon as the client code tries to use this bean.
* </p>
* @param lazyLoadPropertyIndex the property that is expected to be loaded
*/
public void checkLazyLoadFailure() {
if (lazyLoadProperty != -1) {
this.lazyLoadFailure = true;
public boolean isLazyLoadFailure(int lazyLoadPropertyIndex) {
if (lazyLoadProperty != -1 || !isLoadedProperty(lazyLoadPropertyIndex)) {
lazyLoadFailure = true;
return true;
}
lazyLoadFailure = false;
return false;
}
/**
* Set the Id of the owner bean.
*/
public void setOwnerId(Object ownerId) {
this.ownerId = ownerId;
}
/**
@@ -449,7 +461,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.
@@ -496,7 +519,7 @@ public final class EntityBeanIntercept implements Serializable {
setDirty(true);
}
private void setChangedProperty(int propertyIndex) {
public void setChangedProperty(int propertyIndex) {
if (changedProps == null) {
changedProps = new boolean[owner._ebean_getPropertyNames().length];
}
@@ -581,7 +604,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.
*/
@@ -715,7 +760,7 @@ public final class EntityBeanIntercept implements Serializable {
if (lazyLoadFailure) {
// failed when batch lazy loaded by another bean in the batch
throw new EntityNotFoundException("Bean has been deleted - lazy loading failed");
throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted");
}
if (lazyLoadProperty == -1) {
@@ -730,7 +775,7 @@ public final class EntityBeanIntercept implements Serializable {
if (lazyLoadFailure) {
// failed when lazy loading this bean
throw new EntityNotFoundException("Bean has been deleted - lazy loading failed");
throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted.");
}
// bean should be loaded and intercepting now. setLoaded() has
@@ -891,7 +936,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 +951,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 +967,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 +982,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 +997,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 +1012,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 +1027,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 +1042,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);
@@ -60,7 +60,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
}
@SuppressWarnings("unchecked")
public void addBean(EntityBean bean) {
public void addEntityBean(EntityBean bean) {
list.add((E) bean);
}
@@ -206,6 +206,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
list.add(index, element);
}
@Override
public void addBean(E bean) {
add(bean);
}
public boolean add(E o) {
checkReadOnly();
init();
@@ -319,6 +324,13 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.listIterator(index);
}
@Override
public void removeBean(E bean) {
if (list.remove(bean)) {
getModifyHolder().modifyRemoval(bean);
}
}
public E remove(int index) {
checkReadOnly();
init();
@@ -343,41 +355,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 +427,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,40 @@ 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);
}
@Override
public void addBean(E bean) {
throw new IllegalStateException("Method not allowed on Map. Please use List instead.");
}
@Override
public void removeBean(E bean) {
throw new IllegalStateException("Method not allowed on Map. Please use List instead.");
}
public E remove(Object key) {
@@ -53,7 +53,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
}
@SuppressWarnings("unchecked")
public void addBean(EntityBean bean) {
public void addEntityBean(EntityBean bean) {
set.add((E) bean);
}
@@ -174,6 +174,18 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.hashCode();
}
@Override
public void addBean(E bean) {
add(bean);
}
@Override
public void removeBean(E bean) {
if (set.remove(bean)) {
getModifyHolder().modifyRemoval(bean);
}
}
// -----------------------------------------------------//
// proxy method for map
// -----------------------------------------------------//
@@ -192,32 +204,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 +271,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 +319,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,254 @@
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 profilingUpdateFrequency;
private int garbageCollectionWait = 100;
private boolean skipGarbageCollectionOnShutdown;
private boolean skipProfileReportingOnShutdown;
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 frequency in seconds the profiling should be collected and automatically applied to the tuning.
*/
public int getProfilingUpdateFrequency() {
return profilingUpdateFrequency;
}
/**
* Set the frequency in seconds the profiling should be collected and automatically applied to the tuning.
*/
public void setProfilingUpdateFrequency(int profilingUpdateFrequency) {
this.profilingUpdateFrequency = profilingUpdateFrequency;
}
/**
* 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 triggering garbage collection should be skipped on shutdown.
* You might set this when System.GC() slows a application shutdown too much.
*/
public boolean isSkipGarbageCollectionOnShutdown() {
return skipGarbageCollectionOnShutdown;
}
/**
* Set to true if triggering garbage collection should be skipped on shutdown.
* You might set this when System.GC() slows a application shutdown too much.
*/
public void setSkipGarbageCollectionOnShutdown(boolean skipGarbageCollectionOnShutdown) {
this.skipGarbageCollectionOnShutdown = skipGarbageCollectionOnShutdown;
}
/**
* Return true if profile reporting should be skipped on shutdown.
*/
public boolean isSkipProfileReportingOnShutdown() {
return skipProfileReportingOnShutdown;
}
/**
* Set to true if profile reporting should be skipped on shutdown.
*/
public void setSkipProfileReportingOnShutdown(boolean skipProfileReportingOnShutdown) {
this.skipProfileReportingOnShutdown = skipProfileReportingOnShutdown;
}
/**
* 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);
skipGarbageCollectionOnShutdown = p.getBoolean("autoTune.skipGarbageCollectionOnShutdown", skipGarbageCollectionOnShutdown);
skipProfileReportingOnShutdown = p.getBoolean("autoTune.skipProfileReportingOnShutdown", skipProfileReportingOnShutdown);
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);
profilingUpdateFrequency = p.getInt("autoTune.profilingUpdateFrequency", profilingUpdateFrequency);
}
}
@@ -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
}
@@ -0,0 +1,143 @@
package com.avaje.ebean.config;
/**
* Helper to find classes taking into account the context class loader.
*/
public class ClassLoadConfig {
protected final ClassLoaderContext context;
/**
* Construct with the default classLoader search with context classLoader first.
*/
public ClassLoadConfig() {
this(null);
}
/**
* Specify the classLoader to use for class detection and new instance creation.
*/
public ClassLoadConfig(ClassLoader classLoader) {
this.context = new ClassLoaderContext(classLoader);
}
/**
* Return true if the Java.time types are available and should be supported.
*/
public boolean isJavaTimePresent() {
return isPresent("java.time.LocalDate");
}
/**
* Return true if the Joda types are available and should be supported.
*/
public boolean isJodaTimePresent() {
return isPresent("org.joda.time.LocalDateTime");
}
/**
* Return true if javax validation annotations like Size and NotNull are present.
*/
public boolean isJavaxValidationAnnotationsPresent() {
return isPresent("javax.validation.constraints.NotNull");
}
/**
* Return true if Jackson annotations like JsonIgnore are present.
*/
public boolean isJacksonAnnotationsPresent() {
return isPresent("com.fasterxml.jackson.annotation.JsonIgnore");
}
/**
* Return true if Jackson ObjectMapper is present.
*/
public boolean isJacksonObjectMapperPresent() {
return isPresent("com.fasterxml.jackson.databind.ObjectMapper");
}
/**
* Return a new instance of the class using the default constructor.
*/
public Object newInstance(String className) {
try {
Class<?> cls = forName(className);
return cls.newInstance();
} catch (Exception e) {
throw new IllegalArgumentException("Error constructing " + className, e);
}
}
/**
* Return true if the given class is present.
*/
protected boolean isPresent(String className) {
try {
forName(className);
return true;
} catch (Throwable ex) {
// Class or one of its dependencies is not present...
return false;
}
}
/**
* Load a class taking into account a context class loader (if present).
*/
protected Class<?> forName(String name) throws ClassNotFoundException {
return context.forName(name);
}
/**
* Wraps the preferred, caller and context class loaders.
*/
protected class ClassLoaderContext {
/**
* Optional - if set only use this classLoader (no fallback).
*/
protected final ClassLoader preferredLoader;
protected final ClassLoader contextLoader;
protected final ClassLoader callerLoader;
ClassLoaderContext(ClassLoader preferredLoader) {
this.preferredLoader = preferredLoader;
this.callerLoader = ServerConfig.class.getClassLoader();
this.contextLoader = contextLoader();
}
ClassLoader contextLoader() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
return (loader != null) ? loader: callerLoader;
}
Class<?> forName(String name) throws ClassNotFoundException {
if (preferredLoader != null) {
// only use the explicitly set classLoader
return classForName(name, preferredLoader);
}
try {
// try the context loader first
return classForName(name, contextLoader);
} catch (ClassNotFoundException e) {
if (callerLoader == contextLoader) {
throw e;
} else {
// fallback to the caller classLoader
return classForName(name, callerLoader);
}
}
}
Class<?> classForName(String name, ClassLoader classLoader) throws ClassNotFoundException {
return Class.forName(name, true, classLoader);
}
}
}
@@ -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,393 @@
package com.avaje.ebean.config;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.config.dbplatform.DbPlatformName;
import com.avaje.ebean.dbmigration.DbMigration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Configuration for the DB migration processing.
*/
public class DbMigrationConfig {
protected static final Logger logger = LoggerFactory.getLogger(DbMigrationConfig.class);
/**
* The database platform to generate migration DDL for.
*/
protected DbPlatformName platform;
/**
* Set to true if the DB migration should be generated on server start.
*/
protected boolean generate;
/**
* Set to true to suppress the output of the rollback script.
*/
protected boolean suppressRollback;
/**
* The migration version name (typically FlywayDb compatible).
* <p>
* Example: 1.1.1_2
* <p>
* The version is expected to be the combination of the current pom version plus
* a 'feature' id. The combined version must be unique and ordered to work with
* FlywayDb so each developer sets a unique version so that the migration script
* generated is unique (typically just prior to being submitted as a merge request).
*/
protected String version;
/**
* Description text that can be appended to the version to become the ddl script file name.
* <p>
* So if the name is "a foo table" then the ddl script file could be:
* "1.1.1_2__a-foo-table.sql"
* <p>
* When the DB migration relates to a git feature (merge request) then this description text
* is a short description of the feature.
*/
protected String name;
/**
* Resource path for the migration xml and sql.
*/
protected String migrationPath = "dbmigration";
/**
* Subdirectory the model xml files go into.
*/
protected String modelPath = "model";
/**
* Subdirectory the drop ddl scripts go into.
*/
protected String dropPath = "drop";
/**
* Subdirectory the rollback ddl scripts go into.
*/
protected String rollbackPath = "rollback";
/**
* Apply script suffix.
*/
protected String applySuffix = ".sql";
/**
* Default drop script suffix to ddl so that it isn't picked up by FlywayDb.
*/
protected String dropSuffix = ".drop.ddl";
/**
* Default rollback script suffix to ddl so that it isn't picked up by FlywayDb.
*/
protected String rollbackSuffix = ".rollback.ddl";
protected String modelSuffix = ".model.xml";
/**
* Return the DB platform to generate migration DDL for.
*
* We typically need to explicitly specify this as migration can often be generated
* when running against H2.
*/
public DbPlatformName getPlatform() {
return platform;
}
/**
* Set the DB platform to generate migration DDL for.
*/
public void setPlatform(DbPlatformName platform) {
this.platform = platform;
}
/**
* Return the resource path for db migrations.
*/
public String getMigrationPath() {
return migrationPath;
}
/**
* Set the resource path for db migrations.
* <p>
* The default of "dbmigration" is reasonable in most cases. You may look to set this
* to 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 setMigrationPath(String migrationPath) {
this.migrationPath = migrationPath;
}
/**
* Return the relative path for the model files (defaults to model).
*/
public String getModelPath() {
return modelPath;
}
/**
* Set the relative path for the model files.
*/
public void setModelPath(String modelPath) {
this.modelPath = modelPath;
}
/**
* Return the relative path for the drop ddl scripts (defaults to drop).
*/
public String getDropPath() {
return dropPath;
}
/**
* Set the relative path for the drop ddl scripts (defaults to drop).
*/
public void setDropPath(String dropPath) {
this.dropPath = dropPath;
}
/**
* Return the relative path for the rollback ddl scripts (defaults to rollback).
*/
public String getRollbackPath() {
return rollbackPath;
}
/**
* Set the relative path for the rollback ddl scripts (defaults to rollback).
*/
public void setRollbackPath(String rollbackPath) {
this.rollbackPath = rollbackPath;
}
/**
* Return the model suffix (defaults to model.xml)
*/
public String getModelSuffix() {
return modelSuffix;
}
/**
* Set the model suffix.
*/
public void setModelSuffix(String modelSuffix) {
this.modelSuffix = modelSuffix;
}
/**
* Return true if the rollback script should not be output.
*/
public boolean isSuppressRollback() {
return suppressRollback;
}
/**
* Set to true to suppress the output of the rollback script.
*/
public void setSuppressRollback(boolean suppressRollback) {
this.suppressRollback = suppressRollback;
}
/**
* Return the apply script suffix (defaults to sql).
*/
public String getApplySuffix() {
return applySuffix;
}
/**
* Set the apply script suffix (defaults to sql).
*/
public void setApplySuffix(String applySuffix) {
this.applySuffix = applySuffix;
}
/**
* Return the drop script suffix (defaults to ddl so that it isn't picked up by FlywayDb).
*/
public String getDropSuffix() {
return dropSuffix;
}
/**
* Set the drop script suffix (defaults to ddl so that it isn't picked up by FlywayDb).
*/
public void setDropSuffix(String dropSuffix) {
this.dropSuffix = dropSuffix;
}
/**
* Return the rollback script suffix (defaults to ddl so that it isn't picked up by FlywayDb).
*/
public String getRollbackSuffix() {
return rollbackSuffix;
}
/**
* Set the rollback script suffix (defaults to ddl so that it isn't picked up by FlywayDb).
*/
public void setRollbackSuffix(String rollbackSuffix) {
this.rollbackSuffix = rollbackSuffix;
}
/**
* Set the migration version.
* <p>
* Note that version set via System property or environment variable <code>ddl.migration.version</code> takes precedence.
*/
public void setVersion(String version) {
this.version = version;
}
/**
* Set the migration name.
* <p>
* Note that name set via System property or environment variable <code>ddl.migration.name</code> takes precedence.
*/
public void setName(String name) {
this.name = name;
}
/**
* Set the model, rollback and drop paths to be empty such that all the migration files are generated
* into a single directory.
*/
public void singleDirectory() {
this.dropPath = "";
this.rollbackPath = "";
this.modelPath = "";
}
/**
* Load the settings from the PropertiesWrapper.
*/
public void loadSettings(PropertiesWrapper properties) {
migrationPath = properties.get("migration.migrationPath", migrationPath);
if (properties.getBoolean("migration.singleDirectory", false)) {
singleDirectory();
} else {
modelPath = properties.get("migration.modelPath", modelPath);
rollbackPath = properties.get("migration.rollbackPath", rollbackPath);
dropPath = properties.get("migration.dropPath", dropPath);
}
applySuffix = properties.get("migration.applySuffix", applySuffix);
dropSuffix = properties.get("migration.dropSuffix", dropSuffix);
rollbackSuffix = properties.get("migration.rollbackSuffix", rollbackSuffix);
modelSuffix = properties.get("migration.modelSuffix", modelSuffix);
platform = properties.getEnum(DbPlatformName.class, "migration.platform", platform);
suppressRollback = properties.getBoolean("migration.suppressRollback", suppressRollback);
generate = properties.getBoolean("migration.generate", generate);
version = properties.get("migration.version", version);
name = properties.get("migration.name", name);
}
/**
* Return true if the migration should be generated.
* <p>
* It is expected that when an environment variable <code>ddl.migration.enabled</code>
* is set to <code>true</code> then the DB migration will generate the migration DDL.
* </p>
*/
public boolean isGenerateOnStart() {
// environment properties take precedence
String envGenerate = readEnvironment("ddl.migration.generate");
if (envGenerate != null) {
return "true".equalsIgnoreCase(envGenerate.trim());
}
return generate;
}
/**
* Called by EbeanServer on start.
*
* <p>
* If enabled this generates the migration xml and DDL scripts.
* </p>
*/
public void generateOnStart(EbeanServer server) {
if (isGenerateOnStart()) {
if (platform == null) {
logger.warn("No platform set for migration DDL generation");
} else {
// generate the migration xml and platform specific DDL
DbMigration migration = new DbMigration(server);
migration.setPlatform(platform);
try {
migration.generateMigration();
} catch (Exception e) {
throw new RuntimeException("Error generating DB migration", e);
}
}
}
}
/**
* Return the migration version (typically FlywayDb compatible).
* <p>
* Example: 1.1.1_2
* <p>
* The version is expected to be the combination of the current pom version plus
* a 'feature' id. The combined version must be unique and ordered to work with
* FlywayDb so each developer sets a unique version so that the migration script
* generated is unique (typically just prior to being submitted as a merge request).
*/
public String getVersion() {
String envVersion = readEnvironment("ddl.migration.version");
if (!isEmpty(envVersion)) {
return envVersion.trim();
}
return version;
}
/**
* Return the migration name which is short description text that can be appended to
* the migration version to become the ddl script file name.
* <p>
* So if the name is "a foo table" then the ddl script file could be:
* "1.1.1_2__a-foo-table.sql"
* </p>
* <p>
* When the DB migration relates to a git feature (merge request) then this description text
* is a short description of the feature.
* </p>
*/
public String getName() {
String envName = readEnvironment("ddl.migration.name");
if (!isEmpty(envName)) {
return envName.trim();
}
return name;
}
/**
* Return the system or environment property.
*/
protected String readEnvironment(String key) {
String val = System.getProperty(key);
if (val == null) {
val = System.getenv(key);
}
return val;
}
/**
* Return true if the string is null or empty.
*/
protected boolean isEmpty(String val) {
return val == null || val.trim().isEmpty();
}
}
@@ -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;
@@ -141,8 +141,8 @@ public class PropertiesWrapper {
* Return a Enum property value.
*/
public <T extends Enum<T>> T getEnum(Class<T> enumType, String key, T defaultValue) {
String level = get(key, defaultValue.name());
return Enum.valueOf(enumType, level.toUpperCase());
String level = get(key, null);
return (level == null) ? defaultValue : Enum.valueOf(enumType, level.toUpperCase());
}
}
@@ -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");
}
/**
* 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);
if (loadTestProperties) {
// load test properties if present in classpath
map = load(map, "test-ebean.properties");
}
return map;
}
/**
@@ -39,7 +56,6 @@ final class PropertyMapLoader {
InputStream is = findInputStream(fileName);
if (is == null) {
logger.error(fileName + " not found");
return p;
} else {
return load(p, is);
@@ -47,7 +63,7 @@ final class PropertyMapLoader {
}
/**
* Load the inputstream returning the property map.
* Load the InputStream returning the property map.
*
* @param p
* an existing property map to load into.
@@ -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);
}
@@ -7,9 +7,20 @@ import com.avaje.ebean.cache.ServerCacheFactory;
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.BeanFindController;
import com.avaje.ebean.event.BeanPersistController;
import com.avaje.ebean.event.BeanPersistListener;
import com.avaje.ebean.event.BeanPostLoad;
import com.avaje.ebean.event.BeanQueryAdapter;
import com.avaje.ebean.event.BulkTableEventListener;
import com.avaje.ebean.event.ServerConfigStartup;
import com.avaje.ebean.event.TransactionEventListener;
import com.avaje.ebean.event.changelog.ChangeLogListener;
import com.avaje.ebean.event.changelog.ChangeLogPrepare;
import com.avaje.ebean.event.changelog.ChangeLogRegister;
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;
import javax.sql.DataSource;
@@ -70,6 +81,11 @@ public class ServerConfig {
private ContainerConfig containerConfig;
/**
* The underlying properties that were used during configuration.
*/
private Properties properties;
/**
* The resource directory.
*/
@@ -120,9 +136,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 +178,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.
*/
@@ -190,6 +212,12 @@ public class ServerConfig {
private boolean ddlRun;
private boolean ddlCreateOnly;
private String ddlInitSql;
private String ddlSeedSql;
private boolean useJtaTransactionManager;
/**
@@ -198,11 +226,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 +235,28 @@ public class ServerConfig {
*/
private DataSourceConfig dataSourceConfig = new DataSourceConfig();
/**
* The db migration config (migration resource path etc).
*/
private DbMigrationConfig migrationConfig = new DbMigrationConfig();
/**
* The ClassLoadConfig used to detect Joda, Java8, Jackson etc and create plugin instances given a className.
*/
private ClassLoadConfig classLoadConfig = new ClassLoadConfig();
/**
* 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 +277,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 +298,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 +381,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 +564,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 +682,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 +833,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 +1152,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 +1242,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 +1483,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;
}
/**
@@ -1327,19 +1535,81 @@ public class ServerConfig {
}
/**
* Set to true to run the DDL generation on startup.
* Set to true to generate the "create all" DDL on startup.
*
* Typically we want this on when we are running tests locally (and often using H2)
* and we want to create the full DB schema from scratch to run tests.
*/
public void setDdlGenerate(boolean ddlGenerate) {
this.ddlGenerate = ddlGenerate;
}
/**
* Set to true to run the generated DDL on startup.
* Set to true to run the generated "create all DDL" on startup.
*
* Typically we want this on when we are running tests locally (and often using H2)
* and we want to create the full DB schema from scratch to run tests.
*/
public void setDdlRun(boolean ddlRun) {
this.ddlRun = ddlRun;
}
/**
* Return true if the "drop all ddl" should be skipped.
*
* Typically we want to do this when using H2 (in memory) as our test database and the drop statements
* are not required so skipping the drop table statements etc makes it faster with less noise in the logs.
*/
public boolean isDdlCreateOnly() {
return ddlCreateOnly;
}
/**
* Set to true if the "drop all ddl" should be skipped.
*
* Typically we want to do this when using H2 (in memory) as our test database and the drop statements
* are not required so skipping the drop table statements etc makes it faster with less noise in the logs.
*/
public void setDdlCreateOnly(boolean ddlCreateOnly) {
this.ddlCreateOnly = ddlCreateOnly;
}
/**
* Return SQL script to execute after the "create all" DDL has been run.
* <p>
* Typically this is a sql script that inserts test seed data when running tests.
* Place a sql script in src/test/resources that inserts test seed data.
* </p>
*/
public String getDdlSeedSql() {
return ddlSeedSql;
}
/**
* Set a SQL script to execute after the "create all" DDL has been run.
* <p>
* Typically this is a sql script that inserts test seed data when running tests.
* Place a sql script in src/test/resources that inserts test seed data.
* </p>
*/
public void setDdlSeedSql(String ddlSeedSql) {
this.ddlSeedSql = ddlSeedSql;
}
/**
* Return a SQL script to execute before the "create all" DDL has been run.
*/
public String getDdlInitSql() {
return ddlInitSql;
}
/**
* Set a SQL script to execute before the "create all" DDL has been run.
*/
public void setDdlInitSql(String ddlInitSql) {
this.ddlInitSql = ddlInitSql;
}
/**
* Return true if the DDL should be generated.
*/
@@ -1660,14 +1930,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.
*/
@@ -1801,6 +2102,22 @@ public class ServerConfig {
this.persistenceContextScope = persistenceContextScope;
}
/**
* Return the ClassLoadConfig which is used to detect Joda, Java8 types etc and also
* create new instances of plugins given a className.
*/
public ClassLoadConfig getClassLoadConfig() {
return classLoadConfig;
}
/**
* Set the ClassLoadConfig which is used to detect Joda, Java8 types etc and also
* create new instances of plugins given a className.
*/
public void setClassLoadConfig(ClassLoadConfig classLoadConfig) {
this.classLoadConfig = classLoadConfig;
}
/**
* Load settings from ebean.properties.
*/
@@ -1812,16 +2129,59 @@ 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;
}
/**
* Return the instance to use (can be null) for the given plugin.
*
* @param properties the properties
* @param pluginType the type of plugin
* @param key properties key
* @param instance existing instance
*/
@SuppressWarnings("unchecked")
private <T> T createInstance(PropertiesWrapper p, Class<T> pluginType, String key) {
protected <T> T createInstance(PropertiesWrapper properties, Class<T> pluginType, String key, T instance) {
String classname = p.get(key, null);
return classname == null ? null : (T) ClassUtil.newInstance(classname);
if (instance != null) {
return instance;
}
String classname = properties.get(key, null);
return createInstance(pluginType, classname);
}
/**
* Return the instance to use (can be null) for the given plugin.
* @param pluginType the type of plugin
* @param classname the implementation class as per properties
*/
protected <T> T createInstance(Class<T> pluginType, String classname) {
return classname == null ? null : (T) classLoadConfig.newInstance(classname);
}
/**
@@ -1838,8 +2198,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 +2207,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 +2270,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);
@@ -1932,13 +2300,16 @@ public class ServerConfig {
ddlGenerate = p.getBoolean("ddl.generate", ddlGenerate);
ddlRun = p.getBoolean("ddl.run", ddlRun);
ddlCreateOnly = p.getBoolean("ddl.createOnly", ddlCreateOnly);
ddlInitSql = p.get("ddl.initSql", ddlInitSql);
ddlSeedSql = p.get("ddl.seedSql", ddlSeedSql);
classes = getClasses(p);
}
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 +2391,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 +2409,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");
}
/**
@@ -17,7 +17,7 @@ public class DB2SequenceIdGenerator extends SequenceIdGenerator {
*/
public DB2SequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
super(be, ds, seqName, batchSize);
this.baseSql = "select nextval for " + seqName;
this.baseSql = "values nextval for " + seqName;
this.unionBaseSql = " union " + baseSql;
}
@@ -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 {
}

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