Compare commits

...
57 Commits
Author SHA1 Message Date
Rob Bygrave f34e7b6003 Version 13.26.0 2024-01-20 22:01:30 +13:00
Rob BygraveandGitHub 089dd8e364 Merge pull request #3311 from ebean-orm/feature/findSingleAttributeOrEmpty
enh: Add findSingleAttributeOrEmpty() returning Optional
2024-01-19 15:23:27 +13:00
Rob Bygrave 44770382fb enh: Add findSingleAttributeOrEmpty() returning Optional 2024-01-19 10:41:54 +13:00
Rob BygraveandGitHub 2a62d413cc Merge pull request #3308 from Incanus3/fix/querybean_or_with_exists
fix TQRootBean.exists() when used with .or()
2024-01-19 08:29:29 +13:00
Rob Bygrave 0046d983cb Adjust test such that table alias does not clash
The .raw("contact.customer_id = customer.id") clashes as "customer.id" is
a logical path from contact
2024-01-19 08:14:58 +13:00
Jakub Kaláb 2e1b52d7d4 WIP: fix TQRootBean.exists() when used with .or() 2024-01-18 11:32:34 +01:00
Rob BygraveandGitHub 09d5163396 Merge pull request #3307 from ebean-orm/feature/bump-avaje-config-310
Bump avaje-config to version 3.10
2024-01-18 22:30:42 +13:00
Rob Bygrave a6a38b9a92 Bump avaje-config to version 3.10 2024-01-18 22:30:09 +13:00
Rob BygraveandGitHub bd4521b240 Merge pull request #3306 from ebean-orm/feature/querybean-deprecated
Add forRemoval=true for existing Deprecated methods in query beans
2024-01-18 22:28:23 +13:00
Rob Bygrave 8a7379879b Add forRemoval=true for existing Deprecated methods in query beans 2024-01-18 20:15:57 +13:00
Rob BygraveandGitHub b78dd6f79a Merge pull request #3304 from ebean-orm/feature/3296-querybean-copy
#3296 Add copy() method to query beans
2024-01-15 22:38:30 +13:00
Rob Bygrave 4ebb5fd112 #3296 Add copy() method to query beans 2024-01-15 22:30:17 +13:00
Rob Bygrave 487368976f Tidy SimpleQueryBeanWriter internals 2024-01-15 22:03:17 +13:00
Rob Bygrave c6defceec9 Add additional test for filterMany() with fetch() 2024-01-15 21:02:47 +13:00
Rob BygraveandGitHub 8ed3b765ec Merge pull request #3299 from ebean-orm/feature/3294-warnings
#3294 Suppress compiler warnings on generated query bean `filterMany()`
2023-12-22 08:33:31 +13:00
Rob BygraveandGitHub fcbcc53e27 Merge pull request #3298 from ebean-orm/feature/add-usingConnection-dtoQuery
Add usingConnection() to DtoQuery and SqlQuery
2023-12-22 08:25:48 +13:00
Rob Bygrave b377e1a618 #3294 Suppress compiler warnings on generated query bean filterMany() 2023-12-22 08:24:54 +13:00
Rob Bygrave a0f612ed71 Add usingConnection() to DtoQuery and SqlQuery
For the case where we have a java.sql.Connection and wish
to execute a DtoQuery or SqlQuery using that connection.
2023-12-21 21:24:02 +13:00
Rob Bygrave 47e97a77a8 Version 13.25.2 2023-12-07 20:18:40 +13:00
Rob Bygrave e8d3f50bb4 Bump ebean-agent to 13.25.2 2023-12-07 19:57:55 +13:00
Rob BygraveandGitHub 716cfaf938 Merge pull request #3286 from ebean-orm/feature/dbarray-instant-and-localdate
Add support for LocalDate and Instant with DbArray
2023-12-07 08:57:40 +13:00
robin.bygrave 7cd9e5ee03 Add support for LocalDate and Instant with DbArray 2023-12-06 14:54:30 +13:00
Rob Bygrave f9c9bea623 Follow up for #3248 - add betweenProperties on query bean 2023-12-06 00:40:57 +13:00
Rob Bygrave 720832122c Follow up for #3248 - add betweenProperties on query bean 2023-12-05 23:32:16 +13:00
Rob BygraveandGitHub 7b635acf56 Merge pull request #3284 from raphaelNguyen/master
Expose betweenProperties on query bean
2023-12-05 23:21:26 +13:00
Raphael Nguyen 6b7efe65d7 Expose betweenProperties on query bean 2023-12-05 15:08:16 +11:00
Rob BygraveandGitHub 03cd4000f0 Merge pull request #3282 from ebean-orm/dependabot/maven/ch.qos.logback-logback-classic-1.3.12
Bump ch.qos.logback:logback-classic from 1.2.11 to 1.3.12
2023-11-30 13:59:21 +13:00
Rob BygraveandGitHub dfd6434b59 Merge pull request #3281 from ebean-orm/dependabot/maven/tests/test-java16/ch.qos.logback-logback-classic-1.3.12
Bump ch.qos.logback:logback-classic from 1.2.11 to 1.3.12 in /tests/test-java16
2023-11-30 13:59:08 +13:00
Rob BygraveandGitHub 4e7480237b Merge pull request #3283 from ebean-orm/dependabot/maven/tests/test-kotlin/ch.qos.logback-logback-classic-1.3.12
Bump ch.qos.logback:logback-classic from 1.2.11 to 1.3.12 in /tests/test-kotlin
2023-11-30 13:58:52 +13:00
dependabot[bot]andGitHub 9bfcf07486 Bump ch.qos.logback:logback-classic in /tests/test-kotlin
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.2.11 to 1.3.12.
- [Commits](https://github.com/qos-ch/logback/compare/v_1.2.11...v_1.3.12)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-29 22:15:53 +00:00
dependabot[bot]andGitHub b1f1344057 Bump ch.qos.logback:logback-classic from 1.2.11 to 1.3.12
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.2.11 to 1.3.12.
- [Commits](https://github.com/qos-ch/logback/compare/v_1.2.11...v_1.3.12)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-29 22:13:26 +00:00
dependabot[bot]andGitHub 07201c1519 Bump ch.qos.logback:logback-classic in /tests/test-java16
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.2.11 to 1.3.12.
- [Commits](https://github.com/qos-ch/logback/compare/v_1.2.11...v_1.3.12)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-29 22:13:04 +00:00
Rob BygraveandGitHub 455a9fdffc Merge pull request #3280 from ebean-orm/feature/typequery-imports-tqrootbean
QueryBean generation - use full class names for TQRootBean, TQAssocBean
2023-11-29 01:21:00 +13:00
Rob Bygrave 3f67425727 QueryBean generation - conditionally fully qualify the property types
If there is an entity bean short name clash like PString, PLong, etc then
fully qualify all the property types in the generated code, otherwise use
imports for the property types.
2023-11-29 00:46:56 +13:00
Rob Bygrave 3fd9ae06db QueryBean generation - use fully qualify use of DB 2023-11-29 00:22:45 +13:00
Rob Bygrave a8ce726e47 QueryBean generation - use full class names for TQRootBean, TQAssocBean
Rather than imports, such that these are not possible name clashes with
beans of the exact same name.
2023-11-28 21:51:07 +13:00
Rob BygraveandGitHub 29cd1a143d Merge pull request #3277 from ebean-orm/feature/bump-datasource2
Bump ebean-datasource to 8.11 with support for Driver by class
2023-11-23 23:34:23 +13:00
Rob Bygrave 6a19c6a0ce Bump ebean-datasource to 8.11 with support for Driver by class
- Can specify explicit driver by class or instance
- Can use a DataSource as connection source
2023-11-23 23:31:29 +13:00
Rob BygraveandGitHub eaec515cc1 Merge pull request #3276 from ebean-orm/feature/skipCheckForReadOnly
skipDataSourceCheck() when using readOnlyDatabase
2023-11-23 23:27:21 +13:00
Rob Bygrave 97709d3493 skipDataSourceCheck() when using readOnlyDatabase
As we don't want the warning logged in this case:
DataSource [{0}] has autoCommit defaulting to true!
2023-11-23 23:23:53 +13:00
Rob Bygrave 87ad874621 Read the readOnlyDatabase property via loadSettings() 2023-11-23 23:15:58 +13:00
Rob Bygrave dfe95f6fc0 Version 13.25.1 2023-11-22 17:50:09 +13:00
Rob Bygrave 05feccfeb6 Bump ebean-agent 2023-11-22 17:46:54 +13:00
Rob BygraveandGitHub 196cb09c66 Merge pull request #3274 from ebean-orm/feature/3269
#3268 - @DbComment on @ManyToOne fields are ignored (ddl-generator)
2023-11-21 23:54:26 +13:00
Rob Bygrave 589e198301 #3268 - @DbComment on @ManyToOne fields are ignored (ddl-generator) 2023-11-21 23:53:29 +13:00
Rob BygraveandGitHub b2b81677e8 Merge pull request #3273 from ebean-orm/feature/3269
#3269 - @JoinColumns set ForeignKey is none in ddl , but is not work
2023-11-21 23:42:06 +13:00
Rob Bygrave f032aad22e #3269 - @JoinColumns set ForeignKey is none in ddl , but is not work 2023-11-21 23:40:21 +13:00
Rob Bygrave c48e5428c5 #3265 Fix for Update Query logging to trim large values in bind log 2023-11-21 22:32:35 +13:00
Rob Bygrave cbca940611 Merge branch 'FOCONIS-findsingleattribute-beanfindcontroller' 2023-11-21 22:05:12 +13:00
Rob Bygrave 0da3772ae9 #3270 Fix for use with BeanFindController and attribute queries
The existence of a BeanFindController should not break the use of
single attribute queries + still allow auto-tuning.
2023-11-21 22:04:47 +13:00
Rob Bygrave 496ef36b11 Merge branch 'findsingleattribute-beanfindcontroller' of github.com:FOCONIS/ebean into FOCONIS-findsingleattribute-beanfindcontroller 2023-11-21 21:40:09 +13:00
Rob BygraveandGitHub a4a2aba56f Merge pull request #3272 from ebean-orm/feature/readOnlyDatabase
Refactor tidy internals of DbPrimary, DatabaseFactory, ContainerConfi…
2023-11-21 21:20:35 +13:00
Rob Bygrave 803f1d8642 Refactor tidy internals of DbPrimary, DatabaseFactory, ContainerConfig, ClusterManager 2023-11-20 22:18:53 +13:00
Rob BygraveandGitHub ff1c73e20d Merge pull request #3266 from ebean-orm/feature/readOnlyDatabase
Add read only database configuration/builder option
2023-11-17 14:10:51 +13:00
Noemi Praml 7afd37cd98 Failing Tests with CustomerFindController 2023-11-14 17:05:42 +01:00
Rob Bygrave 24bb364d40 Add read only database configuration/builder option
When using DatabaseBuilder.readOnlyDatabase(true) then
ebean will:
- Set the DataSourceBuilder to use autoCommit=true and readOnly=true
- Use the same DataSource instance for both dataSource and readOnlyDataSource

This is to simplify the setup/configuration for creating a Database that
will only have read-only use.

Note that readOnly=true is a JDBC hint and for example H2 database effectively
ignores that hint where as Postgres will enforce the read-only true nature.
2023-11-13 23:12:05 +13:00
Rob Bygrave 5d54a238bd Bump ebean-agent to 13.25.0 2023-11-06 20:09:35 +13:00
112 changed files with 1101 additions and 457 deletions
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -22,13 +22,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -47,19 +47,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -41,7 +41,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -60,13 +60,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<artifactId>composites</artifactId>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<name>ebean api</name>
@@ -39,7 +39,7 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-config</artifactId>
<version>3.9</version>
<version>3.10</version>
</dependency>
<dependency>
@@ -1053,6 +1053,14 @@ public interface DatabaseBuilder {
@Deprecated
DatabaseBuilder setSkipDataSourceCheck(boolean skipDataSourceCheck);
/**
* Set to true if this database is used in a read only way.
* <p>
* The DataSource and read-only DataSource are expected to be the same
* and use readOnly=true and autoCommit=true.
*/
DatabaseBuilder readOnlyDatabase(boolean readOnlyDatabase);
/**
* Set a DataSource.
*/
@@ -2607,6 +2615,14 @@ public interface DatabaseBuilder {
*/
boolean skipDataSourceCheck();
/**
* Return true if this database is used in a read only way.
* <p>
* The DataSource and read-only DataSource are expected to be the same
* and use readOnly=true and autoCommit=true.
*/
boolean readOnlyDatabase();
/**
* Return the DataSource.
*/
@@ -3,10 +3,9 @@ package io.ebean;
import io.ebean.config.ContainerConfig;
import io.ebean.service.SpiContainer;
import io.ebean.service.SpiContainerFactory;
import jakarta.persistence.PersistenceException;
import java.util.Iterator;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.concurrent.locks.ReentrantLock;
@@ -146,12 +145,9 @@ public final class DatabaseFactory {
if (container != null) {
return container;
}
if (containerConfig == null) {
// effectively load configuration from ebean.properties
Properties properties = DbPrimary.getProperties();
containerConfig = new ContainerConfig();
containerConfig.loadFromProperties(properties);
}
container = createContainer(containerConfig);
return container;
@@ -160,7 +156,7 @@ public final class DatabaseFactory {
/**
* Create the container instance using the configuration.
*/
protected static SpiContainer createContainer(ContainerConfig containerConfig) {
private static SpiContainer createContainer(ContainerConfig containerConfig) {
Iterator<SpiContainerFactory> factories = ServiceLoader.load(SpiContainerFactory.class).iterator();
if (factories.hasNext()) {
return factories.next().create(containerConfig);
@@ -44,25 +44,12 @@ final class DbPrimary {
* Return the default database name.
*/
static String getDefaultServerName() {
lock.lock();
try {
getProperties();
return defaultServerName;
} finally {
lock.unlock();
}
}
/**
* Return the default configuration Properties.
*/
static Properties getProperties() {
lock.lock();
try {
if (defaultServerName == null) {
defaultServerName = determineDefaultServerName();
}
return Config.asProperties();
return defaultServerName;
} finally {
lock.unlock();
}
@@ -3,6 +3,8 @@ package io.ebean;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import javax.sql.DataSource;
import java.sql.Connection;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
@@ -206,14 +208,19 @@ public interface DtoQuery<T> extends CancelableQuery {
*/
DtoQuery<T> usingTransaction(Transaction transaction);
/**
* Execute the query using the given connection.
*/
DtoQuery<T> usingConnection(Connection connection);
/**
* Ensure that the master DataSource is used if there is a read only data source
* being used (that is using a read replica database potentially with replication lag).
* <p>
* When the database is configured with a read-only DataSource via
* say {@link io.ebean.config.DatabaseConfig#setReadOnlyDataSource(DataSource)} then
* say {@link io.ebean.DatabaseBuilder#readOnlyDataSource(DataSource)} then
* by default when a query is run without an active transaction, it uses the read-only data
* source. We we use {@code usingMaster()} to instead ensure that the query is executed
* source. We use {@code usingMaster()} to instead ensure that the query is executed
* against the master data source.
*/
DtoQuery<T> usingMaster();
+21 -2
View File
@@ -702,9 +702,9 @@ public interface Query<T> extends CancelableQuery {
* being used (that is using a read replica database potentially with replication lag).
* <p>
* When the database is configured with a read-only DataSource via
* say {@link io.ebean.config.DatabaseConfig#setReadOnlyDataSource(DataSource)} then
* say {@link io.ebean.DatabaseBuilder#readOnlyDataSource(DataSource)} then
* by default when a query is run without an active transaction, it uses the read-only data
* source. We we use {@code usingMaster()} to instead ensure that the query is executed
* source. We use {@code usingMaster()} to instead ensure that the query is executed
* against the master data source.
*/
Query<T> usingMaster();
@@ -970,6 +970,25 @@ public interface Query<T> extends CancelableQuery {
@Nullable
<A> A findSingleAttribute();
/**
* Execute the query returning a single optional attribute value.
* <p>
* <h3>Example</h3>
* <pre>{@code
*
* Optional<String> maybeName =
* new QCustomer()
* .select(name)
* .id.eq(42)
* .status.eq(NEW)
* .findSingleAttributeOrEmpty();
*
* }</pre>
*
* @return an optional value for the selected property
*/
<A> Optional<A> findSingleAttributeOrEmpty();
/**
* Return true if this is countDistinct query.
*/
@@ -3,7 +3,9 @@ package io.ebean;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import javax.sql.DataSource;
import java.io.Serializable;
import java.sql.Connection;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
@@ -45,14 +47,19 @@ public interface SqlQuery extends Serializable, CancelableQuery {
*/
SqlQuery usingTransaction(Transaction transaction);
/**
* Execute the query using the given connection.
*/
SqlQuery usingConnection(Connection connection);
/**
* Ensure that the master DataSource is used if there is a read only data source
* being used (that is using a read replica database potentially with replication lag).
* <p>
* When the database is configured with a read-only DataSource via
* say {@link io.ebean.config.DatabaseConfig#setReadOnlyDataSource(DataSource)} then
* say {@link io.ebean.DatabaseBuilder#readOnlyDataSource(DataSource)}then
* by default when a query is run without an active transaction, it uses the read-only data
* source. We we use {@code usingMaster()} to instead ensure that the query is executed
* source. We use {@code usingMaster()} to instead ensure that the query is executed
* against the master data source.
*/
SqlQuery usingMaster();
@@ -1,5 +1,8 @@
package io.ebean.config;
import io.avaje.config.Config;
import io.avaje.config.Configuration;
import java.util.Properties;
/**
@@ -15,8 +18,17 @@ public class ContainerConfig {
private String namespace;
private String podName;
private int port;
private Properties properties;
private Configuration configuration;
public ContainerConfig() {
this.configuration = Config.asConfiguration();
this.active = configuration.getBool("ebean.cluster.active", active);
this.serviceName = configuration.getNullable("ebean.cluster.serviceName", serviceName);
this.namespace = configuration.getNullable("ebean.cluster.namespace", namespace);
this.podName = configuration.getNullable("ebean.cluster.podName", podName);
this.port = configuration.getInt("ebean.cluster.port", 0);
}
/**
* Return the service name.
@@ -92,7 +104,7 @@ public class ContainerConfig {
* Return the deployment properties.
*/
public Properties getProperties() {
return properties;
return properties != null ? properties : configuration.asProperties();
}
/**
@@ -102,26 +114,4 @@ public class ContainerConfig {
this.properties = properties;
}
/**
* Load the settings from properties.
*/
public void loadFromProperties(Properties properties) {
this.properties = properties;
this.active = getProperty(properties, "ebean.cluster.active", active);
this.serviceName = properties.getProperty("ebean.cluster.serviceName", serviceName);
this.namespace = properties.getProperty("ebean.cluster.namespace", namespace);
this.podName = properties.getProperty("ebean.cluster.podName", podName);
String portParam = properties.getProperty("ebean.cluster.port");
if (portParam != null) {
this.port = Integer.parseInt(portParam);
}
}
/**
* Return the boolean property setting.
*/
protected boolean getProperty(Properties properties, String key, boolean defaultValue) {
return "true".equalsIgnoreCase(properties.getProperty(key, Boolean.toString(defaultValue)));
}
}
@@ -304,6 +304,8 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
private boolean skipDataSourceCheck;
private boolean readOnlyDatabase;
/**
* The data source (if programmatically provided).
*/
@@ -1334,7 +1336,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
@Override
public boolean skipDataSourceCheck() {
return skipDataSourceCheck;
return skipDataSourceCheck || readOnlyDatabase;
}
@Override
@@ -1343,6 +1345,17 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
return this;
}
@Override
public DatabaseBuilder readOnlyDatabase(boolean readOnlyDatabase) {
this.readOnlyDatabase = readOnlyDatabase;
return this;
}
@Override
public boolean readOnlyDatabase() {
return readOnlyDatabase;
}
@Override
public DataSource getDataSource() {
return dataSource;
@@ -2115,6 +2128,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
loadDocStoreSettings(p);
defaultServer = p.getBoolean("defaultServer", defaultServer);
readOnlyDatabase = p.getBoolean("readOnlyDatabase", readOnlyDatabase);
autoPersistUpdates = p.getBoolean("autoPersistUpdates", autoPersistUpdates);
loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo);
maxCallStack = p.getInt("maxCallStack", maxCallStack);
@@ -21,9 +21,4 @@ class DbPrimaryTest {
assertEquals("h2", DbPrimary.getDefaultServerName());
}
@Test
void testLoadProperties() {
Properties properties = DbPrimary.getProperties();
assertFalse(properties.isEmpty());
}
}
@@ -74,6 +74,7 @@ class DatabaseConfigTest {
props.setProperty("forUpdateNoKey", "true");
props.setProperty("defaultServer", "false");
props.setProperty("skipDataSourceCheck", "true");
props.setProperty("readOnlyDatabase", "true");
props.setProperty("queryPlan.enable", "true");
props.setProperty("queryPlan.thresholdMicros", "10000");
@@ -93,6 +94,7 @@ class DatabaseConfigTest {
assertTrue(settings.isAutoLoadModuleInfo());
assertTrue(settings.isLoadModuleInfo());
assertTrue(settings.skipDataSourceCheck());
assertTrue(settings.readOnlyDatabase());
assertTrue(settings.isIdGeneratorAutomatic());
assertFalse(settings.getPlatformConfig().isCaseSensitiveCollation());
+26 -26
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<name>ebean bom</name>
@@ -89,25 +89,25 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -125,13 +125,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -155,37 +155,37 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-spring-txn</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<!-- platforms -->
@@ -193,79 +193,79 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-clickhouse</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-db2</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-h2</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-hana</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mariadb</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mysql</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-nuodb</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-oracle</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgres</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlite</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlserver</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
+6 -6
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -22,7 +22,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -46,7 +46,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -159,21 +159,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
@@ -5,7 +5,6 @@ import io.ebean.Database;
import io.ebean.config.ContainerConfig;
import io.ebeaninternal.server.transaction.RemoteTransactionEvent;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
@@ -20,38 +19,22 @@ public class ClusterManager implements ServerLookup {
private static final System.Logger clusterLogger = AppLog.getLogger("io.ebean.Cluster");
private final ReentrantLock lock = new ReentrantLock();
private final ConcurrentHashMap<String, Database> serverMap = new ConcurrentHashMap<>();
private final Object monitor = new Object();
private final ClusterBroadcast broadcast;
private boolean started;
private boolean shutdown;
public ClusterManager(ContainerConfig config) {
ClusterBroadcastFactory factory = createFactory();
if (factory != null && config.isActive()) {
broadcast = factory.create(this, config);
if (config.isActive()) {
ClusterBroadcastFactory factory = createFactory();
broadcast = factory != null ? factory.create(this, config) : null;
} else {
broadcast = null;
}
}
/**
* Return the ClusterTransportFactory via ServiceLoader.
*/
private ClusterBroadcastFactory createFactory() {
ServiceLoader<ClusterBroadcastFactory> load = ServiceLoader.load(ClusterBroadcastFactory.class);
ClusterBroadcastFactory factory = null;
Iterator<ClusterBroadcastFactory> iterator = load.iterator();
if (iterator.hasNext()) {
factory = iterator.next();
}
return factory;
return ServiceLoader.load(ClusterBroadcastFactory.class).findFirst().orElse(null);
}
public void registerServer(Database server) {
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.core;
import io.ebean.Database;
import io.ebean.DatabaseBuilder;
import io.ebean.config.*;
import io.ebean.config.dbplatform.DatabasePlatform;
@@ -13,11 +14,13 @@ import io.ebeaninternal.server.cluster.ClusterManager;
import io.ebeaninternal.server.core.bootup.BootupClassPathSearch;
import io.ebeaninternal.server.core.bootup.BootupClasses;
import io.ebeaninternal.server.executor.DefaultBackgroundExecutor;
import jakarta.persistence.PersistenceException;
import java.net.URL;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
@@ -33,12 +36,22 @@ public final class DefaultContainer implements SpiContainer {
private final ReentrantLock lock = new ReentrantLock();
private final ClusterManager clusterManager;
private final List<EntityClassRegister> entityClassRegisters;
public DefaultContainer(ContainerConfig containerConfig) {
this.clusterManager = new ClusterManager(containerConfig);
// register so that we can shutdown any Ebean wide
// resources such as clustering
ShutdownManager.registerContainer(this);
entityClassRegisters = initEntityRegisters();
}
private List<EntityClassRegister> initEntityRegisters() {
var entityClassRegisters = new ArrayList<EntityClassRegister>();
for (EntityClassRegister entityClassRegister : ServiceLoader.load(EntityClassRegister.class)) {
entityClassRegisters.add(entityClassRegister);
}
return entityClassRegisters;
}
@Override
@@ -52,10 +65,8 @@ public final class DefaultContainer implements SpiContainer {
*/
@Override
public SpiEbeanServer createServer(String name) {
DatabaseBuilder config = new DatabaseConfig();
config.setName(name);
config.loadFromProperties();
return createServer(config);
var builder = Database.builder().name(name).loadFromProperties();
return createServer(builder);
}
private SpiBackgroundExecutor createBackgroundExecutor(DatabaseBuilder builder) {
@@ -82,7 +93,7 @@ public final class DefaultContainer implements SpiContainer {
boolean online = true;
if (config.isDocStoreOnly()) {
config.setDatabasePlatform(new DatabasePlatform());
config.databasePlatform(new DatabasePlatform());
} else {
TenantMode tenantMode = config.getTenantMode();
if (TenantMode.DB != tenantMode) {
@@ -126,12 +137,10 @@ public final class DefaultContainer implements SpiContainer {
}
if (config.isLoadModuleInfo()) {
// auto register entity classes
boolean found = false;
for (EntityClassRegister loader : ServiceLoader.load(EntityClassRegister.class)) {
for (EntityClassRegister loader : entityClassRegisters) {
config.addAll(loader.classesFor(config.getName(), config.isDefaultServer()));
found = true;
}
if (!found) {
if (entityClassRegisters.isEmpty()) {
checkMissingModulePathProvides();
}
}
@@ -193,7 +202,7 @@ public final class DefaultContainer implements SpiContainer {
*/
private void setNamingConvention(DatabaseBuilder.Settings config) {
if (config.getNamingConvention() == null) {
config.setNamingConvention(new UnderscoreNamingConvention());
config.namingConvention(new UnderscoreNamingConvention());
}
}
@@ -208,7 +217,7 @@ public final class DefaultContainer implements SpiContainer {
}
// automatically determine the platform
platform = new DatabasePlatformFactory().create(config);
config.setDatabasePlatform(platform);
config.databasePlatform(platform);
}
platform.configure(config.getPlatformConfig());
}
@@ -232,11 +241,9 @@ public final class DefaultContainer implements SpiContainer {
* Check the autoCommit and Transaction Isolation levels of the DataSource.
* <p>
* If autoCommit is true this could be a real problem.
* </p>
* <p>
* If the Isolation level is not READ_COMMITTED then optimistic concurrency
* checking may not work as expected.
* </p>
*/
private boolean checkDataSource(DatabaseBuilder.Settings config) {
if (isOfflineMode(config)) {
@@ -961,7 +961,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
if (!query.isRawSql()) {
query.setDefaultRawSqlIfRequired();
if (query.isAutoTunable() && !autoTuneService.tuneQuery(query)) {
if (!query.isAutoTunable() || !autoTuneService.tuneQuery(query)) {
// use deployment FetchType.LAZY/EAGER annotations
// to define the 'default' select clause
query.setDefaultSelectClause();
@@ -38,15 +38,19 @@ final class InitDataSource {
* Initialise the "main" read write DataSource from configuration.
*/
private DataSource initDataSource() {
return createFromConfig(config.getDataSourceConfig(), false);
return createFromConfig(config.getDataSourceConfig(), config.readOnlyDatabase(), false);
}
/**
* Initialise the "read only" DataSource from configuration.
*/
private DataSource initReadOnlyDataSource() {
if (config.readOnlyDatabase()) {
// using the same DataSource instance
return config.getDataSource();
}
var roConfig = readOnlyConfig();
return roConfig == null ? null : createFromConfig(roConfig, true);
return roConfig == null ? null : createFromConfig(roConfig, false, true);
}
DataSourceBuilder.Settings readOnlyConfig() {
@@ -76,20 +80,21 @@ final class InitDataSource {
return url != null && !"none".equalsIgnoreCase(url) && !url.trim().isEmpty();
}
private DataSource createFromConfig(DataSourceBuilder.Settings dsConfig, boolean readOnly) {
private DataSource createFromConfig(DataSourceBuilder.Settings dsConfig, boolean readOnlyDB, boolean readOnly) {
if (dsConfig == null) {
throw new PersistenceException("No DataSourceBuilder defined for " + config.getName());
}
if (dsConfig.isOffline()) {
if (config.getDatabasePlatformName() == null) {
throw new PersistenceException("You MUST specify a DatabasePlatformName on DatabaseConfig when offline");
}
if (dsConfig.isOffline() && config.getDatabasePlatformName() == null) {
throw new PersistenceException("You MUST specify a DatabasePlatformName on DatabaseConfig when offline");
}
attachAlert(dsConfig);
attachListener(dsConfig);
if (readOnly) {
if (readOnlyDB) {
dsConfig.autoCommit(true);
dsConfig.readOnly(true);
} else if (readOnly) {
// setup to use AutoCommit such that we skip explicit commit
var mainSettings = config.getDataSourceConfig();
dsConfig.autoCommit(true);
@@ -278,7 +278,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
this.partitionMeta = deploy.getPartitionMeta();
this.tablespaceMeta = deploy.getTablespaceMeta();
this.storageEngine = deploy.getStorageEngine();
this.autoTunable = beanFinder == null && (entityType == EntityType.ORM || entityType == EntityType.VIEW);
this.autoTunable = entityType == EntityType.ORM || entityType == EntityType.VIEW;
// helper object used to derive lists of properties
DeployBeanPropertyLists listHelper = new DeployBeanPropertyLists(owner, this, deploy);
this.softDeleteProperty = listHelper.getSoftDeleteProperty();
@@ -99,6 +99,10 @@ final class AnnotationFields extends AnnotationParser {
if (formula != null) {
prop.setSqlFormula(processFormula(formula.select()), processFormula(formula.join()));
}
DbComment comment = get(prop, DbComment.class);
if (comment != null) {
prop.setDbComment(comment.value());
}
initWhoProperties(prop);
initDbMigration(prop);
}
@@ -81,7 +81,7 @@ final class BetweenPropertyExpression extends NonPrepareExpression {
@Override
public void addSql(SpiExpressionRequest request) {
request.append(" ?").append(BETWEEN).property(name(lowProperty)).append(" and ").property(name(highProperty));
request.append("?").append(BETWEEN).property(name(lowProperty)).append(" and ").property(name(highProperty));
}
@Override
@@ -119,7 +119,11 @@ public final class Binder {
if (param.isEncryptionKey()) {
bindLog.append("****");
} else {
bindLog.append(value);
String sv = String.valueOf(value);
if (sv.length() > 50) {
sv = sv.substring(0, 47) + "...";
}
bindLog.append(sv);
}
}
if (value instanceof Collection) {
@@ -305,6 +305,11 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Override
public <A> Optional<A> findSingleAttributeOrEmpty() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Override
public boolean isCountDistinct() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
@@ -9,8 +9,10 @@ import io.ebeaninternal.api.*;
import io.ebeaninternal.server.dto.DtoBeanDescriptor;
import io.ebeaninternal.server.dto.DtoMappingRequest;
import io.ebeaninternal.server.dto.DtoQueryPlan;
import io.ebeaninternal.server.transaction.ExternalJdbcTransaction;
import javax.annotation.Nullable;
import java.sql.Connection;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
@@ -86,6 +88,12 @@ public final class DefaultDtoQuery<T> extends AbstractQuery implements SpiDtoQue
return this;
}
@Override
public DtoQuery<T> usingConnection(Connection connection) {
this.transaction = new ExternalJdbcTransaction(connection);
return this;
}
@Override
public DtoQuery<T> usingMaster() {
this.useMaster = true;
@@ -1161,7 +1161,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
// add the rawSql statement - if any
if (orderByIsEmpty()) {
if (rawSql != null && rawSql.getSql() != null) {
order(rawSql.getSql().getOrderBy());
orderBy(rawSql.getSql().getOrderBy());
}
}
if (checkPagingOrderBy()) {
@@ -1517,7 +1517,6 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
}
@Override
@SuppressWarnings("unchecked")
public final <A> List<A> findSingleAttributeList() {
return server.findSingleAttributeList(this);
}
@@ -1533,6 +1532,11 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
return !list.isEmpty() ? list.get(0) : null;
}
@Override
public final <A> Optional<A> findSingleAttributeOrEmpty() {
return Optional.ofNullable(findSingleAttribute());
}
@Override
public final T findOne() {
return server.findOne(this);
@@ -7,7 +7,9 @@ import io.ebeaninternal.api.BindParams;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiSqlQuery;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.server.transaction.ExternalJdbcTransaction;
import java.sql.Connection;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
@@ -50,6 +52,12 @@ public final class DefaultRelationalQuery extends AbstractQuery implements SpiSq
return this;
}
@Override
public SqlQuery usingConnection(Connection connection) {
this.transaction = new ExternalJdbcTransaction(connection);
return this;
}
@Override
public SqlQuery usingMaster() {
this.useMaster = true;
@@ -1,9 +1,12 @@
package io.ebeaninternal.server.type;
import io.ebean.core.type.ScalarType;
import io.ebean.core.type.BasicTypeConverter;
import io.ebean.core.type.ScalarType;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.util.UUID;
/**
@@ -32,6 +35,8 @@ interface ArrayElementConverter<T> {
ArrayElementConverter<Double> DOUBLE = new DoubleConverter();
ArrayElementConverter<Float> FLOAT = new FloatConverter();
ArrayElementConverter<BigDecimal> BIG_DECIMAL = new BigDecimalConverter();
ArrayElementConverter<Instant> INSTANT = new InstantConverter();
ArrayElementConverter<LocalDate> LOCAL_DATE = new LocalDateConverter();
class LongConverter implements ArrayElementConverter<Long> {
@@ -101,6 +106,48 @@ interface ArrayElementConverter<T> {
}
}
class InstantConverter implements ArrayElementConverter<Instant> {
@Override
public Instant fromSerialized(Object rawValue) {
return fromDbArray(rawValue);
}
@Override
public Instant fromDbArray(Object rawValue) {
if (rawValue instanceof Instant) {
return (Instant) rawValue;
} else if (rawValue instanceof Timestamp) {
return ((Timestamp) rawValue).toInstant();
} else if (rawValue instanceof String) {
return Instant.parse((String) rawValue);
} else {
throw new IllegalStateException("Instant fromDbArray unsupported for " + rawValue);
}
}
}
class LocalDateConverter implements ArrayElementConverter<LocalDate> {
@Override
public LocalDate fromSerialized(Object rawValue) {
return fromDbArray(rawValue);
}
@Override
public LocalDate fromDbArray(Object rawValue) {
if (rawValue instanceof LocalDate) {
return (LocalDate) rawValue;
} else if (rawValue instanceof java.sql.Date) {
return ((java.sql.Date) rawValue).toLocalDate();
} else if (rawValue instanceof String) {
return LocalDate.parse((String) rawValue);
} else {
throw new IllegalStateException("Instant fromDbArray unsupported for " + rawValue);
}
}
}
class BigDecimalConverter implements ArrayElementConverter<BigDecimal> {
@Override
@@ -141,7 +188,7 @@ interface ArrayElementConverter<T> {
@Override
public java.util.UUID fromSerialized(Object rawValue) {
return java.util.UUID.fromString((String)rawValue);
return java.util.UUID.fromString((String) rawValue);
}
@Override
@@ -16,6 +16,8 @@ import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.sql.Types;
import java.time.Instant;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
@@ -63,6 +65,12 @@ class ScalarTypeArrayList extends ScalarTypeArrayBase<List> implements ScalarTyp
if (valueType.equals(String.class)) {
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING));
}
if (valueType.equals(Instant.class)) {
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "timestamptz", DocPropertyType.TEXT, ArrayElementConverter.INSTANT));
}
if (valueType.equals(LocalDate.class)) {
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "date", DocPropertyType.TEXT, ArrayElementConverter.LOCAL_DATE));
}
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
} finally {
lock.unlock();
@@ -8,6 +8,8 @@ import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.sql.Types;
import java.time.Instant;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -58,6 +60,12 @@ final class ScalarTypeArrayListH2 extends ScalarTypeArrayList {
if (valueType.equals(String.class)) {
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING));
}
if (valueType.equals(Instant.class)) {
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "timestamp", DocPropertyType.TEXT, ArrayElementConverter.INSTANT));
}
if (valueType.equals(LocalDate.class)) {
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "date", DocPropertyType.TEXT, ArrayElementConverter.LOCAL_DATE));
}
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
} finally {
lock.unlock();
@@ -15,7 +15,7 @@ public class BetweenPropertyExpressionTest extends BaseExpressionTest {
public void sqlExpression() {
TDSpiExpressionRequest request = new TDSpiExpressionRequest(null);
exp("a", "b", 10).addSql(request);
Assertions.assertThat(request.sql()).isEqualTo(" ? between a and b");
Assertions.assertThat(request.sql()).isEqualTo("? between a and b");
}
@Test
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<name>ebean ddl generation</name>
@@ -28,14 +28,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>provided</scope>
</dependency>
@@ -65,7 +65,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
@@ -1,5 +1,6 @@
package io.ebeaninternal.dbmigration.model;
import io.ebean.annotation.ConstraintMode;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DdlHelp;
import io.ebeaninternal.dbmigration.migration.AlterForeignKey;
import io.ebeaninternal.dbmigration.migration.ForeignKey;
@@ -22,6 +23,8 @@ public class MCompoundForeignKey {
private final List<String> columns = new ArrayList<>();
private final List<String> referenceColumns = new ArrayList<>();
private String indexName;
private ConstraintMode fkeyOnDelete;
private ConstraintMode fkeyOnUpdate;
public MCompoundForeignKey(String name, String referenceTable, String indexName) {
this.name = name;
@@ -47,9 +50,15 @@ public class MCompoundForeignKey {
fk.setColumnNames(toColumnNames(columns));
fk.setRefColumnNames(toColumnNames(referenceColumns));
fk.setRefTableName(referenceTable);
fk.setOnDelete(fkeyModeOf(fkeyOnDelete));
fk.setOnUpdate(fkeyModeOf(fkeyOnUpdate));
return fk;
}
private String fkeyModeOf(ConstraintMode mode) {
return (mode == null) ? null : mode.name();
}
/**
* Create and return an AlterForeignKey migration element.
*/
@@ -63,7 +72,7 @@ public class MCompoundForeignKey {
fk.setTableName(tableName);
return fk;
}
/**
* Create and return an AlterForeignKey migration element.
*/
@@ -117,7 +126,6 @@ public class MCompoundForeignKey {
* Return as an array of string column names.
*/
private String toColumnNames(List<String> columns) {
StringBuilder sb = new StringBuilder(40);
for (int i = 0; i < columns.size(); i++) {
if (i > 0) {
@@ -139,7 +147,7 @@ public class MCompoundForeignKey {
return true;
if (!(obj instanceof MCompoundForeignKey))
return false;
MCompoundForeignKey other = (MCompoundForeignKey) obj;
return Objects.equals(columns, other.columns)
&& Objects.equals(indexName, other.indexName)
@@ -148,4 +156,8 @@ public class MCompoundForeignKey {
&& Objects.equals(referenceTable, other.referenceTable);
}
public void setForeignKeyModes(ConstraintMode onDelete, ConstraintMode onUpdate) {
this.fkeyOnDelete = onDelete;
this.fkeyOnUpdate = onUpdate;
}
}
@@ -91,7 +91,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
@Override
public void visitEnd() {
// set the primary key name
table.setPkName(primaryKeyName());
@@ -169,6 +168,8 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
@Override
public void visitOneImported(BeanPropertyAssocOne<?> p) {
PropertyForeignKey foreignKey = p.foreignKey();
boolean addForeignKey = foreignKey == null || !foreignKey.isNoConstraint();
TableJoinColumn[] columns = p.tableJoin().columns();
if (columns.length == 0) {
@@ -178,17 +179,19 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
List<MColumn> modelColumns = new ArrayList<>(columns.length);
MCompoundForeignKey compoundKey = null;
if (columns.length > 1) {
if (addForeignKey && columns.length > 1) {
// compound foreign key
String refTable = p.targetDescriptor().baseTable();
String fkName = foreignKeyConstraintName(p.name());
String fkIndex = foreignKeyIndexName(p.name());
compoundKey = new MCompoundForeignKey(fkName, refTable, fkIndex);
if (foreignKey != null) {
compoundKey.setForeignKeyModes(foreignKey.getOnDelete(), foreignKey.getOnUpdate());
}
table.addForeignKey(compoundKey);
}
for (TableJoinColumn column : columns) {
String dbCol = column.getLocalDbColumn();
BeanProperty importedProperty = p.findMatchImport(dbCol);
if (importedProperty == null) {
@@ -200,26 +203,28 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
MColumn col = table.addColumn(dbCol, columnDefn, !p.isNullable());
col.setDbMigrationInfos(p.dbMigrationInfos());
col.setDefaultValue(p.dbColumnDefault());
if (columns.length == 1) {
if (p.hasForeignKeyConstraint() && !importedProperty.descriptor().suppressForeignKey()) {
// single references column (put it on the column)
String refTable = importedProperty.descriptor().baseTable();
if (refTable == null) {
// odd case where an EmbeddedId only has 1 property
refTable = p.targetDescriptor().baseTable();
}
col.setReferences(refTable + "." + refColumn);
col.setForeignKeyName(foreignKeyConstraintName(col.getName()));
if (p.hasForeignKeyIndex()) {
col.setForeignKeyIndex(foreignKeyIndexName(col.getName()));
}
PropertyForeignKey foreignKey = p.foreignKey();
if (foreignKey != null) {
col.setForeignKeyModes(foreignKey.getOnDelete(), foreignKey.getOnUpdate());
col.setComment(p.dbComment());
if (addForeignKey) {
if (columns.length > 1) {
compoundKey.addColumnPair(dbCol, refColumn);
} else {
if (p.hasForeignKeyConstraint() && !importedProperty.descriptor().suppressForeignKey()) {
// single references column (put it on the column)
String refTable = importedProperty.descriptor().baseTable();
if (refTable == null) {
// odd case where an EmbeddedId only has 1 property
refTable = p.targetDescriptor().baseTable();
}
col.setReferences(refTable + "." + refColumn);
col.setForeignKeyName(foreignKeyConstraintName(col.getName()));
if (p.hasForeignKeyIndex()) {
col.setForeignKeyIndex(foreignKeyIndexName(col.getName()));
}
if (foreignKey != null) {
col.setForeignKeyModes(foreignKey.getOnDelete(), foreignKey.getOnUpdate());
}
}
}
} else {
compoundKey.addColumnPair(dbCol, refColumn);
}
modelColumns.add(col);
}
@@ -1,8 +1,6 @@
package io.ebeaninternal.dbmigration.model.build;
import io.ebean.DatabaseBuilder;
import io.localtest.BaseTestCase;
import io.ebean.DB;
import io.ebean.DatabaseFactory;
import io.ebean.config.DatabaseConfig;
@@ -11,11 +9,13 @@ import io.ebean.platform.h2.H2Platform;
import io.ebean.platform.sqlserver.SqlServer17Platform;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DefaultConstraintMaxLength;
import io.ebeaninternal.dbmigration.migration.ForeignKey;
import io.ebeaninternal.dbmigration.model.MColumn;
import io.ebeaninternal.dbmigration.model.MCompoundForeignKey;
import io.ebeaninternal.dbmigration.model.MTable;
import io.ebeaninternal.dbmigration.model.ModelContainer;
import io.ebeaninternal.dbmigration.model.visitor.VisitAllUsing;
import io.localtest.BaseTestCase;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.CKeyAssoc;
import org.tests.model.basic.CKeyDetail;
@@ -44,10 +44,12 @@ public class ModelBuildBeanVisitorTest extends BaseTestCase {
new VisitAllUsing(addTable, defaultServer).visitAllBeans();
assert_compound_pk(model);
assert_compound_fk(model);
assert_discriminatorColumn_explicit(model);
assert_discriminatorColumn_implied(model);
assert_discriminatorColumn_length(model);
assert_comment_onManyToOne(model);
}
@Test
@@ -73,7 +75,7 @@ public class ModelBuildBeanVisitorTest extends BaseTestCase {
config.setDbOffline(true);
config.setDatabasePlatform(new SqlServer17Platform());
final SpiEbeanServer database = (SpiEbeanServer)DatabaseFactory.create(config);
final SpiEbeanServer database = (SpiEbeanServer) DatabaseFactory.create(config);
try {
ModelBuildContext ctx = new ModelBuildContext(model, config.getDatabasePlatform(), config.getConstraintNaming(), true);
@@ -105,6 +107,21 @@ public class ModelBuildBeanVisitorTest extends BaseTestCase {
assertThat(item.primaryKeyColumns()).hasSize(2);
}
private void assert_compound_fk(ModelContainer model) {
MTable item = model.getTable("item");
assertThat(item).isNotNull();
List<MCompoundForeignKey> compoundKeys = item.getCompoundKeys();
assertThat(compoundKeys).hasSize(1);
MCompoundForeignKey compoundForeignKey = compoundKeys.get(0);
ForeignKey foreignKey = compoundForeignKey.createForeignKey();
assertThat(foreignKey.getName()).isEqualTo("fk_item_etype");
assertThat(foreignKey.getColumnNames()).isEqualTo("customer,type");
assertThat(foreignKey.getRefTableName()).isEqualTo("\"type\"");
assertThat(foreignKey.getOnDelete()).isEqualTo("SET_NULL");
assertThat(foreignKey.getOnUpdate()).isEqualTo("SET_DEFAULT");
}
private void assert_discriminatorColumn_explicit(ModelContainer model) {
MTable configuration = model.getTable("configuration");
@@ -128,4 +145,11 @@ public class ModelBuildBeanVisitorTest extends BaseTestCase {
assertThat(discTypeColumn.getType()).isEqualTo("varchar(3)");
assertThat(discTypeColumn.isNotnull()).isTrue();
}
private void assert_comment_onManyToOne(ModelContainer model) {
MTable message = model.getTable("c_message");
MColumn conversation = message.getColumn("conversation_id");
assertThat(conversation.getType()).isEqualTo("bigint");
assertThat(conversation.getComment()).isEqualTo("A ManyToOne comment");
}
}
@@ -1,5 +1,7 @@
package org.tests.model.compositekeys;
import io.ebean.annotation.ConstraintMode;
import io.ebean.annotation.DbForeignKey;
import jakarta.persistence.AttributeOverride;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
@@ -32,11 +34,13 @@ public class Item {
@Version
private Long version;
@DbForeignKey(onDelete = ConstraintMode.SET_NULL, onUpdate = ConstraintMode.SET_DEFAULT)
@ManyToOne
@JoinColumn(name = "customer", referencedColumnName = "customer", insertable = false, updatable = false)
@JoinColumn(name = "type", referencedColumnName = "type", insertable = false, updatable = false)
private Type eType;
@DbForeignKey(noConstraint = true)
@ManyToOne
@JoinColumn(name = "customer", referencedColumnName = "customer", insertable = false, updatable = false)
@JoinColumn(name = "region", referencedColumnName = "type", insertable = false, updatable = false)
@@ -1,5 +1,6 @@
package org.tests.model.converstation;
import io.ebean.annotation.DbComment;
import org.tests.model.BaseModel;
import jakarta.persistence.Entity;
@@ -14,6 +15,7 @@ public class Message extends BaseModel {
String body;
@DbComment("A ManyToOne comment")
@ManyToOne
Conversation conversation;
+2 -2
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>provided</scope>
</dependency>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<name>ebean postgis types</name>
@@ -19,14 +19,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<!-- provided scope -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>provided</scope>
</dependency>
@@ -62,7 +62,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<name>ebean querybean</name>
@@ -17,7 +17,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>provided</scope>
</dependency>
@@ -63,14 +63,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
@@ -84,7 +84,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>provided</scope>
</dependency>
@@ -304,6 +304,14 @@ public abstract class PBaseComparable<R, T> extends PBaseValueEqual<R, T> {
return _root;
}
/**
* Between - value between this property and another property
*/
public final R betweenProperties(Query.Property<T> highProperty, T value) {
expr().betweenProperties(_name, highProperty.toString(), value);
return _root;
}
/**
* Greater than.
*
@@ -32,7 +32,7 @@ public abstract class PBaseString<R, T> extends PBaseComparable<R, T> {
* @param value the equal to bind value
* @return the root query bean instance
*/
@Deprecated
@Deprecated(forRemoval = true)
public final R equalToType(T value) {
expr().eq(_name, value);
return _root;
@@ -46,7 +46,7 @@ public abstract class PBaseString<R, T> extends PBaseComparable<R, T> {
* @param value the equal to bind value
* @return the root query bean instance
*/
@Deprecated
@Deprecated(forRemoval = true)
public final R notEqualToType(T value) {
expr().ne(_name, value);
return _root;
@@ -745,7 +745,7 @@ public abstract class TQRootBean<T, R> {
* Add EXISTS sub-query predicate.
*/
public R exists(Query<?> subQuery) {
query.where().exists(subQuery);
peekExprList().exists(subQuery);
return root;
}
@@ -753,7 +753,7 @@ public abstract class TQRootBean<T, R> {
* Add NOT EXISTS sub-query predicate.
*/
public R notExists(Query<?> subQuery) {
query.where().notExists(subQuery);
peekExprList().notExists(subQuery);
return root;
}
@@ -764,7 +764,7 @@ public abstract class TQRootBean<T, R> {
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
public final R exists(String sqlSubQuery, Object... bindValues) {
query().where().exists(sqlSubQuery, bindValues);
peekExprList().exists(sqlSubQuery, bindValues);
return root;
}
@@ -775,7 +775,7 @@ public abstract class TQRootBean<T, R> {
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
public final R notExists(String sqlSubQuery, Object... bindValues) {
query().where().notExists(sqlSubQuery, bindValues);
peekExprList().notExists(sqlSubQuery, bindValues);
return root;
}
@@ -1275,7 +1275,7 @@ public abstract class TQRootBean<T, R> {
/**
* @deprecated migrate to {@link #orderBy()}.
*/
@Deprecated(since = "13.19")
@Deprecated(since = "13.19", forRemoval = true)
public R order() {
return root;
}
@@ -1295,7 +1295,7 @@ public abstract class TQRootBean<T, R> {
/**
* @deprecated migrate to {@link #orderBy(String)}
*/
@Deprecated(since = "13.19")
@Deprecated(since = "13.19", forRemoval = true)
public R order(String orderByClause) {
return orderBy(orderByClause);
}
@@ -1867,6 +1867,28 @@ public abstract class TQRootBean<T, R> {
return query.findSingleAttribute();
}
/**
* Execute the query returning a single optional attribute value.
* <p>
* <h3>Example</h3>
* <pre>{@code
*
* Optional<String> maybeName =
* new QCustomer()
* .select(name)
* .id.eq(42)
* .status.eq(NEW)
* .findSingleAttributeOrEmpty();
*
* }</pre>
*
* @return an optional value for the selected property
*/
@Nullable
public <A> Optional<A> findSingleAttributeOrEmpty() {
return query.findSingleAttributeOrEmpty();
}
/**
* Execute the query processing the beans one at a time.
* <p>
@@ -1,8 +1,9 @@
package org.example.domain;
import io.ebean.annotation.DbArray;
import jakarta.persistence.*;
import org.example.domain.finder.ContactFinder;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.ZonedDateTime;
@@ -17,6 +18,11 @@ import java.util.Map;
@Table(name = "be_contact")
public class Contact extends BaseModel {
/**
* Convenience Finder for 'active record' style.
*/
public static final ContactFinder find = new ContactFinder();
@DbArray
List<@Size(max=20) String> phoneNumbers = new ArrayList<>();
@@ -0,0 +1,12 @@
package org.example.domain;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class PFile {
@Id
long id;
String name;
}
@@ -0,0 +1,12 @@
package org.example.domain;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class PLong {
@Id
long id;
String name;
}
@@ -0,0 +1,12 @@
package org.example.domain;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class Pinstant {
@Id
long id;
String name;
}
@@ -0,0 +1,18 @@
package org.example.domain.finder;
import io.ebean.Finder;
import org.example.domain.Contact;
import org.example.domain.query.QContact;
/**
*/
public class ContactFinder extends Finder<Long, Contact> {
public ContactFinder() {
super(Contact.class);
}
public QContact typed() {
return new QContact();
}
}
@@ -1,6 +1,8 @@
package org.querytest;
import org.example.domain.Contact;
import org.example.domain.Customer;
import org.example.domain.query.QCustomer;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
@@ -9,6 +11,8 @@ import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class QCustomerAndOrTest {
@Test
@@ -55,6 +59,30 @@ public class QCustomerAndOrTest {
}
@Test
public void testOrWithExists() {
QCustomer query = Customer.find.typed()
.alias("_cust")
.or()
.name.eq("Superman")
.exists(Contact.find.typed()
.alias("contact")
.firstName.eq("Superman")
.raw("contact.customer_id = _cust.id")
.query()
)
.endOr()
.select(QCustomer.alias().id);
query.findList();
assertThat(query.getGeneratedSql()).isEqualTo(
"select _cust.id from be_customer _cust where (" +
"_cust.name = ? or exists (select 1 from be_contact contact where " +
"contact.first_name = ? and contact.customer_id = _cust.id))"
);
}
private Date fiveDaysAgo() {
LocalDateTime fiveDaysAgo = LocalDate.now().atStartOfDay().minusDays(5);
return new Date(fiveDaysAgo.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
@@ -63,6 +63,25 @@ public class QCustomerTest {
}
@Test
public void copy() {
var origin = new QCustomer()
.setDistinct(true)
.status.equalTo(Customer.Status.BAD);
var copy1 = origin.copy().name.isNotNull();
var q1 = copy1.query();
copy1.findList();
assertThat(q1.getGeneratedSql()).contains("from be_customer t0 where t0.status = ? and t0.name is not null");
var copy2 = origin.copy().version.ge(1L);
var q2 = copy2.query();
copy2.findList();
assertThat(q2.getGeneratedSql()).contains("from be_customer t0 where t0.status = ? and t0.version >= ?");
}
@Test
public void findSingleAttribute() {
@@ -813,6 +832,30 @@ public class QCustomerTest {
new QContact()
.firstName.inRangeWith(lastName, "B")
.findList();
new QContact()
.firstName.between("A", "B")
.findList();
}
@Test
void betweenProperties() {
var query = new QContact()
.firstName.betweenProperties(lastName, "B");
query.findList();
assertThat(query.getGeneratedSql()).contains(" where ? between t0.first_name and t0.last_name");
}
@Test
void betweenProperties_notFirstPredicate() {
var query = new QContact()
.lastName.isNotNull()
.firstName.betweenProperties(lastName, "B")
.email.isNotNull();
query.findList();
assertThat(query.getGeneratedSql()).contains(" where t0.last_name is not null and ? between t0.first_name and t0.last_name and t0.email is not null");
}
@Test
@@ -1026,6 +1069,32 @@ public class QCustomerTest {
assertThat(maxDate).isNotNull();
}
@Test
public void findSingleAttributeOrEmpty() {
Customer cust = new Customer();
cust.setName("MaybeIExist yeah");
cust.setStatus(Customer.Status.GOOD);
cust.setRegistered(new Date());
cust.save();
Optional<String> customerName = new QCustomer()
.select(name)
.status.eq(Customer.Status.GOOD)
.name.startsWith("MaybeIExist")
.findSingleAttributeOrEmpty();
assertThat(customerName).isPresent();
Optional<String> customerName2 = new QCustomer()
.select(name)
.status.eq(Customer.Status.GOOD)
.name.eq("NahIDoNotExist")
.findSingleAttributeOrEmpty();
assertThat(customerName2).isEmpty();
}
@Test
public void testFetchByScalarValue() {
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<artifactId>ebean-redis</artifactId>
@@ -22,28 +22,28 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
@@ -57,7 +57,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>provided</scope>
</dependency>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<artifactId>ebean-spring-txn</artifactId>
@@ -28,7 +28,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>provided</scope>
</dependency>
@@ -77,7 +77,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<name>ebean test</name>
@@ -33,20 +33,20 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
@@ -149,14 +149,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
@@ -5,28 +5,19 @@ import org.junit.jupiter.api.Test;
import java.util.Properties;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ContainerConfigTest {
class ContainerConfigTest {
@Test
public void loadFromProperties() {
Properties p = new Properties();
p.setProperty("ebean.cluster.active", "true");
p.setProperty("ebean.cluster.serviceName", "a");
p.setProperty("ebean.cluster.namespace", "b");
p.setProperty("ebean.cluster.podName", "c");
p.setProperty("ebean.cluster.port", "42");
void loadFromProperties() {
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.loadFromProperties(p);
assertEquals(true, containerConfig.isActive());
assertEquals("a", containerConfig.getServiceName());
assertEquals("b", containerConfig.getNamespace());
assertEquals("c", containerConfig.getPodName());
assertEquals(42, containerConfig.getPort());
assertThat(containerConfig.isActive()).isFalse();
assertThat(containerConfig.getServiceName()).isNull();
assertThat(containerConfig.getNamespace()).isNull();
assertThat(containerConfig.getPodName()).isNull();
assertThat(containerConfig.getPort()).isEqualTo(0);
}
}
@@ -409,7 +409,7 @@ class EqlParserTest extends BaseTestCase {
Query<Customer> query = parse("where 'x' between name and smallnote");
query.findList();
assertSql(query).contains("where ? between t0.name and t0.smallnote");
assertSql(query).contains("where ? between t0.name and t0.smallnote");
}
@Test
@@ -418,7 +418,7 @@ class EqlParserTest extends BaseTestCase {
query.setParameter("some", "A");
query.findList();
assertSql(query).contains("where ? between t0.name and t0.smallnote");
assertSql(query).contains("where ? between t0.name and t0.smallnote");
}
@Test
@@ -26,7 +26,7 @@ public class SpiServerTest extends BaseTestCase {
BeanType<Customer> beanType = pluginApi.beanType(Customer.class);
assertEquals("o_customer", beanType.baseTable());
assertNotNull(pluginApi.databasePlatform());
assertNull(beanType.findController());
assertNotNull(beanType.findController());
assertNotNull(beanType.persistController());
assertNull(beanType.persistListener());
assertNull(beanType.queryAdapter());
@@ -73,9 +73,26 @@ public class TestQueryUsingConnection extends BaseTestCase {
assertThat(count).isEqualTo(otherCount + 1);
assertThat(otherCount).isEqualTo(masterCount);
}
}
@IgnorePlatform({Platform.SQLSERVER, Platform.COCKROACH})
@Test
public void dtoQueryUsingConnection() {
ResetBasicData.reset();
try (Transaction transaction = DB.createTransaction()) {
final CountryDto dto = DB.findDto(CountryDto.class, "select code, name from o_country where code=?")
.usingConnection(transaction.connection())
.setParameter("NZ")
.findOne();
assertThat(dto).isNotNull();
assertEquals("NZ", dto.code);
transaction.rollback();
}
}
public static class CountryDto {
final String code;
final String name;
@@ -1,8 +1,8 @@
package org.tests.basic;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import io.ebean.Update;
import io.ebean.xtest.BaseTestCase;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -10,6 +10,7 @@ import org.tests.model.basic.Customer;
import org.tests.model.basic.ResetBasicData;
import java.util.Arrays;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@@ -37,13 +38,17 @@ public class TestUpdate extends BaseTestCase {
@Test
public void testNormal() {
String sillyContent = "a123456789b123456789c123456789d123456789e123456789";
for (int i = 1; i <= 3; i++) {
Update<Customer> update = DB.createUpdate(Customer.class,
"update customer set smallnote = :smallnote where name in (:name)");
update.setParameter("name", Arrays.asList("testUpdate" + i)).setParameter("smallnote", "Note #" + i).execute();
update
.setParameter("name", List.of("testUpdate" + i))
.setParameter("smallnote", "Note #" + i + sillyContent)
.execute();
}
Customer cust = DB.find(Customer.class).where().eq("name", "testUpdate3").findOne();
assertThat(cust.getSmallnote()).isEqualTo("Note #3");
assertThat(cust.getSmallnote()).isEqualTo("Note #3" + sillyContent);
}
@Test
@@ -9,6 +9,8 @@ import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Version;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -58,6 +60,12 @@ public class EArrayBean {
@DbArray
Set<Status> status2;
@DbArray
List<Instant> times;
@DbArray
List<LocalDate> dates;
@Version
Long version;
@@ -165,6 +173,24 @@ public class EArrayBean {
this.status2 = status2;
}
public List<Instant> getTimes() {
return times;
}
public EArrayBean setTimes(List<Instant> times) {
this.times = times;
return this;
}
public List<LocalDate> getDates() {
return dates;
}
public EArrayBean setDates(List<LocalDate> dates) {
this.dates = dates;
return this;
}
public Long getVersion() {
return version;
}
@@ -10,6 +10,8 @@ import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.time.Instant;
import java.time.LocalDate;
import java.util.*;
import static org.assertj.core.api.Assertions.assertThat;
@@ -58,6 +60,8 @@ class TestDbArray_basic extends BaseTestCase {
bean.setStatus2(new LinkedHashSet<>());
bean.getStatus2().add(EArrayBean.Status.TWO);
bean.getStatus2().add(EArrayBean.Status.ONE);
bean.setTimes(List.of(Instant.now(), Instant.now().minusSeconds(60)));
bean.setDates(List.of(LocalDate.now(), LocalDate.now().minusDays(1)));
DB.save(bean);
@@ -66,6 +70,8 @@ class TestDbArray_basic extends BaseTestCase {
assertThat(found.getPhoneNumbers()).containsExactly("4321", "9823");
assertThat(found.getDoubs()).hasSize(2);
assertThat(found.getFloats()).hasSize(2);
assertThat(found.getTimes()).hasSize(2);
assertThat(found.getDates()).hasSize(2);
if (isPostgresCompatible()) {
Query<EArrayBean> query = DB.find(EArrayBean.class)
@@ -0,0 +1,35 @@
package org.tests.model.basic;
import io.ebean.bean.BeanCollection;
import io.ebean.event.BeanFindController;
import io.ebean.event.BeanQueryRequest;
/**
* @author Noemi Praml, FOCONIS AG
*/
public class CustomerFindController implements BeanFindController {
@Override
public boolean isRegisterFor(Class<?> cls) {
return Customer.class.isAssignableFrom(cls);
}
@Override
public boolean isInterceptFind(BeanQueryRequest<?> request) {
return false;
}
@Override
public <T> T find(BeanQueryRequest<T> request) {
return null;
}
@Override
public boolean isInterceptFindMany(BeanQueryRequest<?> request) {
return false;
}
@Override
public <T> BeanCollection<T> findMany(BeanQueryRequest<T> request) {
return null;
}
}
@@ -355,6 +355,24 @@ public class TestQueryFilterMany extends BaseTestCase {
assertSql(sql.get(1)).contains(" and lower(t0.title) like");
}
@Test
public void testFetchAndFilterMany() {
ResetBasicData.reset();
LoggedSql.start();
DB.find(Customer.class)
.fetch("contacts")
.filterMany("contacts.notes").istartsWith("title", "foo")
.findList();
List<String> sql = LoggedSql.stop();
assertThat(sql.size()).isEqualTo(2);
assertSql(sql.get(0)).contains(" from o_customer t0 left join contact t1 on t1.customer_id = t0.id");
platformAssertIn(sql.get(1), " from contact_note t0 where (t0.contact_id)");
assertSql(sql.get(1)).contains(" and lower(t0.title) like");
}
@Test
public void testFilterManyUsingExpression() {
@@ -20,6 +20,7 @@ import org.tests.o2m.OmBasicParent;
import java.sql.Date;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
@@ -139,6 +140,32 @@ class TestQuerySingleAttribute extends BaseTestCase {
assertThat(name).isNotNull();
}
@Test
void findSingleAttributeOrEmpty() {
ResetBasicData.reset();
Query<Customer> query = DB.find(Customer.class)
.select("name")
.where().eq("name", "Rob").query();
Optional<String> name = query.findSingleAttributeOrEmpty();
assertThat(sqlOf(query)).contains("select t0.name from o_customer t0");
assertThat(name).isPresent().contains("Rob");
}
@Test
void findSingleAttributeOrEmpty_when_empty() {
ResetBasicData.reset();
Query<Customer> query = DB.find(Customer.class)
.select("name")
.where().eq("name", "I_Do_Not_ExistO!").query();
Optional<String> name = query.findSingleAttributeOrEmpty();
assertThat(name).isEmpty();
}
@Test
void findSingleAttributeList_with_join_column() {
ResetBasicData.reset();
@@ -265,6 +265,33 @@ class SqlQueryTests extends BaseTestCase {
assertThat(custDtos).isNotEmpty();
}
@Test
void queryUsingConnection() throws SQLException {
ResetBasicData.reset();
boolean h2 = isH2();
String sql = h2 ? "select id, name||session_id(), status from o_customer where name is not null"
: "select id, name, status from o_customer where name is not null";
try (Transaction txn = DB.createTransaction()) {
String h2SessionId = h2 ? h2SessionId(txn) : null;
AtomicInteger counter = new AtomicInteger();
DB.sqlQuery(sql)
.usingConnection(txn.connection())
.mapTo(CUST_MAPPER)
.findEach(custDto -> {
counter.incrementAndGet();
assertThat(custDto.name).isNotNull();
if (h2) {
assertThat(custDto.name).endsWith(h2SessionId);
}
});
assertThat(counter.get()).isGreaterThan(0);
}
}
@Test
void queryUsingTransaction() throws SQLException {
ResetBasicData.reset();
@@ -0,0 +1,119 @@
package org.tests.readonly;
import io.ebean.Database;
import io.ebean.DatabaseBuilder;
import io.ebean.Transaction;
import io.ebean.annotation.Transactional;
import io.ebean.datasource.DataSourceBuilder;
import io.ebean.test.containers.PostgresContainer;
import io.ebeaninternal.api.SpiTransaction;
import jakarta.persistence.PersistenceException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.UTDetail;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
class PostgresReadOnlyDatabaseTest {
private static Database readDb;
@BeforeAll
static void beforeAll() {
readDb = setupReadOnlyDatabase();
}
@Test
void insertPreventedInReadOnlyTransaction() {
assertThatThrownBy(() -> {
try (Transaction transaction = readDb.beginTransaction()) {
UTDetail u0 = new UTDetail("u0", 45, 3D);
readDb.save(u0);
}
}).isInstanceOf(PersistenceException.class)
.hasMessageContaining("ERROR: cannot execute INSERT in a read-only transaction");
}
@Test
void queryInExplicitTransaction() {
try (Transaction transaction = readDb.beginTransaction()) {
List<UTDetail> list = readDb.find(UTDetail.class).findList();
assertThat(list).hasSize(2);
assertThat(transaction.isReadOnly()).isTrue();
transaction.commit(); // autoCommit=true but this is still allowed
}
}
@Test
void queryInImplicitTransaction() {
List<UTDetail> list = readDb.find(UTDetail.class).findList();
assertThat(list).hasSize(2);
}
// Requires .register(true).defaultDatabase(true) ... when running this test
@Disabled
@Test
void queryInReadOnlyTransactional() {
readOnlyTransactional();
transactionalOnlyContainingQueries();
}
@Transactional(readOnly = true)
void readOnlyTransactional() {
List<UTDetail> list = readDb.find(UTDetail.class).findList();
assertThat(list).hasSize(2);
SpiTransaction current = (SpiTransaction) Transaction.current();
assertThat(current.isReadOnly()).isTrue();
}
@Transactional
void transactionalOnlyContainingQueries() {
List<UTDetail> list = readDb.find(UTDetail.class).findList();
assertThat(list).hasSize(2);
SpiTransaction current = (SpiTransaction) Transaction.current();
assertThat(current.isReadOnly()).isTrue();
}
private static Database setupReadOnlyDatabase() {
PostgresContainer.builder("15")
.dbName("readonly_test")
.build()
.start();
var dataSourceBuilder = DataSourceBuilder.create()
.username("readonly_test")
.password("test")
.url("jdbc:postgresql://localhost:6432/readonly_test");
var writeDb = databaseBuilder(dataSourceBuilder)
.ddlGenerate(true)
.ddlRun(true)
.build();
writeDb.truncate(UTDetail.class);
writeDb.save(new UTDetail("u0", 45, 3D));
writeDb.save(new UTDetail("u1", 42, 5D));
return databaseBuilder(dataSourceBuilder)
.readOnlyDatabase(true)
// register + default required for the tests using @Transactional
// .register(true).defaultDatabase(true)
.build();
}
private static DatabaseBuilder databaseBuilder(DataSourceBuilder dataSourceBuilder) {
return Database.builder()
.name("ro_test")
.dataSourceBuilder(dataSourceBuilder)
.ddlExtra(false)
.defaultDatabase(false)
.register(false)
.addClass(UTDetail.class);
}
}
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<name>kotlin querybean generator</name>
@@ -21,7 +21,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
@@ -35,7 +35,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
@@ -56,14 +56,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<scope>test</scope>
</dependency>
@@ -94,6 +94,13 @@ class KotlinLangAdapter implements LangAdapter {
writer.append(" * Private constructor for FetchGroup building.").eol();
writer.append(" */").eol();
writer.append(" private constructor(fetchGroupQuery: Query<%s>) : super(fetchGroupQuery)", shortName).eol();
writer.eol();
writer.append(" /** Return a copy of the query. */").eol();
writer.append(" fun copy() : Q%s {", shortName).eol();
writer.append(" return Q%s(query().copy())", shortName).eol();
writer.append(" }").eol();
writer.eol();
}
@Override
+14 -14
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -15,67 +15,67 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hsqldb</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlanywhere</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -15,7 +15,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -15,7 +15,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -15,7 +15,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<!-- Provided scope so that the H2HistoryTrigger can live in Ebean core
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -15,7 +15,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -15,7 +15,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -15,13 +15,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -15,7 +15,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -15,7 +15,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -15,7 +15,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<artifactId>platforms</artifactId>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -15,7 +15,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
<dependency>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -15,7 +15,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -15,7 +15,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -15,7 +15,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</dependency>
</dependencies>
+6 -6
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId>
<artifactId>ebean-parent</artifactId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
<packaging>pom</packaging>
<name>ebean parent</name>
@@ -51,10 +51,10 @@
<ebean-ddl-runner.version>2.3</ebean-ddl-runner.version>
<ebean-migration-auto.version>1.2</ebean-migration-auto.version>
<ebean-migration.version>13.11.1</ebean-migration.version>
<ebean-test-containers.version>7.1</ebean-test-containers.version>
<ebean-datasource.version>8.9</ebean-datasource.version>
<ebean-agent.version>13.24.0</ebean-agent.version>
<ebean-maven-plugin.version>13.24.0</ebean-maven-plugin.version>
<ebean-test-containers.version>7.3</ebean-test-containers.version>
<ebean-datasource.version>8.11</ebean-datasource.version>
<ebean-agent.version>13.26.0</ebean-agent.version>
<ebean-maven-plugin.version>13.26.0</ebean-maven-plugin.version>
<surefire.useModulePath>false</surefire.useModulePath>
</properties>
@@ -70,7 +70,7 @@
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
<version>1.3.12</version>
<scope>test</scope>
</dependency>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.25.0-jakarta</version>
<version>13.26.0-jakarta</version>
</parent>
<name>querybean generator</name>
@@ -19,11 +19,6 @@ interface Constants {
String DBJSONB = "io.ebean.annotation.DbJsonB";
String DBNAME = "io.ebean.annotation.DbName";
String TQROOTBEAN = "io.ebean.typequery.TQRootBean";
String TQASSOCBEAN = "io.ebean.typequery.TQAssocBean";
String TQASSOC = "io.ebean.typequery.TQAssoc";
String DB = "io.ebean.DB";
String MODULEINFO = "io.ebean.config.ModuleInfo";
String METAINF_MANIFEST = "META-INF/ebean-generated-info.mf";
String METAINF_SERVICES_MODULELOADER = "META-INF/services/io.ebean.config.EntityClassRegister";

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