Compare commits

...
86 Commits
Author SHA1 Message Date
Rob Bygrave 7853bf0960 Merge branch 'master' into ebean-15x 2024-04-04 23:54:39 +13:00
Rob Bygrave 0128d64841 Version 14.1.0 2024-04-04 22:54:23 +13:00
Rob Bygrave 68b313f778 Update ebean-agent to 14.1.0
This version allows for removal of query bean setRoot() which is no longer needed.
2024-04-04 22:42:06 +13:00
Rob BygraveandGitHub fad32c58d8 Merge pull request #3384 from ebean-orm/feature/rename-iquerybean
Rename QueryBean interface to IQueryBean (because we want to rename TQRootBean)
2024-04-04 22:36:59 +13:00
Rob Bygrave 8f1ebdb89a Rename QueryBean interface to IQueryBean (because we want to rename TQRootBean)
We want to rename TQRootBean to QueryBean. I can't do that right now because we need to make ebean-agent aware of that first. So yes, perhaps not ideal with IQueryBean but I think it will make sense once TQRootBean is renamed to QueryBean.
2024-04-04 22:35:55 +13:00
Rob BygraveandGitHub f7703efde2 Merge pull request #3383 from ebean-orm/feature/orderById
#3379 Followup, Move orderById() to common QueryBuilder interface
2024-04-04 22:09:34 +13:00
Rob BygraveandGitHub c5ffccb649 Merge pull request #3382 from ebean-orm/fix/3381-pc-clear
Fix for #3381 - Empty OneToMany when overflowing LazyLoadBatchSize an…
2024-04-04 22:08:57 +13:00
Rob Bygrave 3e65705bf9 #3379 Followup, Move orderById() to common QueryBuilder interface
Effectively this adds it to QueryBeans (where it was missing)
2024-04-04 22:05:17 +13:00
Rob Bygrave 7469a38bbc #3375 Followup, Temporarily add back setRoot() method to allow time for IntelliJ plugin to be released
Adding this means that it will work with an old ebean-agent. It takes a few days to get a new IntelliJ plugin released and we can't wait due to wanting to release the bug fix for #3381
2024-04-04 21:53:18 +13:00
Rob Bygrave 7ea4311662 Fix for #3381 - Empty OneToMany when overflowing LazyLoadBatchSize and mixed queries
14.0.0 via #3295 introduced this bug.

 #3295 introduced a behaviour where bulk updates clear the persistence context. Now the lazy loading of a BeanCollection works with an assumption that the "parent bean" is in the persistence context (and this assumption is broken with that change for this test case). That is, the bulk update is clearing the persistence context - removing the parent bean BEFORE the lazy loading is invoked ... and that doesn't then work because the parent bean isn't in the persistence context.

 This fix means that when lazy loading many's, the parent beans are putIfAbsent into the persistence context.
2024-04-04 20:13:20 +13:00
Rob BygraveandGitHub f556e04f58 Merge pull request #3380 from ebean-orm/feature/deprecate-update-transaction
Deprecate update(transaction) and delete(transaction) - migrate to usingTransaction(transaction)
2024-04-01 20:57:58 +13:00
Rob Bygrave d9c75a60a5 Deprecate update(transaction) and delete(transaction) - migrate to usingTransaction(transaction)
Migrate to usingTransaction(transaction) to set the transaction explicitly on a delete or update query.
2024-04-01 20:35:59 +13:00
Rob BygraveandGitHub 225bec7b28 Merge pull request #3379 from ebean-orm/feature/query-builder-interface
Add QueryBuilder interface as common API for Query and QueryBean
2024-04-01 19:42:34 +13:00
Rob Bygrave da44f7e604 Add QueryBuilder interface as common API for Query and QueryBean 2024-04-01 18:58:57 +13:00
e0eda4f8be #3370 LimitOffsetPagedList add getTotalCount cache (#3373)
* #3370 LimitOffsetPagedList add getTotalCount cache

* Move totalRowCount check to inside the lock

* No change, format only on LimitOffsetPagedList

---------

Co-authored-by: Rob Bygrave <robin.bygrave@gmail.com>
2024-04-01 11:08:57 +13:00
Rob BygraveandGitHub e4e780588c Merge pull request #3378 from ebean-orm/feature/QueryBean-interface
Add QueryBean interface for query beans to implement
2024-04-01 10:59:38 +13:00
Rob Bygrave 7c8f235550 Add QueryBean interface for query beans to implement 2024-04-01 10:56:25 +13:00
Rob BygraveandGitHub 9a77ec1567 Merge pull request #3377 from ebean-orm/feature/3374
querybeans: #3374 - Add copy() method to TQRootBean
2024-04-01 09:09:24 +13:00
Rob Bygrave ff426319f5 Fix deprecated annotation for kotlin-querybean-generator 2024-04-01 09:02:13 +13:00
Rob Bygrave 7f56aff9dd Bump kotlin-querybean-generator 2024-03-31 11:49:58 +13:00
Rob Bygrave cdbdd98d36 querybeans: #3374 - Add copy() method to TQRootBean 2024-03-31 11:44:32 +13:00
Rob BygraveandGitHub 7bf030f59c Merge pull request #3376 from ebean-orm/feature/querybean-txn
Deprecate Query bean constructor that takes transaction - migrate to query.usingTransaction() instead
2024-03-31 11:38:26 +13:00
Rob Bygrave 16dca28831 Deprecate Query bean constructor that takes transaction - migrate to usingTransaction()
Migrate to query.usingTransaction() instead of the constructor that takes a transaction.
2024-03-31 11:37:32 +13:00
Rob BygraveandGitHub 678b43693d Merge pull request #3372 from ebean-orm/feature/1857-SlowQueryBindCapture
#1857 Add bind values capture for SlowQueryEvent / SlowQueryListener
2024-03-31 11:34:18 +13:00
Rob BygraveandGitHub 7ab93a0cdf Merge pull request #3375 from ebean-orm/feature/tidy-tqrootbean
Update TQRootBean with final methods, remove setRoot()
2024-03-31 11:32:54 +13:00
Rob Bygrave 951f942c73 Tidy TQRootBean constructor for alias.
Note that this requires the updated ebean-agent, where it will not longer use the setRoot() method which has now been removed.
2024-03-31 11:19:39 +13:00
Rob Bygrave cf2ec4b81d Modify TQRootBean making root final
Remove the unused setRoot() method
2024-03-31 10:02:41 +13:00
Rob Bygrave 7d1745ba53 Add final modifier to TQRootBean methods
As these are never expected to be overwritten
2024-03-31 09:57:42 +13:00
Rob BygraveandGitHub 7adbdbf532 feat: For SpringJdbcTransactionManager support using CurrentTenantProvider (#3368)
Note that this only works for Multi-Tenant PARTITION mode where the TenantId is a column on the tables (rather than schema or database multi-tenancy mode).
2024-03-26 22:45:39 +13:00
Rob Bygrave 40d9c88e34 #1857 Add bind values capture for SlowQueryEvent / SlowQueryListener
- changes SqlQueryEvent into an interface.
- captures the bind values the slow query used and makes those available via SlowQueryEvent
- also makes the query label and profileLocation available via SlowQueryEvent
2024-03-25 22:52:04 +13:00
Rob Bygrave 15b3eb2bf3 Merge branch 'master' into ebean-15x 2024-03-21 22:48:57 +13:00
Rob Bygrave ab45ad34e0 Version 14.0.2 2024-03-21 22:07:12 +13:00
Rob Bygrave 24b514f851 Bump ebean-agent, no effective change 2024-03-21 21:55:02 +13:00
Rob BygraveandGitHub 582fec7ce4 For #3363 disable flushOnQuery before BeanPersistAdapter post-processors (#3367) 2024-03-21 21:51:10 +13:00
Rob BygraveandGitHub 0b11c541c8 fix: #3142 Cascading a OneToMany, set the relationship when the child isn't new or dirty (#3366)
That is, previously the relationship back from the child to the parent was being updated when the child bean was new or dirty BUT NOT in the case when the child bean was loaded and unchanged.

This fix includes that case updating the ManyToOne side of the relationship on the child when the save is cascaded.
2024-03-21 00:14:54 +13:00
Rob BygraveandGitHub 540ceab96f feat: Add query.setHint() to support sql hint as inline comment in select queries (#3365)
* feat: Add query.setHint() to support sql hint as inline comment in select queries

This is for ORM queries only.

An ORM query like:

    new QCustomer()
      .setHint("FirstRows")
      .select(QCustomer.Alias.id, QCustomer.Alias.name)
      .findList();

Produces SQL that includes the hint as an inline comment like:

  select /*+ FirstRows */ t0.id, t0.name
  from customer t0

* Fix test QOrderTest
2024-03-20 21:48:43 +13:00
Rob BygraveandGitHub 8b858a073a feat: Add includeLabelInSql configuration option to include query label as inline comment in generated sql select (#3362)
* feat: Add includeLabelInSql configuration option to include query label as inline comment in generated sql select

The generated select queries can look like:

select /* MyInnerTest.insert_and_find */ t0.id, ...

Using either query.setLabel() or profile location (which all query beans get by default). This means that tooling looking at sql in the database can more easily relate that sql back to application code.

* More tests for labels with includeLabelInSql=true

* Remove trim when using profileLocation label
2024-03-18 07:38:30 +13:00
Rob BygraveandGitHub 02dafc9838 Merge pull request #3360 from ebean-orm/feature/refactor-DbExpressionRequest
Refactor extract DbExpressionRequest interface for db platform specific expressions
2024-03-08 00:53:56 +13:00
Rob Bygrave 0816810d3b Refactor extract DbExpressionRequest interface for db platform specific expressions
This provides a simpler DbExpressionRequest interface for db platform specific expression adapters (rather than the SpiExpressionRequest which has more features that we don't wish to expose to those expression adapters.
2024-03-07 22:45:21 +13:00
Rob Bygrave 1f6e2ee844 No effective change - update test only ClusterTest, increase wait to 200ms 2024-03-07 20:59:41 +13:00
Rob Bygrave dc00765a98 Merge branch 'fix-for-db2' 2024-03-07 20:45:57 +13:00
Rob Bygrave a48b2f4ebe #3354 Use 4000 for DB Lob detection with distinct query
- Use 4000 to match the DB2 logic for considering a column a lob (for distinct etc)
- Rename distinctNoLobs -> platformDistinctNoLobs
- Rename  isDbLob() -> isLobForPlatform()
- Rename unselectLobs() -> unselectLobsForPlatform()
2024-03-07 20:45:40 +13:00
Rob BygraveandGitHub 837563544f Merge pull request #3357 from ebean-orm/feature/avaje-config-dependency-ContainerConfig
Modify ContainerConfig to remove the avaje-config dependency
2024-03-07 20:23:36 +13:00
Rob Bygrave fd199f406b Modify ContainerConfig to remove the avaje-config dependency
This actually reverts a change that was made in commit:
https://github.com/ebean-orm/ebean/commit/803f1d86428ce3b653276d72207e5a0009b57d16
2024-03-05 21:18:27 +13:00
Roland Praml a48e96c7e9 FIX broken test for DB2 2024-03-04 10:02:05 +01:00
Rob Bygrave 7ba6e5f67d Add howto-deploy-to-central.md 2024-03-03 22:08:47 +13:00
Rob Bygrave f53c56490c Merge branch 'master' into ebean-15x 2024-03-03 20:56:17 +13:00
Rob Bygrave 6ce42b1ca3 Version 14.0.1 2024-03-03 20:24:26 +13:00
Rob BygraveandGitHub 89617cefbe Merge pull request #3353 from ebean-orm/feature/bump-migration-14
dep: Bump ebean-migration to 14.0.0, no effective change
2024-03-03 20:19:40 +13:00
Rob Bygrave dd377621a4 dep: Bump ebean-migration to 14.0.0, no effective change
No effective change in that ebean-migration 14.0.0 has no change, it was released to align version numbers with 14.x
2024-03-03 20:19:17 +13:00
Rob Bygrave d844855462 Bump ebean-agent to 14.0.1 2024-03-03 18:32:14 +13:00
Rob BygraveandGitHub f68c25d5f3 Merge pull request #3352 from ebean-orm/feature/dep-common-components
dep: Update the common components to 14.0.0 ebean-joda-types, ebean-jackson-jsonnode
2024-03-03 18:29:15 +13:00
Rob Bygrave 61cfc7a979 dep: Update the common components to 14.0.0 ebean-joda-types, ebean-jackson-jsonnode 2024-03-03 17:01:36 +13:00
Rob BygraveandGitHub 3c98ee7f1b Merge pull request #3351 from ebean-orm/dep/bump-config
Bump test dependencies only - logback and ebean-test-containers
2024-03-03 16:54:56 +13:00
Rob Bygrave 0738316f15 Bump test dependencies only - logback and ebean-test-containers 2024-03-03 16:54:22 +13:00
Rob BygraveandGitHub ceb83befa3 Merge pull request #3350 from ebean-orm/dep/bump-config
dep: Bump avaje-config to 3.12 - supports AWS AppConfig & Dynamic Logback
2024-03-03 15:42:59 +13:00
Rob Bygrave a0b04cceda dep: Bump avaje-config to 3.12 - supports AWS AppConfig & Dynamic Logback
This version of avaje-config supports using AWS AppConfig as a configuration source (via avaje-aws-appconfig). It also supports dynamic changing Logback logging levels (via avaje-dynamic-logback).
2024-03-03 15:38:14 +13:00
Rob Bygrave 03edfb5454 git workflow trigger on push to master and pull_request 2024-03-03 15:33:39 +13:00
Rob BygraveandGitHub 62015451df Merge pull request #3349 from ebean-orm/feature/dep-ebean-datasource
dep: Bump ebean-datasource to 8.12
2024-03-03 15:32:36 +13:00
Rob Bygrave ed9113efe6 dep: Bump ebean-datasource to 8.12
This adds the option to register a JVM shutdown hook (which we generally will not use with ebean as the ebean io.ebean.Database shutdown wants to shutdown the DataSource after any background tasks have completed).

This also adds an experimental feature for use with AWS Lambda to check for old idle connections due to lambda suspension.
2024-03-03 15:24:44 +13:00
Rob Bygrave 334793667e Add deployment error message for ManyToMany with one of the related beans missing an @Id property 2024-03-03 14:14:23 +13:00
Rob BygraveandGitHub 351a1c4739 Merge pull request #3348 from ebean-orm/feature/3313-fetchGroup-with-config
#3313 Ability to configure fetch batch size when using FetchGroups and query beans
2024-03-03 13:53:52 +13:00
Rob Bygrave b2de333dcc #3313 Ability to configure fetch batch size when using FetchGroups and query beans
We can do this currently using string paths and properties, this adds support for doing this when using query beans and strong types
2024-03-03 13:47:49 +13:00
Rob Bygrave 6091f7b683 No effective change - tidy test TestJsonImplicitLoaded 2024-03-03 12:25:25 +13:00
Rob BygraveandGitHub 43fb84cbc0 Merge pull request #3345 from FOCONIS/jsonwrite-loaded-props
NEW: Allow control of jsonwrite-loadedprops
2024-03-03 12:23:17 +13:00
Rob BygraveandGitHub 52a4e9e19b Merge pull request #3347 from ebean-orm/feature/3337-querybean-imports
#3337 Fix querybean-generation to not import the entity bean type
2024-03-03 12:17:42 +13:00
Rob Bygrave a2cdea24ed #3337 Fix querybean-generation to not import the entity bean type
Use the full canonical name of the entity bean in the generated code.
2024-03-03 12:13:49 +13:00
Rob Bygrave cd780208e5 Javadoc format only for io.ebean.Database 2024-03-03 11:45:36 +13:00
Rob BygraveandGitHub 9ce0e923d7 Merge pull request #3346 from ebean-orm/feature/lengthCheck-postgres
#3341 String length validation with Postgres PGobject (JSON/JSONB)
2024-03-02 10:26:52 +13:00
Rob Bygrave 9e461e4708 #3341 String length validation with Postgres PGobject (JSON/JSONB) 2024-03-02 10:06:22 +13:00
Rob Bygrave 5fa09a6f90 #3341 String length validation with Postgres PGobject (JSON/JSONB) 2024-03-02 09:52:04 +13:00
Rob Bygrave 6babb2e6f5 Add ebean.lengthCheck for mariadb test run 2024-03-02 09:39:25 +13:00
Rob Bygrave 26abe27e42 Add ebean.lengthCheck for sqlserver17 test run 2024-03-02 09:38:33 +13:00
Rob Bygrave 9b18d46b78 Add ebean.lengthCheck for mysql test run 2024-03-02 09:27:05 +13:00
Roland Praml eed487ad26 NEW: Allow control of jsonwrite-loadedprops 2024-02-29 13:26:22 +01:00
Rob BygraveandGitHub c10865dfaf Merge pull request #3344 from ebean-orm/feature/bump-avaje-config-311
Bump avaje-config to 3.11
2024-02-27 21:22:38 +13:00
Rob Bygrave 2352df309c Bump avaje-config to 3.11 2024-02-27 21:21:58 +13:00
Rob Bygrave feb2bd1e15 String length validation tidy up 2024-02-27 21:04:19 +13:00
Rob Bygrave 11c9bdfc6f Squashed commit of the following:
commit 20152e16891582f8ff466a93ec2cf01871824d6d
Author: Rob Bygrave <robin.bygrave@gmail.com>
Date:   Tue Feb 27 20:59:51 2024 +1300

    #3341 Update DatabaseConfig for fluid style + javadoc

commit 1c495a7384
Author: Roland Praml <roland.praml@foconis.de>
Date:   Mon Feb 26 10:25:42 2024 +0100

    Fix: Compile errors

commit 574876b758
Merge: df7b04877 77634fc3e
Author: Roland Praml <roland.praml@foconis.de>
Date:   Fri Feb 23 16:16:39 2024 +0100

    Merge branch 'master-rob' into FOCONIS-string-length-validation

commit df7b04877d
Author: Rob Bygrave <robin.bygrave@gmail.com>
Date:   Mon Jun 26 21:16:32 2023 +1200

    #3121 BindMaxLength validation

    At deploy time derive a BindMaxLength property to use
    per BeanProperty

commit 4683877e0b
Merge: 9a4b9d4be d0020ab8c
Author: Rob Bygrave <robin.bygrave@gmail.com>
Date:   Fri Jun 23 16:51:34 2023 +1200

    Merge branch 'string-length-validation' of github.com:FOCONIS/ebean into FOCONIS-string-length-validation

commit d0020ab8ce
Author: Roland Praml <roland.praml@foconis.de>
Date:   Tue Jun 20 14:47:20 2023 +0200

    Length validation less invasive

commit 9b3b8ad46a
Author: Roland Praml <roland.praml@foconis.de>
Date:   Tue Jun 20 13:03:04 2023 +0200

    extended DataBind, so that it could return the last bound object

commit ca3c02bc1c
Author: Roland Praml <roland.praml@foconis.de>
Date:   Mon Jun 19 09:52:52 2023 +0200

    Failing test for SqlServer
2024-02-27 21:04:06 +13:00
Rob BygraveandGitHub 559b39eedc Merge pull request #3340 from ebean-orm/revert-3212-15x/remove-future-queries
Revert "[15x] Remove "Future queries" findFutureList, findFutureIds, findFutureCount"
2024-02-27 20:26:41 +13:00
Rob Bygrave 0ebcba17f1 #3340 Changes to support Revert "[15x] Remove "Future queries
The spiQuery.usingFuture() was added after the original removal so adding that.
2024-02-26 22:20:39 +13:00
Rob BygraveandGitHub 71edd33fa3 Revert "[15x] Remove "Future queries" findFutureList, findFutureIds, findFutureCount" 2024-02-26 22:02:28 +13:00
Rob BygraveandGitHub 4a6fc98395 Merge pull request #3339 from ebean-orm/fix/3338
Fix for #3338 Potential shutdown hang with SpringContextShutdownHook …
2024-02-26 21:58:39 +13:00
Rob Bygrave 7322030e90 Fix for #3338 Potential shutdown hang with SpringContextShutdownHook and ebean ShutdownHook 2024-02-26 08:32:44 +13:00
Rob BygraveandGitHub 77634fc3eb Merge pull request #3336 from ebean-orm/feature/bump-postgresql-4272
Bump postgresql dependency to 42.7.2
2024-02-21 16:11:24 +13:00
robin.bygrave ed8d4b5fc4 Bump postgresql dependency to 42.7.2 2024-02-21 16:05:13 +13:00
207 changed files with 4418 additions and 3323 deletions
+4 -1
View File
@@ -1,7 +1,10 @@
name: Build
on: [push, pull_request]
on:
pull_request:
push:
branches: master
jobs:
build:
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+7 -7
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -14,7 +14,7 @@
<properties>
<postgis.jdbc.version>2.5.1</postgis.jdbc.version>
<postgres.jdbc.version>42.6.0</postgres.jdbc.version>
<postgres.jdbc.version>42.7.2</postgres.jdbc.version>
</properties>
<dependencies>
@@ -22,13 +22,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -47,19 +47,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+8 -8
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,31 +17,31 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>13.24.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>13.24.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -60,13 +60,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
</parent>
<artifactId>composites</artifactId>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
</parent>
<name>ebean api</name>
@@ -39,7 +39,7 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-config</artifactId>
<version>3.10</version>
<version>3.12</version>
</dependency>
<dependency>
@@ -3,7 +3,7 @@ package io.ebean;
import jakarta.persistence.PersistenceException;
/**
* Thrown when a foreign key constraint is enforced.
* Thrown when a foreign key constraint is enforced or a field is too large.
*/
public class DataIntegrityException extends PersistenceException {
private static final long serialVersionUID = -6740171949170180970L;
@@ -14,4 +14,11 @@ public class DataIntegrityException extends PersistenceException {
public DataIntegrityException(String message, Throwable cause) {
super(message, cause);
}
/**
* Create with message only.
*/
public DataIntegrityException(String message) {
super(message);
}
}
+10 -10
View File
@@ -88,16 +88,16 @@ public interface Database {
/**
* Return a new database builder.
* <pre>{@code
*
* // build the 'default' database using configuration
* // from application.properties / application.yaml
*
* Database db = Database.builder()
* .loadFromProperties()
* .build();
*
* }</pre>
* <pre>{@code
*
* // build the 'default' database using configuration
* // from application.properties / application.yaml
*
* Database db = Database.builder()
* .loadFromProperties()
* .build();
*
* }</pre>
*/
static DatabaseBuilder builder() {
return new DatabaseConfig();
@@ -85,6 +85,7 @@ public interface DatabaseBuilder {
}
return this;
}
/**
* Set the name of the Database.
*/
@@ -2164,6 +2165,15 @@ public interface DatabaseBuilder {
@Deprecated
DatabaseBuilder setLoadModuleInfo(boolean loadModuleInfo);
/**
* Set if generated SQL SELECT should include the query label as an
* inline SQL comment (to help reference back from the SQL to the code
* that executed the query.
*
* @param includeLabelInSql When true include a SQL inline comment in generated SELECT queries.
*/
DatabaseConfig includeLabelInSql(boolean includeLabelInSql);
/**
* Set the naming convention to apply to metrics names.
*/
@@ -2177,6 +2187,11 @@ public interface DatabaseBuilder {
@Deprecated
DatabaseBuilder setMetricNaming(Function<String, String> metricNaming);
/**
* Sets the length check mode.
*/
DatabaseConfig lengthCheck(LengthCheck lengthCheck);
/**
* Provides read access (getters) for the DatabaseBuilder configuration
* that has been set.
@@ -3034,10 +3049,20 @@ public interface DatabaseBuilder {
*/
boolean isLoadModuleInfo();
/**
* Return true if generated sql select query should include an inline sql comment with the
* query label or profile location label.
*/
boolean isIncludeLabelInSql();
/**
* Return the naming convention to apply to metrics names.
*/
Function<String, String> getMetricNaming();
/**
* Returns the length check mode.
*/
LengthCheck getLengthCheck();
}
}
@@ -216,6 +216,8 @@ public interface ExpressionList<T> {
int delete();
/**
* @deprecated migrate to {@link #usingTransaction(Transaction)} then delete().
* <p>
* Execute as a delete query deleting the 'root level' beans that match the predicates
* in the query.
* <p>
@@ -225,6 +227,7 @@ public interface ExpressionList<T> {
*
* @return the number of rows that were deleted.
*/
@Deprecated(forRemoval = true, since = "13.1.0")
int delete(Transaction transaction);
/**
@@ -236,11 +239,14 @@ public interface ExpressionList<T> {
int update();
/**
* @deprecated migrate to {@link #usingTransaction(Transaction)} then update().
* <p>
* Execute as a update query with the given transaction.
*
* @return the number of rows that were updated.
* @see UpdateQuery
*/
@Deprecated(forRemoval = true, since = "13.1.0")
int update(Transaction transaction);
/**
@@ -412,6 +418,42 @@ public interface ExpressionList<T> {
*/
Optional<T> findOneOrEmpty();
/**
* Execute find row count query in a background thread.
* <p>
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
* @return a Future object for the row count query
*/
FutureRowCount<T> findFutureCount();
/**
* Execute find Id's query in a background thread.
* <p>
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
* @return a Future object for the list of Id's
*/
FutureIds<T> findFutureIds();
/**
* Execute find list query in a background thread.
* <p>
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
* @return a Future object for the list result of the query
*/
FutureList<T> findFutureList();
/**
* Return a PagedList for this query using firstRow and maxRows.
* <p>
@@ -0,0 +1,20 @@
package io.ebean;
import java.util.List;
import java.util.concurrent.Future;
/**
* FutureIds represents the result of a background query execution for the Id's.
* <p>
* It extends the java.util.concurrent.Future with the ability to get the Id's
* while the query is still executing in the background.
* </p>
*/
public interface FutureIds<T> extends Future<List<Object>> {
/**
* Returns the original query used to fetch the Id's.
*/
Query<T> getQuery();
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,903 @@
package io.ebean;
import io.avaje.lang.Nullable;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* Build and execute an ORM query.
*
* @param <SELF> The type of the builder
* @param <T> The entity bean type
*/
public interface QueryBuilder<SELF, T> extends QueryBuilderProjection<SELF, T> {
/**
* Set root table alias.
*/
SELF alias(String alias);
/**
* Apply changes to the query conditional on the supplied predicate.
* <p>
* Typically, the changes are extra predicates etc.
*
* @param predicate The predicate which when true the changes are applied
* @param apply The changes to apply to the query
*/
SELF alsoIf(BooleanSupplier predicate, Consumer<SELF> apply);
/**
* Perform an 'As of' query using history tables to return the object graph
* as of a time in the past.
* <p>
* To perform this query the DB must have underlying history tables.
*
* @param asOf the date time in the past at which you want to view the data
*/
SELF asOf(Timestamp asOf);
/**
* Convert the query to a DTO bean query.
* <p>
* We effectively use the underlying ORM query to build the SQL and then execute
* and map it into DTO beans.
*/
<D> DtoQuery<D> asDto(Class<D> dtoClass);
/**
* Convert the query to a UpdateQuery.
* <p>
* Typically this is used with query beans to covert a query bean
* query into an UpdateQuery like the examples below.
* </p>
*
* <pre>{@code
*
* int rowsUpdated = new QCustomer()
* .name.startsWith("Rob")
* .asUpdate()
* .set("active", false)
* .update();;
*
* }</pre>
*
* <pre>{@code
*
* int rowsUpdated = new QContact()
* .notes.note.startsWith("Make Inactive")
* .email.endsWith("@foo.com")
* .customer.id.equalTo(42)
* .asUpdate()
* .set("inactive", true)
* .setRaw("email = lower(email)")
* .update();
*
* }</pre>
*/
UpdateQuery<T> asUpdate();
/**
* Return a copy of the query.
* <p>
* This is so that you can use a Query as a "prototype" for creating other
* query instances. You could create a Query with various where expressions
* and use that as a "prototype" - using this copy() method to create a new
* instance that you can then add other expressions then execute.
* </p>
*/
SELF copy();
/**
* Execute the query using the given transaction.
*/
SELF usingTransaction(Transaction transaction);
/**
* Execute the query using the given connection.
*/
SELF usingConnection(Connection connection);
/**
* Execute the query using the given database.
*/
SELF usingDatabase(Database database);
/**
* 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
* 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
* against the master data source.
*/
SELF usingMaster();
/**
* Set the base table to use for this query.
* <p>
* Typically this is used when a table has partitioning and we wish to specify a specific
* partition/table to query against.
* </p>
* <pre>{@code
*
* QOrder()
* .setBaseTable("order_2019_05")
* .status.equalTo(Status.NEW)
* .findList();
*
* }</pre>
*/
SELF setBaseTable(String baseTable);
/**
* Specify the PersistenceContextScope to use for this query.
* <p>
* When this is not set the 'default' configured on {@link io.ebean.config.DatabaseConfig#setPersistenceContextScope(PersistenceContextScope)}
* is used - this value defaults to {@link PersistenceContextScope#TRANSACTION}.
* <p>
* Note that the same persistence Context is used for subsequent lazy loading and query join queries.
* <p>
* Note that #findEach uses a 'per object graph' PersistenceContext so this scope is ignored for
* queries executed as #findIterate, #findEach, #findEachWhile.
*
* @param scope The scope to use for this query and subsequent lazy loading.
*/
SELF setPersistenceContextScope(PersistenceContextScope scope);
/**
* Explicitly specify whether to use AutoTune for this query.
* <p>
* If you do not call this method on a query the "Implicit AutoTune mode" is
* used to determine if AutoTune should be used for a given query.
* <p>
* AutoTune can add additional fetch paths to the query and specify which
* properties are included for each path. If you have explicitly defined some
* fetch paths AutoTune will not remove them.
*/
SELF setAutoTune(boolean autoTune);
/**
* Execute the query allowing properties with invalid JSON to be collected and not fail the query.
* <pre>{@code
*
* // fetch a bean with JSON content
* EBasicJsonList bean= DB.find(EBasicJsonList.class)
* .setId(42)
* .setAllowLoadErrors() // collect errors into bean state if we have invalid JSON
* .findOne();
*
*
* // get the invalid JSON errors from the bean state
* Map<String, Exception> errors = server().getBeanState(bean).getLoadErrors();
*
* // If this map is not empty tell we have invalid JSON
* // and should try and fix the JSON content or inform the user
*
* }</pre>
*/
SELF setAllowLoadErrors();
/**
* Set the default lazy loading batch size to use.
* <p>
* When lazy loading is invoked on beans loaded by this query then this sets the
* batch size used to load those beans.
*
* @param lazyLoadBatchSize the number of beans to lazy load in a single batch
*/
SELF setLazyLoadBatchSize(int lazyLoadBatchSize);
/**
* Set a label on the query.
* <p>
* This label can be used to help identify query performance metrics but we can also use
* profile location enhancement on Finders so for some that would be a better option.
*/
SELF setLabel(String label);
/**
* Set a SQL query hint.
* <p>
* This results in an inline comment that immediately follows
* after the select keyword in the form: {@code /*+ hint *\/ }
*/
SELF setHint(String hint);
/**
* Execute the query including soft deleted rows.
* <p>
* This means that Ebean will not add any predicates to the query for filtering out
* soft deleted rows. You can still add your own predicates for the deleted properties
* and effectively you have full control over the query to include or exclude soft deleted
* rows as needed for a given use case.
*/
SELF setIncludeSoftDeletes();
/**
* Set true if you want to disable lazy loading.
* <p>
* That is, once the object graph is returned further lazy loading is disabled.
*/
SELF setDisableLazyLoading(boolean disableLazyLoading);
/**
* Set whether this query uses DISTINCT.
*/
SELF setDistinct(boolean distinct);
/**
* Set the first row to return for this query.
*
* @param firstRow the first row to include in the query result.
*/
SELF setFirstRow(int firstRow);
/**
* Set the maximum number of rows to return in the query.
*
* @param maxRows the maximum number of rows to return in the query.
*/
SELF setMaxRows(int maxRows);
/**
* Set RawSql to use for this query.
*/
SELF setRawSql(RawSql rawSql);
/**
* Extended version for setDistinct in conjunction with "findSingleAttributeList";
*
* <pre>{@code
*
* List<CountedValue<Order.Status>> orderStatusCount =
*
* DB.find(Order.class)
* .select("status")
* .where()
* .gt("orderDate", LocalDate.now().minusMonths(3))
*
* // fetch as single attribute with a COUNT
* .setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
* .findSingleAttributeList();
*
* for (CountedValue<Order.Status> entry : orderStatusCount) {
* System.out.println(" count:" + entry.getCount()+" orderStatus:" + entry.getValue() );
* }
*
* // produces
*
* count:3 orderStatus:NEW
* count:1 orderStatus:SHIPPED
* count:1 orderStatus:COMPLETE
*
* }</pre>
*/
SELF setCountDistinct(CountDistinctOrder orderBy);
/**
* Set the property to use as keys for a map.
* <p>
* If no property is set then the id property is used.
* </p>
* <pre>{@code
*
* // Assuming sku is unique for products...
*
* Map<String,Product> productMap = DB.find(Product.class)
* .setMapKey("sku") // sku map keys...
* .findMap();
*
* }</pre>
*
* @param mapKey the property to use as keys for a map.
*/
SELF setMapKey(String mapKey);
/**
* When set to true when you want the returned beans to be read only.
*/
SELF setReadOnly(boolean readOnly);
/**
* Set a timeout on this query.
* <p>
* This will typically result in a call to setQueryTimeout() on a
* preparedStatement. If the timeout occurs an exception will be thrown - this
* will be a SQLException wrapped up in a PersistenceException.
* </p>
*
* @param secs the query timeout limit in seconds. Zero means there is no limit.
*/
SELF setTimeout(int secs);
/**
* A hint which for JDBC translates to the Statement.fetchSize().
* <p>
* Gives the JDBC driver a hint as to the number of rows that should be
* fetched from the database when more rows are needed for ResultSet.
* </p>
* <p>
* Note that internally findEach and findEachWhile will set the fetch size
* if it has not already as these queries expect to process a lot of rows.
* If we didn't then Postgres and MySql for example would eagerly pull back
* all the row data and potentially consume a lot of memory in the process.
* </p>
* <p>
* As findEach and findEachWhile automatically set the fetch size we don't have
* to do so generally but we might still wish to for tuning a specific use case.
* </p>
*/
SELF setBufferFetchSizeHint(int fetchSize);
/**
* Set the mode to use the bean cache when executing this query.
* <p>
* By default, "find by id" and "find by natural key" will use the bean cache
* when bean caching is enabled. Setting this to false means that the query
* will not use the bean cache and instead hit the database.
* <p>
* By default, findList() with natural keys will not use the bean cache. In that
* case we need to explicitly use the bean cache.
*/
SELF setBeanCacheMode(CacheMode beanCacheMode);
/**
* Set the {@link CacheMode} to use the query for executing this query.
*/
SELF setUseQueryCache(CacheMode cacheMode);
/**
* Set this to false to not use the bean cache.
* <p>
* This method is now superseded by {@link #setBeanCacheMode(CacheMode)}
* which provides more explicit options controlled bean cache use.
* <p>
* This method is likely to be deprecated in the future with migration
* over to setUseBeanCache().
*/
default SELF setUseCache(boolean useCache) {
return setBeanCacheMode(useCache ? CacheMode.ON : CacheMode.OFF);
}
/**
* Calls {@link #setUseQueryCache(CacheMode)} with <code>ON</code> or <code>OFF</code>.
*/
default SELF setUseQueryCache(boolean enabled) {
return setUseQueryCache(enabled ? CacheMode.ON : CacheMode.OFF);
}
/**
* Set the order by clause replacing the existing order by clause if there is
* one.
* <p>
* This follows SQL syntax using commas between each property with the
* optional asc and desc keywords representing ascending and descending order
* respectively.
*/
SELF orderBy(String orderByClause);
/**
* Set an OrderBy object to replace any existing OrderBy clause.
*/
SELF setOrderBy(OrderBy<T> orderBy);
/**
* Controls, if paginated queries should always append an 'order by id' statement at the end to
* guarantee a deterministic sort result. This may affect performance.
* If this is not enabled, and an orderBy is set on the query, it's up to the programmer that
* this query provides a deterministic result.
*/
SELF orderById(boolean orderById);
/**
* Execute the query with the given lock type and WAIT.
* <p>
* Note that <code>forUpdate()</code> is the same as
* <code>withLock(LockType.UPDATE)</code>.
* <p>
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
SELF withLock(Query.LockType lockType);
/**
* Execute the query with the given lock type and lock wait.
* <p>
* Note that <code>forUpdateNoWait()</code> is the same as
* <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
* <p>
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
SELF withLock(Query.LockType lockType, Query.LockWait lockWait);
/**
* Execute using "for update" clause which results in the DB locking the record.
* <p>
* The same as <code>withLock(LockType.UPDATE, LockWait.WAIT)</code>.
*/
SELF forUpdate();
/**
* Execute using "for update" clause with "no wait" option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* <p>
* The same as <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
*/
SELF forUpdateNoWait();
/**
* Execute using "for update" clause with "skip locked" option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* <p>
* The same as <code>withLock(LockType.UPDATE, LockWait.SKIPLOCKED)</code>.
*/
SELF forUpdateSkipLocked();
/**
* Returns the set of properties or paths that are unknown (do not map to known properties or paths).
* <p>
* Validate the query checking the where and orderBy expression paths to confirm if
* they represent valid properties or paths for the given bean type.
*/
Set<String> validate();
/**
* Return the sql that was generated for executing this query.
* <p>
* This is only available after the query has been executed and provided only
* for informational purposes.
*/
String getGeneratedSql();
/**
* Return the type of beans being queried.
*/
Class<T> getBeanType();
/**
* Execute as a delete query deleting the 'root level' beans that match the predicates
* in the query.
* <p>
* Note that if the query includes joins then the generated delete statement may not be
* optimal depending on the database platform.
*
* @return the number of beans/rows that were deleted.
*/
int delete();
/**
* Execute the query returning true if a row is found.
* <p>
* The query is executed using max rows of 1 and will only select the id property.
* This method is really just a convenient way to optimise a query to perform a
* 'does a row exist in the db' check.
*
* <h2>Example using a query bean:</h2>
* <pre>{@code
*
* boolean userExists =
* new QContact()
* .email.equalTo("rob@foo.com")
* .exists();
*
* }</pre>
*
* <h2>Example:</h2>
* <pre>{@code
*
* boolean userExists = query()
* .where().eq("email", "rob@foo.com")
* .exists();
*
* }</pre>
*
* @return True if the query finds a matching row in the database
*/
boolean exists();
/**
* Execute the query returning either a single bean or null (if no matching
* bean is found).
* <p>
* If more than 1 row is found for this query then a PersistenceException is
* thrown.
* <p>
* This is useful when your predicates dictate that your query should only
* return 0 or 1 results.
* <p>
* <pre>{@code
*
* // assuming the sku of products is unique...
* Product product =
* new QProduct()
* .sku.equalTo("aa113")
* .findOne();
* ...
* }</pre>
* <p>
* It is also useful with finding objects by their id when you want to specify
* further join information to optimise the query.
* <p>
* <pre>{@code
*
* // Fetch order 42 and additionally fetch join its order details...
* Order order =
* new QOrder()
* .fetch("details") // eagerly load the order details
* .id.equalTo(42)
* .findOne();
*
* // the order details were eagerly loaded
* List<OrderDetail> details = order.getDetails();
* ...
* }</pre>
*/
@Nullable
T findOne();
/**
* Execute the query returning an optional bean.
*/
Optional<T> findOneOrEmpty();
/**
* Execute the query returning the list of objects.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* <p>
* <pre>{@code
*
* List<Customer> customers =
* new QCustomer()
* .name.ilike("rob%")
* .findList();
*
* }</pre>
*
* @see Query#findList()
*/
List<T> findList();
/**
* Execute the query returning the result as a Stream.
* <p>
* Note that this can support very large queries iterating
* any number of results. To do so internally it can use
* multiple persistence contexts.
* </p>
* <pre>{@code
*
* // use try with resources to ensure Stream is closed
*
* try (Stream<Customer> stream = query.findStream()) {
* stream
* .map(...)
* .collect(...);
* }
*
* }</pre>
*/
Stream<T> findStream();
/**
* Execute the query returning the set of objects.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* <p>
* <pre>{@code
*
* Set<Customer> customers =
* new QCustomer()
* .name.ilike("rob%")
* .findSet();
*
* }</pre>
*
* @see Query#findSet()
*/
Set<T> findSet();
/**
* Execute the query returning the list of Id's.
* <p>
* This query will execute against the EbeanServer that was used to create it.
*
* @see Query#findIds()
*/
<A> List<A> findIds();
/**
* Execute the query returning a map of the objects.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* <p>
* You can use setMapKey() or asMapKey() to specify the property to be used as keys
* on the map. If one is not specified then the id property is used.
* <p>
* <pre>{@code
*
* Map<String, Product> map =
* new QProduct()
* .sku.asMapKey()
* .findMap();
*
* }</pre>
*
* @see Query#findMap()
*/
<K> Map<K, T> findMap();
/**
* Execute the query iterating over the results.
* <p>
* Note that findIterate (and findEach and findEachWhile) uses a "per graph"
* persistence context scope and adjusts jdbc fetch buffer size for large
* queries. As such it is better to use findList for small queries.
* <p>
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
* when you have finished iterating the results (typically in a finally block).
* <p>
* findEach() and findEachWhile() are preferred to findIterate() as they ensure
* the jdbc statement and resultSet are closed at the end of the iteration.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
* <pre>{@code
*
* Query<Customer> query =
* new QCustomer()
* .status.equalTo(Customer.Status.NEW)
* .orderBy()
* id.asc()
* .query();
*
* try (QueryIterator<Customer> it = query.findIterate()) {
* while (it.hasNext()) {
* Customer customer = it.next();
* // do something with customer ...
* }
* }
*
* }</pre>
*/
QueryIterator<T> findIterate();
/**
* Execute the query returning a list of values for a single property.
* <p>
* <h3>Example</h3>
* <pre>{@code
*
* List<String> names =
* new QCustomer()
* .setDistinct(true)
* .select(name)
* .findSingleAttributeList();
*
* }</pre>
*
* @return the list of values for the selected property
*/
<A> List<A> findSingleAttributeList();
/**
* Execute the query returning a single value or null for a single property.
* <p>
* <h3>Example</h3>
* <pre>{@code
*
* LocalDate maxDate =
* new QCustomer()
* .select("max(startDate)")
* .findSingleAttribute();
*
* }</pre>
*
* @return a single value or null for the selected property
*/
@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();
/**
* Execute the query returning a hashset of values for a single property.
*/
<A> Set<A> findSingleAttributeSet();
/**
* Execute the query processing the beans one at a time.
* <p>
* This method is appropriate to process very large query results as the
* beans are consumed one at a time and do not need to be held in memory
* (unlike #findList #findSet etc)
* <p>
* Note that internally Ebean can inform the JDBC driver that it is expecting larger
* resultSet and specifically for MySQL this hint is required to stop it's JDBC driver
* from buffering the entire resultSet. As such, for smaller resultSets findList() is
* generally preferable.
* <p>
* Compared with #findEachWhile this will always process all the beans where as
* #findEachWhile provides a way to stop processing the query result early before
* all the beans have been read.
* <p>
* This method is functionally equivalent to findIterate() but instead of using an
* iterator uses the Consumer interface which is better suited to use with closures.
*
* <pre>{@code
*
* new QCustomer()
* .status.equalTo(Status.NEW)
* .orderBy().id.asc()
* .findEach((Customer customer) -> {
*
* // do something with customer
* System.out.println("-- visit " + customer);
* });
*
* }</pre>
*
* @param consumer the consumer used to process the queried beans.
*/
void findEach(Consumer<T> consumer);
/**
* Execute findEach streaming query batching the results for consuming.
* <p>
* This query execution will stream the results and is suited to consuming
* large numbers of results from the database.
* <p>
* Typically, we use this batch consumer when we want to do further processing on
* the beans and want to do that processing in batch form, for example - 100 at
* a time.
*
* @param batch The number of beans processed in the batch
* @param consumer Process the batch of beans
*/
void findEach(int batch, Consumer<List<T>> consumer);
/**
* Execute the query using callbacks to a visitor to process the resulting
* beans one at a time.
* <p>
* This method is functionally equivalent to findIterate() but instead of using an
* iterator uses the Predicate interface which is better suited to use with closures.
*
* <pre>{@code
*
* new QCustomer()
* .status.equalTo(Status.NEW)
* .orderBy().id.asc()
* .findEachWhile((Customer customer) -> {
*
* // do something with customer
* System.out.println("-- visit " + customer);
*
* // return true to continue processing or false to stop
* return (customer.getId() < 40);
* });
*
* }</pre>
*
* @param consumer the consumer used to process the queried beans.
*/
void findEachWhile(Predicate<T> consumer);
/**
* Return versions of a @History entity bean.
* <p>
* Generally this query is expected to be a find by id or unique predicates query.
* It will execute the query against the history returning the versions of the bean.
*/
List<Version<T>> findVersions();
/**
* Return versions of a @History entity bean between a start and end timestamp.
* <p>
* Generally this query is expected to be a find by id or unique predicates query.
* It will execute the query against the history returning the versions of the bean.
*/
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
/**
* Return the count of entities this query should return.
* <p>
* This is the number of 'top level' or 'root level' entities.
*/
int findCount();
/**
* Execute find row count query in a background thread.
* <p>
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a
* timeout).
*
* @return a Future object for the row count query
*/
FutureRowCount<T> findFutureCount();
/**
* Execute find Id's query in a background thread.
* <p>
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a
* timeout).
*
* @return a Future object for the list of Id's
*/
FutureIds<T> findFutureIds();
/**
* Execute find list query in a background thread.
* <p>
* This query will execute in it's own PersistenceContext and using its own transaction.
* What that means is that it will not share any bean instances with other queries.
*
* @return a Future object for the list result of the query
*/
FutureList<T> findFutureList();
/**
* Return a PagedList for this query using firstRow and maxRows.
* <p>
* The benefit of using this over findList() is that it provides functionality to get the
* total row count etc.
* <p>
* If maxRows is not set on the query prior to calling findPagedList() then a
* PersistenceException is thrown.
* <p>
* <pre>{@code
*
* PagedList<Order> pagedList =
* new QOrder()
* .setFirstRow(50)
* .setMaxRows(20)
* .findPagedList();
*
* // fetch the total row count in the background
* pagedList.loadRowCount();
*
* List<Order> orders = pagedList.getList();
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*
* @return The PagedList
*/
PagedList<T> findPagedList();
}
@@ -0,0 +1,242 @@
package io.ebean;
/**
* Builder for ORM Query projection (the select and fetch part).
*
* @param <SELF> The builder type
* @param <T> The entity bean type
*/
public interface QueryBuilderProjection<SELF, T> {
/**
* Apply the path properties replacing the select and fetch clauses.
* <p>
* This is typically used when the FetchPath is applied to both the query and the JSON output.
*/
SELF apply(FetchPath fetchPath);
/**
* Specify the properties to fetch on the root level entity bean in comma delimited format.
* <p>
* The Id property is automatically included in the properties to fetch unless setDistinct(true)
* is set on the query.
* </p>
* <p>
* Use {@link #fetch(String, String)} to specify specific properties to fetch
* on other non-root level paths of the object graph.
* </p>
* <pre>{@code
*
* List<Customer> customers = DB.find(Customer.class)
* // Only fetch the customer id, name and status.
* // This is described as a "Partial Object"
* .select("name, status")
* .where.ilike("name", "rob%")
* .findList();
*
* }</pre>
*
* @param fetchProperties the properties to fetch for this bean (* = all properties).
*/
SELF select(String fetchProperties);
/**
* Apply the fetchGroup which defines what part of the object graph to load.
*/
SELF select(FetchGroup<T> fetchGroup);
/**
* Specify a path to fetch eagerly including specific properties.
* <p>
* Ebean will endeavour to fetch this path using a SQL join. If Ebean determines that it can
* not use a SQL join (due to maxRows or because it would result in a cartesian product) Ebean
* will automatically convert this fetch query into a "query join" - i.e. use fetchQuery().
* </p>
* <pre>{@code
*
* // query orders...
* List<Order> orders = DB.find(Order.class)
* // fetch the customer...
* // ... getting the customers name and phone number
* .fetch("customer", "name, phoneNumber")
*
* // ... also fetch the customers billing address (* = all properties)
* .fetch("customer.billingAddress", "*")
* .findList();
* }</pre>
* <p>
* If columns is null or "*" then all columns/properties for that path are fetched.
* </p>
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers = DB.find(Customer.class)
* .select("name, status")
* .fetch("contacts", "firstName,lastName,email")
* .findList();
*
* }</pre>
*
* @param path the property path we wish to fetch eagerly.
* @param fetchProperties properties of the associated bean that you want to include in the
* fetch (* means all properties, null also means all properties).
*/
SELF fetch(String path, String fetchProperties);
/**
* Fetch the path and properties using a "query join" (separate SQL query).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, fetchProperties, FetchConfig.ofQuery())
*
* }</pre>
* <p>
* This would be used instead of a fetch() when we use a separate SQL query to fetch this
* part of the object graph rather than a SQL join.
* <p>
* We might typically get a performance benefit when the path to fetch is a OneToMany
* or ManyToMany, the 'width' of the 'root bean' is wide and the cardinality of the many
* is high.
*
* @param path the property path we wish to fetch eagerly.
* @param fetchProperties properties of the associated bean that you want to include in the
* fetch (* means all properties, null also means all properties).
*/
SELF fetchQuery(String path, String fetchProperties);
/**
* Fetch the path and properties using L2 bean cache.
*
* @param path The path of the beans we are fetching from L2 cache.
* @param fetchProperties The properties that should be loaded.
*/
SELF fetchCache(String path, String fetchProperties);
/**
* Fetch the path and properties lazily (via batch lazy loading).
* <p>
* This is the same as:
*
* <pre>{@code
*
* fetch(path, fetchProperties, FetchConfig.ofLazy())
*
* }</pre>
* <p>
* The reason for using fetchLazy() is to either:
* <ul>
* <li>Control/tune what is fetched as part of lazy loading</li>
* <li>Make use of the L2 cache, build this part of the graph from L2 cache</li>
* </ul>
*
* @param path the property path we wish to fetch lazily.
* @param fetchProperties properties of the associated bean that you want to include in the
* fetch (* means all properties, null also means all properties).
*/
SELF fetchLazy(String path, String fetchProperties);
/**
* Additionally specify a FetchConfig to use a separate query or lazy loading
* to load this path.
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers = DB.find(Customer.class)
* .select("name, status")
* .fetch("contacts", "firstName,lastName,email", FetchConfig.ofLazy(10))
* .findList();
*
* }</pre>
*
* @param path the property path we wish to fetch eagerly.
*/
SELF fetch(String path, String fetchProperties, FetchConfig fetchConfig);
/**
* Specify a path to fetch eagerly including all its properties.
* <p>
* Ebean will endeavour to fetch this path using a SQL join. If Ebean determines that it can
* not use a SQL join (due to maxRows or because it would result in a cartesian product) Ebean
* will automatically convert this fetch query into a "query join" - i.e. use fetchQuery().
* </p>
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers = DB.find(Customer.class)
* // eager fetch the contacts
* .fetch("contacts")
* .findList();
*
* }</pre>
*
* @param path the property path we wish to fetch eagerly.
*/
SELF fetch(String path);
/**
* Fetch the path eagerly using a "query join" (separate SQL query).
* <p>
* This is the same as:
* <pre>{@code
*
* fetch(path, FetchConfig.ofQuery())
*
* }</pre>
* <p>
* This would be used instead of a fetch() when we use a separate SQL query to fetch this
* part of the object graph rather than a SQL join.
* <p>
* We might typically get a performance benefit when the path to fetch is a OneToMany
* or ManyToMany, the 'width' of the 'root bean' is wide and the cardinality of the many
* is high.
*
* @param path the property path we wish to fetch eagerly
*/
SELF fetchQuery(String path);
/**
* Fetch the path eagerly using L2 cache.
*/
SELF fetchCache(String path);
/**
* Fetch the path lazily (via batch lazy loading).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, FetchConfig.ofLazy())
*
* }</pre>
* <p>
* The reason for using fetchLazy() is to either:
* </p>
* <ul>
* <li>Control/tune what is fetched as part of lazy loading</li>
* <li>Make use of the L2 cache, build this part of the graph from L2 cache</li>
* </ul>
*
* @param path the property path we wish to fetch lazily.
*/
SELF fetchLazy(String path);
/**
* Additionally specify a JoinConfig to specify a "query join" and or define
* the lazy loading query.
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers = DB.find(Customer.class)
* // lazy fetch contacts with a batch size of 100
* .fetch("contacts", FetchConfig.ofLazy(100))
* .findList();
*
* }</pre>
*/
SELF fetch(String path, FetchConfig fetchConfig);
}
@@ -1,8 +1,5 @@
package io.ebean.config;
import io.avaje.config.Config;
import io.avaje.config.Configuration;
import java.util.Properties;
/**
@@ -19,16 +16,6 @@ public class ContainerConfig {
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.
@@ -104,7 +91,7 @@ public class ContainerConfig {
* Return the deployment properties.
*/
public Properties getProperties() {
return properties != null ? properties : configuration.asProperties();
return properties;
}
/**
@@ -114,4 +101,25 @@ 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)));
}
}
@@ -123,6 +123,12 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
*/
private boolean loadModuleInfo = true;
/**
* When true then include a sql comment in generated SELECT queries with the query
* label or profile location label.
*/
private boolean includeLabelInSql;
/**
* Interesting classes such as entities, embedded, ScalarTypes,
* Listeners, Finders, Controllers, AttributeConverters etc.
@@ -531,6 +537,8 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
private String dumpMetricsOptions;
private LengthCheck lengthCheck = LengthCheck.OFF;
private Function<String, String> metricNaming = MetricNamingMatch.INSTANCE;
/**
@@ -2061,6 +2069,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
readOnlyDatabase = p.getBoolean("readOnlyDatabase", readOnlyDatabase);
autoPersistUpdates = p.getBoolean("autoPersistUpdates", autoPersistUpdates);
loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo);
includeLabelInSql = p.getBoolean("includeLabelInSql", includeLabelInSql);
maxCallStack = p.getInt("maxCallStack", maxCallStack);
dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown);
dumpMetricsOptions = p.get("dumpMetricsOptions", dumpMetricsOptions);
@@ -2124,6 +2133,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
jdbcFetchSizeFindEach = p.getInt("jdbcFetchSizeFindEach", jdbcFetchSizeFindEach);
jdbcFetchSizeFindList = p.getInt("jdbcFetchSizeFindList", jdbcFetchSizeFindList);
databasePlatformName = p.get("databasePlatformName", databasePlatformName);
lengthCheck = p.getEnum(LengthCheck.class, "lengthCheck", lengthCheck);
uuidVersion = p.getEnum(UuidVersion.class, "uuidVersion", uuidVersion);
uuidStateFile = p.get("uuidStateFile", uuidStateFile);
@@ -2473,6 +2483,11 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
return loadModuleInfo;
}
@Override
public boolean isIncludeLabelInSql() {
return includeLabelInSql;
}
/**
* @deprecated - migrate to {@link #isLoadModuleInfo()}.
*/
@@ -2489,6 +2504,12 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
return this;
}
@Override
public DatabaseConfig includeLabelInSql(boolean includeLabelInSql) {
this.includeLabelInSql = includeLabelInSql;
return this;
}
@Override
public Function<String, String> getMetricNaming() {
return metricNaming;
@@ -2500,6 +2521,19 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
return this;
}
/**
* Returns the length check mode.
*/
public LengthCheck getLengthCheck() {
return lengthCheck;
}
@Override
public DatabaseConfig lengthCheck(LengthCheck lengthCheck) {
this.lengthCheck = lengthCheck;
return this;
}
public enum UuidVersion {
VERSION4,
VERSION1,
@@ -0,0 +1,22 @@
package io.ebean.config;
/**
* Defines the length-check mode.
*
* @author Roland Praml, FOCONIS AG
*/
public enum LengthCheck {
/**
* By default, length checking is off. This means, strings/jsons and files are passed to the DB and the DB might or might not check the length.
* The DB has to check the data length. Note this is not possible for certain datatypes (e.g. clob without size)
*/
OFF,
/**
* When enabling length check, ebean validates strings/json strings and files before saving them to DB.
*/
ON,
/**
* Same as "ON", but take the UTF8-bytelength for validation. This may be useful, if you have an UTF8 based charset (default for DB2)
*/
UTF8
}
@@ -1,50 +1,29 @@
package io.ebean.config;
import io.ebean.ProfileLocation;
import io.ebean.bean.ObjectGraphNode;
import java.util.List;
/**
* Slow query event.
* The data for the slow query.
*/
public class SlowQueryEvent {
private final String sql;
private final long timeMillis;
private final int rowCount;
private final ObjectGraphNode originNode;
/**
* Construct with the SQL and execution time in millis.
*/
public SlowQueryEvent(String sql, long timeMillis, int rowCount, ObjectGraphNode originNode) {
this.sql = sql;
this.timeMillis = timeMillis;
this.rowCount = rowCount;
this.originNode = originNode;
}
public interface SlowQueryEvent {
/**
* Return the SQL for the slow query.
*/
public String getSql() {
return sql;
}
String getSql();
/**
* Return the execution time in millis.
*/
public long getTimeMillis() {
return timeMillis;
}
long getTimeMillis();
/**
* Return the total row count associated with the query.
*/
public int getRowCount() {
return rowCount;
}
int getRowCount();
/**
* Return the origin point for the root query.
@@ -53,7 +32,20 @@ public class SlowQueryEvent {
* shows the code that invoked the query.
* </p>
*/
public ObjectGraphNode getOriginNode() {
return originNode;
}
ObjectGraphNode getOriginNode();
/**
* Return the bind parameters.
*/
List<Object> getBindParams();
/**
* Return the label.
*/
String getLabel();
/**
* Return the profile location.
*/
ProfileLocation getProfileLocation();
}
@@ -769,4 +769,15 @@ public class DatabasePlatform {
public boolean supportsNativeJavaTime() {
return supportsNativeJavaTime;
}
public String inlineSqlComment(String label) {
if (label == null) {
return "";
}
return "/* " + label + " */ ";
}
public String inlineSqlHint(String hint) {
return "/*+ " + hint + " */ ";
}
}
@@ -8,6 +8,7 @@ import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
@@ -23,7 +24,7 @@ public final class ShutdownManager {
private static final System.Logger log = EbeanVersion.log;
private static final ReentrantLock lock = new ReentrantLock();
private static final List<Database> databases = new ArrayList<>();
private static final List<Database> databases = Collections.synchronizedList(new ArrayList<>());
private static final ShutdownHook shutdownHook = new ShutdownHook();
private static boolean stopping;
@@ -177,12 +178,7 @@ public final class ShutdownManager {
* Register an ebeanServer to be shutdown when the JVM is shutdown.
*/
public static void registerDatabase(Database server) {
lock.lock();
try {
databases.add(server);
} finally {
lock.unlock();
}
databases.add(server);
}
/**
@@ -192,12 +188,7 @@ public final class ShutdownManager {
* </p>
*/
public static void unregisterDatabase(Database server) {
lock.lock();
try {
databases.remove(server);
} finally {
lock.unlock();
}
databases.remove(server);
}
private static class ShutdownHook extends Thread {
@@ -22,6 +22,8 @@ public class JsonWriteOptions {
protected JsonConfig.Include include;
protected boolean includeLoadedImplicit = true;
protected Map<String, JsonWriteBeanVisitor<?>> visitorMap;
/**
@@ -73,6 +75,20 @@ public class JsonWriteOptions {
this.include = include;
}
/**
* Should loaded properties be included implicit, if no other fetch path is specified (default = true).
*/
public boolean isIncludeLoadedImplicit() {
return includeLoadedImplicit;
}
/**
* Set include loaded properties implicit (default = true).
*/
public void setIncludeLoadedImplicit(boolean includeLoadedImplicit) {
this.includeLoadedImplicit = includeLoadedImplicit;
}
/**
* Register a JsonWriteBeanVisitor for the root level.
*/
@@ -75,6 +75,8 @@ class DatabaseConfigTest {
props.setProperty("defaultServer", "false");
props.setProperty("skipDataSourceCheck", "true");
props.setProperty("readOnlyDatabase", "true");
props.setProperty("lengthCheck", "ON");
props.setProperty("includeLabelInSql", "true");
props.setProperty("queryPlan.enable", "true");
props.setProperty("queryPlan.thresholdMicros", "10000");
@@ -95,6 +97,8 @@ class DatabaseConfigTest {
assertTrue(settings.isLoadModuleInfo());
assertTrue(settings.skipDataSourceCheck());
assertTrue(settings.readOnlyDatabase());
assertTrue(settings.isIncludeLabelInSql());
assertThat(settings.getLengthCheck()).isEqualTo(LengthCheck.ON);
assertTrue(settings.isIdGeneratorAutomatic());
assertFalse(settings.getPlatformConfig().isCaseSensitiveCollation());
@@ -128,8 +132,11 @@ class DatabaseConfigTest {
assertThat(settings.getMappingLocations()).containsExactly("classpath:/foo","bar");
config.setPersistBatch(PersistBatch.NONE);
config.setPersistBatchOnCascade(PersistBatch.NONE);
config.persistBatch(PersistBatch.NONE)
.persistBatchOnCascade(PersistBatch.NONE)
.lengthCheck(LengthCheck.ON)
.lengthCheck(LengthCheck.UTF8);
Properties props1 = new Properties();
props1.setProperty("ebean.persistBatch", "ALL");
@@ -146,6 +153,7 @@ class DatabaseConfigTest {
assertEquals(PersistBatch.ALL, settings.getPersistBatch());
assertEquals(PersistBatch.ALL, settings.getPersistBatchOnCascade());
assertEquals(LengthCheck.UTF8, settings.getLengthCheck());
config.setEnabledL2Regions("r0,orgs");
assertEquals("r0,orgs", settings.getEnabledL2Regions());
@@ -174,6 +182,8 @@ class DatabaseConfigTest {
assertEquals(600, config.getQueryPlanCapturePeriodSecs());
assertEquals(10000L, config.getQueryPlanCaptureMaxTimeMillis());
assertEquals(10, config.getQueryPlanCaptureMaxCount());
assertThat(config.getLengthCheck()).isEqualTo(LengthCheck.OFF);
assertFalse(config.isIncludeLabelInSql());
config.setLoadModuleInfo(false);
assertFalse(config.isAutoLoadModuleInfo());
+31 -31
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
</parent>
<name>ebean bom</name>
@@ -89,103 +89,103 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>13.24.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>13.24.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>13.18.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>13.18.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>13.18.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-spring-txn</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<!-- platforms -->
@@ -193,79 +193,79 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-clickhouse</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-db2</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-h2</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-hana</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mariadb</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mysql</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-nuodb</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-oracle</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgres</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlite</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlserver</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -30,7 +30,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version>
<version>42.7.2</version>
<optional>true</optional>
</dependency>
@@ -174,4 +174,9 @@ public interface DataBinder {
*/
String popJson();
/**
* Returns the last bound object (e.g. for BindValidation). Note for InputStreams you'll get an InputStreamInfo.
*/
Object popLastObject();
}
@@ -0,0 +1,27 @@
package io.ebean.core.type;
import java.io.InputStream;
/**
* Helper to transports length info of DataBind.setBinaryStream(stream, length) to BindValidation
*
* @author Roland Praml, FOCONIS AG
*/
public final class InputStreamInfo {
private final InputStream stream;
private final long length;
public InputStreamInfo(InputStream stream, long length) {
this.stream = stream;
this.length = length;
}
public InputStream stream() {
return stream;
}
public long length() {
return length;
}
}
+7 -7
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.0.0</version>
<version>14.1.0</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -22,7 +22,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -46,7 +46,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
</dependency>
<!--
@@ -139,7 +139,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version>
<version>42.7.2</version>
<optional>true</optional>
</dependency>
@@ -147,21 +147,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>14.0.0</version>
<version>14.1.0</version>
<scope>test</scope>
</dependency>
@@ -3,6 +3,7 @@ package io.ebeaninternal.api;
import io.ebean.CacheMode;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.server.core.BindPadding;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -57,17 +58,22 @@ public final class LoadManyRequest extends LoadRequest {
return loadContext.fullPath();
}
private List<Object> parentIdList(SpiEbeanServer server) {
List<Object> idList = new ArrayList<>();
BeanPropertyAssocMany<?> many = many();
private List<Object> parentIdList(SpiEbeanServer server, BeanPropertyAssocMany<?> many, PersistenceContext pc) {
final var idList = new ArrayList<>(loadContext.size());
final var descriptor = many.descriptor();
for (int i = 0; i < loadContext.size(); i++) {
BeanCollection<?> bc = loadContext.get(i);
final BeanCollection<?> bc = loadContext.get(i);
if (bc != null) {
if (lazy && !originIncluded && bc == originCollection) {
originIncluded = true;
}
idList.add(many.parentId(bc.owner()));
final var parent = bc.owner();
final var parentId = descriptor.getId(parent);
idList.add(parentId);
bc.setLoader(server); // don't use the load buffer again
if (lazy) {
descriptor.contextPutIfAbsent(pc, parentId, parent);
if (!originIncluded && bc == originCollection) {
originIncluded = true;
}
}
}
}
if (originCollection != null && !originIncluded) {
@@ -75,7 +81,7 @@ public final class LoadManyRequest extends LoadRequest {
idList.add(many.parentId(originCollection.owner()));
originCollection.setLoader(server); // don't use the load buffer again
}
if (many.targetDescriptor().isPadInExpression()) {
if (descriptor.isPadInExpression()) {
BindPadding.padIds(idList);
}
return idList;
@@ -99,8 +105,9 @@ public final class LoadManyRequest extends LoadRequest {
query.where().raw(extraWhere.replace("${ta}", "t0").replace("${mta}", "int_"));
}
query.setLazyLoadForParents(many);
many.addWhereParentIdIn(query, parentIdList(server));
query.setPersistenceContext(loadContext.persistenceContext());
final var pc = loadContext.persistenceContext();
many.addWhereParentIdIn(query, parentIdList(server, many, pc));
query.setPersistenceContext(pc);
query.setLoadDescription(lazy ? "lazy" : "query", description());
if (lazy) {
query.setLazyLoadBatchSize(loadContext.batchSize());
@@ -336,6 +336,10 @@ public interface SpiEbeanServer extends SpiServer, ExtendedServer, BeanCollectio
<T> FutureRowCount<T> findFutureCount(SpiQuery<T> query);
<T> FutureIds<T> findFutureIds(SpiQuery<T> query);
<T> FutureList<T> findFutureList(SpiQuery<T> query);
<T> PagedList<T> findPagedList(SpiQuery<T> query);
<T> Set<T> findSet(SpiQuery<T> query);
@@ -71,7 +71,7 @@ public interface SpiExpression extends Expression {
*
* @param request the associated request.
*/
void addBindValues(SpiExpressionRequest request);
void addBindValues(SpiExpressionBind request);
/**
* Validate all the properties/paths associated with this expression.
@@ -0,0 +1,29 @@
package io.ebeaninternal.api;
import io.ebeaninternal.server.deploy.BeanDescriptor;
/**
* Expression bind values capture.
*/
public interface SpiExpressionBind {
/**
* Return the bean descriptor for the root type.
*/
BeanDescriptor<?> descriptor();
/**
* Add an encryption key to bind to this request.
*/
void addBindEncryptKey(Object encryptKey);
/**
* Add a bind value to this request.
*/
void addBindValue(Object bindValue);
/**
* Escapes a string to use it as exact match in Like clause.
*/
String escapeLikeString(String value);
}
@@ -1,15 +1,15 @@
package io.ebeaninternal.api;
import io.ebeaninternal.server.core.SpiOrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
import io.ebeaninternal.server.expression.platform.DbExpressionRequest;
import java.util.List;
/**
* Request object used for gathering expression sql and bind values.
*/
public interface SpiExpressionRequest {
public interface SpiExpressionRequest extends SpiExpressionBind, DbExpressionRequest {
/**
* Return the DB specific handler for JSON and ARRAY expressions.
@@ -21,11 +21,6 @@ public interface SpiExpressionRequest {
*/
String parseDeploy(String logicalProp);
/**
* Return the bean descriptor for the root type.
*/
BeanDescriptor<?> descriptor();
/**
* Return the associated QueryRequest.
*/
@@ -34,11 +29,13 @@ public interface SpiExpressionRequest {
/**
* Append to the expression sql without any parsing.
*/
@Override
SpiExpressionRequest append(String expression);
/**
* Append to the expression sql without any parsing.
*/
@Override
SpiExpressionRequest append(char c);
/**
@@ -47,6 +44,7 @@ public interface SpiExpressionRequest {
* This is a fast path case when expression is a bean property path and falls back to using parse()
* when that isn't the case.
*/
@Override
SpiExpressionRequest property(String expression);
/**
@@ -54,16 +52,6 @@ public interface SpiExpressionRequest {
*/
SpiExpressionRequest parse(String expression);
/**
* Add an encryption key to bind to this request.
*/
void addBindEncryptKey(Object encryptKey);
/**
* Add a bind value to this request.
*/
void addBindValue(Object bindValue);
/**
* Return the accumulated expression sql for all expressions in this request.
*/
@@ -84,11 +72,6 @@ public interface SpiExpressionRequest {
*/
void appendLike(boolean rawLikeExpression);
/**
* Escapes a string to use it as exact match in Like clause.
*/
String escapeLikeString(String value);
/**
* Append IN expression taking into account platform and type support for Multi-value.
*/
@@ -220,6 +220,11 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
*/
ProfileLocation profileLocation();
/**
* Return the SQL hint to include in the query.
*/
String hint();
/**
* Return the label set on the query.
*/
@@ -1,10 +1,14 @@
package io.ebeaninternal.server.bind;
import io.ebean.core.type.DataBinder;
import io.ebean.core.type.InputStreamInfo;
import io.ebeaninternal.api.CoreLog;
import io.ebeaninternal.server.core.timezone.DataTimeZone;
import java.io.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.math.BigDecimal;
import java.sql.*;
import java.util.ArrayList;
@@ -23,6 +27,8 @@ public class DataBind implements DataBinder {
protected int pos;
private String json;
private Object lastObject = null;
public DataBind(DataTimeZone dataTimeZone, PreparedStatement pstmt, Connection connection) {
this.dataTimeZone = dataTimeZone;
this.pstmt = pstmt;
@@ -65,16 +71,19 @@ public class DataBind implements DataBinder {
@Override
public void setObject(Object value) throws SQLException {
pstmt.setObject(++pos, value);
lastObject = value;
}
@Override
public final void setObject(Object value, int sqlType) throws SQLException {
pstmt.setObject(++pos, value, sqlType);
lastObject = value;
}
@Override
public void setNull(int jdbcType) throws SQLException {
pstmt.setNull(++pos, jdbcType);
lastObject = null;
}
@Override
@@ -96,7 +105,7 @@ public class DataBind implements DataBinder {
}
}
private void closeInputStreams() {
public void closeInputStreams() {
if (inputStreams != null) {
for (InputStream inputStream : inputStreams) {
try {
@@ -117,36 +126,43 @@ public class DataBind implements DataBinder {
@Override
public void setString(String value) throws SQLException {
pstmt.setString(++pos, value);
lastObject = value;
}
@Override
public final void setInt(int value) throws SQLException {
pstmt.setInt(++pos, value);
lastObject = null;
}
@Override
public final void setLong(long value) throws SQLException {
pstmt.setLong(++pos, value);
lastObject = null;
}
@Override
public final void setShort(short value) throws SQLException {
pstmt.setShort(++pos, value);
lastObject = null;
}
@Override
public final void setFloat(float value) throws SQLException {
pstmt.setFloat(++pos, value);
lastObject = null;
}
@Override
public final void setDouble(double value) throws SQLException {
pstmt.setDouble(++pos, value);
lastObject = null;
}
@Override
public final void setBigDecimal(BigDecimal value) throws SQLException {
pstmt.setBigDecimal(++pos, value);
lastObject = null;
}
@Override
@@ -157,6 +173,7 @@ public class DataBind implements DataBinder {
} else {
pstmt.setDate(++pos, value);
}
lastObject = null;
}
@Override
@@ -167,6 +184,7 @@ public class DataBind implements DataBinder {
} else {
pstmt.setTimestamp(++pos, value);
}
lastObject = null;
}
@Override
@@ -177,26 +195,31 @@ public class DataBind implements DataBinder {
} else {
pstmt.setTime(++pos, value);
}
lastObject = null;
}
@Override
public void setBoolean(boolean value) throws SQLException {
pstmt.setBoolean(++pos, value);
lastObject = null;
}
@Override
public void setBytes(byte[] value) throws SQLException {
pstmt.setBytes(++pos, value);
lastObject = value;
}
@Override
public void setByte(byte value) throws SQLException {
pstmt.setByte(++pos, value);
lastObject = null;
}
@Override
public void setChar(char value) throws SQLException {
pstmt.setString(++pos, String.valueOf(value));
lastObject = null;
}
@Override
@@ -211,21 +234,31 @@ public class DataBind implements DataBinder {
}
inputStreams.add(inputStream);
pstmt.setBinaryStream(++pos, inputStream, length);
lastObject = new InputStreamInfo(inputStream, length);
}
@Override
public void setBlob(byte[] bytes) throws SQLException {
pstmt.setBinaryStream(++pos, new ByteArrayInputStream(bytes), bytes.length);
lastObject = bytes;
}
@Override
public void setClob(String content) throws SQLException {
pstmt.setCharacterStream(++pos, new StringReader(content), content.length());
lastObject = content;
}
@Override
public void setArray(String arrayType, Object[] elements) throws SQLException {
pstmt.setArray(++pos, connection.createArrayOf(arrayType, elements));
lastObject = null;
}
@Override
public Object popLastObject() {
Object ret = lastObject;
lastObject = null;
return ret;
}
}
@@ -0,0 +1,70 @@
package io.ebeaninternal.server.core;
import io.ebean.ProfileLocation;
import io.ebean.bean.ObjectGraphNode;
import io.ebean.config.SlowQueryEvent;
import java.util.List;
/**
* Slow query event.
*/
final class DSlowQueryEvent implements SlowQueryEvent {
private final String sql;
private final long timeMillis;
private final int rowCount;
private final ObjectGraphNode originNode;
private final List<Object> bindParams;
private final String label;
private final ProfileLocation profileLocation;
/**
* Construct with the SQL and execution time in millis.
*/
DSlowQueryEvent(String sql, long timeMillis, int rowCount, ObjectGraphNode originNode,
List<Object> bindParams, String label, ProfileLocation profileLocation) {
this.sql = sql;
this.timeMillis = timeMillis;
this.rowCount = rowCount;
this.originNode = originNode;
this.bindParams = bindParams;
this.profileLocation = profileLocation;
this.label = label != null ? label : profileLocation == null ? null : profileLocation.label();
}
@Override
public String getSql() {
return sql;
}
@Override
public long getTimeMillis() {
return timeMillis;
}
@Override
public int getRowCount() {
return rowCount;
}
@Override
public ObjectGraphNode getOriginNode() {
return originNode;
}
@Override
public List<Object> getBindParams() {
return bindParams;
}
@Override
public String getLabel() {
return label;
}
@Override
public ProfileLocation getProfileLocation() {
return profileLocation;
}
}
@@ -63,8 +63,8 @@ final class DefaultBeanLoader {
Object parentId = parentDesc.getId(parentBean);
if (pc == null) {
pc = new DefaultPersistenceContext();
parentDesc.contextPut(pc, parentId, parentBean);
}
parentDesc.contextPutIfAbsent(pc, parentId, parentBean);
boolean useManyIdCache = beanCollection != null && parentDesc.isManyPropCaching() && many.isUseCache();
if (useManyIdCache) {
Boolean readOnly = null;
@@ -1200,6 +1200,47 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return queryFuture;
}
@Override
public <T> FutureIds<T> findFutureIds(SpiQuery<T> query) {
SpiQuery<T> copy = query.copy();
copy.usingFuture();
boolean createdTransaction = false;
SpiTransaction transaction = query.transaction();
if (transaction == null) {
transaction = currentServerTransaction();
if (transaction == null) {
transaction = (SpiTransaction) createTransaction();
createdTransaction = true;
}
copy.usingTransaction(transaction);
}
QueryFutureIds<T> queryFuture = new QueryFutureIds<>(new CallableQueryIds<>(this, copy, createdTransaction));
backgroundExecutor.execute(queryFuture.futureTask());
return queryFuture;
}
@Override
public <T> FutureList<T> findFutureList(SpiQuery<T> query) {
SpiQuery<T> spiQuery = query.copy();
spiQuery.usingFuture();
// FutureList query always run in it's own persistence content
spiQuery.setPersistenceContext(new DefaultPersistenceContext());
// Create a new transaction solely to execute the findList() at some future time
boolean createdTransaction = false;
SpiTransaction transaction = query.transaction();
if (transaction == null) {
transaction = currentServerTransaction();
if (transaction == null) {
transaction = (SpiTransaction) createTransaction();
createdTransaction = true;
}
spiQuery.usingTransaction(transaction);
}
QueryFutureList<T> queryFuture = new QueryFutureList<>(new CallableQueryList<>(this, spiQuery, createdTransaction));
backgroundExecutor.execute(queryFuture.futureTask());
return queryFuture;
}
@Override
public <T> PagedList<T> findPagedList(SpiQuery<T> query) {
int maxRows = query.getMaxRows();
@@ -1979,7 +2020,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public void slowQueryCheck(long timeMicros, int rowCount, SpiQuery<?> query) {
if (timeMicros > slowQueryMicros && slowQueryListener != null) {
slowQueryListener.process(new SlowQueryEvent(query.getGeneratedSql(), timeMicros / 1000L, rowCount, query.parentNode()));
List<Object> bindParams = new SlowQueryBindCapture(query).capture();
slowQueryListener.process(new DSlowQueryEvent(query.getGeneratedSql(), timeMicros / 1000L, rowCount,
query.parentNode(), bindParams, query.label(), query.profileLocation()));
}
}
@@ -1,10 +1,12 @@
package io.ebeaninternal.server.core;
import io.avaje.applog.AppLog;
import io.ebean.bean.ObjectGraphNode;
import io.ebean.ProfileLocation;
import io.ebean.config.SlowQueryEvent;
import io.ebean.config.SlowQueryListener;
import java.util.List;
import static java.lang.System.Logger.Level.WARNING;
/**
@@ -16,11 +18,10 @@ final class DefaultSlowQueryListener implements SlowQueryListener {
@Override
public void process(SlowQueryEvent event) {
String firstStack = "";
ObjectGraphNode node = event.getOriginNode();
if (node != null) {
firstStack = node.origin().top();
}
log.log(WARNING, "Slow query warning - millis:{0} rows:{1} caller[{2}] sql[{3}]", event.getTimeMillis(), event.getRowCount(), firstStack, event.getSql());
ProfileLocation profileLocation = event.getProfileLocation();
String loc = profileLocation == null ? "" : profileLocation.fullLocation();
List<Object> bindParams = event.getBindParams();
log.log(WARNING, "Slow query warning - millis:{0} rows:{1} location:{2} sql[{3}] params{4}",
event.getTimeMillis(), event.getRowCount(), loc, event.getSql(), bindParams);
}
}
@@ -807,21 +807,27 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
private void controllerPost() {
switch (type) {
case INSERT:
controller.postInsert(this);
break;
case UPDATE:
controller.postUpdate(this);
break;
case DELETE_SOFT:
controller.postSoftDelete(this);
break;
case DELETE:
controller.postDelete(this);
break;
default:
break;
boolean old = transaction.isFlushOnQuery();
transaction.setFlushOnQuery(false);
try {
switch (type) {
case INSERT:
controller.postInsert(this);
break;
case UPDATE:
controller.postUpdate(this);
break;
case DELETE_SOFT:
controller.postSoftDelete(this);
break;
case DELETE:
controller.postDelete(this);
break;
default:
break;
}
} finally {
transaction.setFlushOnQuery(old);
}
}
@@ -0,0 +1,71 @@
package io.ebeaninternal.server.core;
import io.ebeaninternal.api.BindParams;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionList;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.persist.MultiValueWrapper;
import java.util.ArrayList;
import java.util.List;
final class SlowQueryBindCapture implements SpiExpressionBind {
private final SpiQuery<?> query;
private final List<Object> bindParams = new ArrayList<>();
SlowQueryBindCapture(SpiQuery<?> query) {
this.query = query;
}
List<Object> capture() {
var params = query.bindParams();
if (params != null) {
var positionedParameters = params.positionedParameters();
for (BindParams.Param param : positionedParameters) {
if (param.isInParam()) {
add(param.inValue());
}
}
}
Object id = query.getId();
if (id != null) {
add(id);
}
SpiExpressionList<?> spiExpressionList = query.whereExpressions();
if (spiExpressionList != null) {
spiExpressionList.addBindValues(this);
}
return bindParams;
}
private void add(Object value) {
if (value instanceof MultiValueWrapper) {
var mvw = (MultiValueWrapper) value;
bindParams.add(mvw.getValues());
} else {
bindParams.add(value);
}
}
@Override
public BeanDescriptor<?> descriptor() {
return query.descriptor();
}
@Override
public void addBindValue(Object bindValue) {
add(bindValue);
}
@Override
public void addBindEncryptKey(Object encryptKey) {
bindParams.add("*");
}
@Override
public String escapeLikeString(String value) {
return query.descriptor().ebeanServer().databasePlatform().escapeLikeString(value);
}
}
@@ -96,6 +96,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
private final String asOfViewSuffix;
private final boolean jacksonCorePresent;
private final int queryPlanTTLSeconds;
private final BindMaxLength bindMaxLength;
private int entityBeanCount;
private List<BeanDescriptor<?>> immutableDescriptorList;
/**
@@ -144,6 +145,19 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
this.changeLogListener = config.changeLogListener(bootupClasses.getChangeLogListener());
this.changeLogRegister = config.changeLogRegister(bootupClasses.getChangeLogRegister());
this.jacksonCorePresent = config.isJacksonCorePresent();
this.bindMaxLength = initMaxLength();
}
BindMaxLength initMaxLength() {
LengthCheck lengthCheck = this.config.getLengthCheck();
switch (lengthCheck) {
case OFF:
return null;
case UTF8:
return BindMaxLength.ofUtf8();
default:
return BindMaxLength.ofStandard();
}
}
@Override
@@ -1346,6 +1360,10 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
return list;
}
public BindMaxLength bindMaxLength() {
return bindMaxLength;
}
/**
* Comparator to sort the BeanDescriptors by name.
*/
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.deploy;
import com.fasterxml.jackson.core.JsonToken;
import io.ebean.DataIntegrityException;
import io.ebean.ValuePair;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
@@ -10,7 +11,6 @@ import io.ebean.config.EncryptKey;
import io.ebean.config.dbplatform.DbEncryptFunction;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.core.type.DataReader;
import io.ebean.core.type.DocPropertyType;
import io.ebean.core.type.ScalarType;
import io.ebean.plugin.Property;
import io.ebean.text.StringParser;
@@ -161,6 +161,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
*/
private final String dbComment;
private final DbEncryptFunction dbEncryptFunction;
private final BindMaxLength bindMaxLength;
private int deployOrder;
final boolean jsonSerialize;
final boolean jsonDeserialize;
@@ -244,6 +245,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
}
this.jsonSerialize = deploy.isJsonSerialize();
this.jsonDeserialize = deploy.isJsonDeserialize();
this.bindMaxLength = deploy.bindMaxLength();
}
private String tableAliasIntern(BeanDescriptor<?> descriptor, String s, boolean dbEncrypted, String dbColumn) {
@@ -326,6 +328,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
this.elPlaceHolderEncrypted = override.replace(source.elPlaceHolderEncrypted, source.dbColumn);
this.jsonSerialize = source.jsonSerialize;
this.jsonDeserialize = source.jsonDeserialize;
this.bindMaxLength = source.bindMaxLength;
}
/**
@@ -536,6 +539,18 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
@SuppressWarnings("unchecked")
public void bind(DataBind b, Object value) throws SQLException {
scalarType.bind(b, value);
if (bindMaxLength != null) {
Object obj = b.popLastObject();
long length = bindMaxLength.length(dbLength, obj);
if (length > dbLength) {
b.closeInputStreams();
String s = String.valueOf(value); // take original bind value here.
if (s.length() > 50) {
s = s.substring(0, 47) + "...";
}
throw new DataIntegrityException("Cannot bind value '" + s + "' (effective length=" + length + ") to column '" + dbColumn + "' (length=" + dbLength + ")");
}
}
}
@SuppressWarnings(value = "unchecked")
@@ -1128,14 +1143,14 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
* Returns true if this <code>isLob()</code> or the type will effectively map to a lob.
*/
@Override
public boolean isDbLob() {
public boolean isLobForPlatform() {
if (lob) {
return true;
}
switch (dbType) {
case DbPlatformType.JSON:
case DbPlatformType.JSONB:
return dbLength == 0; // must be analog to DbPlatformTypeMapping.lookup
return dbLength == 0 || dbLength > 4000; // must be analog to DbPlatformTypeMapping.lookup
case DbPlatformType.JSONBlob:
case DbPlatformType.JSONClob:
return true;
@@ -360,6 +360,9 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
for (ExportedProperty exportedProperty : exportedProperties) {
row.addColumn(exportedProperty.getForeignDbColumn());
}
if (importedId == null) {
throw new PersistenceException("Missing @Id property on bean related to ManyToMany " + fullName());
}
importedId.buildImport(row);
return row.build();
}
@@ -566,10 +569,9 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
}
/**
* Set the join properties from the parent bean to the child bean.
* This is only valid for OneToMany and NOT valid for ManyToMany.
* Set the parent bean to the child (update the relationship).
*/
public void setJoinValuesToChild(EntityBean parent, EntityBean child, Object mapKeyValue) {
public void setParentToChild(EntityBean parent, EntityBean child, Object mapKeyValue) {
if (mapKeyProperty != null) {
mapKeyProperty.setValue(child, mapKeyValue);
}
@@ -580,6 +582,31 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
}
}
/**
* Return true if the parent bean has been set to the child (updated the relationship).
*/
public boolean setParentToChild(EntityBean parent, EntityBean child, Object mapKeyValue, BeanDescriptor<?> parentDesc) {
if (manyToMany
|| childMasterProperty == null
|| !child._ebean_getIntercept().isLoadedProperty(childMasterProperty.propertyIndex())) {
return false;
}
Object currentParent = childMasterProperty.getValue(child);
if (currentParent != null) {
Object newId = parentDesc.getId(parent);
Object oldId = parentDesc.id(currentParent);
if (Objects.equals(newId, oldId)) {
return false;
}
}
childMasterProperty.setValueIntercept(child, parent);
if (mapKeyProperty != null) {
mapKeyProperty.setValue(child, mapKeyValue);
}
return true;
}
/**
* Return the order by clause used to order the fetching of the data for
* this list, set or map.
@@ -0,0 +1,90 @@
package io.ebeaninternal.server.deploy;
import io.ebean.core.type.InputStreamInfo;
import java.nio.charset.StandardCharsets;
/**
* The max length check on bind values.
*/
public interface BindMaxLength {
/**
* Return a UTF8 based implementation.
*/
static BindMaxLength ofUtf8() {
return new UTF8();
}
/**
* Return a standard implementation.
*/
static BindMaxLength ofStandard() {
return new Standard();
}
/**
* Return the length of the object.
*/
long length(int dbLength, Object obj);
/**
* Length check based on UTF8 bytes.
*/
final class UTF8 implements BindMaxLength {
@Override
public long length(int dbLength, Object obj) {
if (obj == null) {
return -1;
} else if (obj instanceof String) {
String s = (String) obj;
return utf8String(dbLength, s);
} else if (obj instanceof byte[]) {
return ((byte[]) obj).length;
} else if (obj instanceof InputStreamInfo) {
return ((InputStreamInfo) obj).length();
} else if ("org.postgresql.util.PGobject".equals(obj.getClass().getCanonicalName())) {
String value = ((org.postgresql.util.PGobject) obj).getValue();
return value == null ? -1 : utf8String(dbLength, value);
} else {
return -1;
}
}
private static int utf8String(int dbLength, String s) {
int stringLength = s.length();
if (stringLength > dbLength) {
return stringLength;
} else if (stringLength * 4 <= dbLength) {
return -1;
} else {
return s.getBytes(StandardCharsets.UTF_8).length;
}
}
}
/**
* Standard string length implementation.
*/
final class Standard implements BindMaxLength {
@Override
public long length(int dbLength, Object obj) {
if (obj == null) {
return -1;
} else if (obj instanceof String) {
return ((String) obj).length();
} else if (obj instanceof byte[]) {
return ((byte[]) obj).length;
} else if (obj instanceof InputStreamInfo) {
return ((InputStreamInfo) obj).length();
} else if ("org.postgresql.util.PGobject".equals(obj.getClass().getCanonicalName())) {
String value = ((org.postgresql.util.PGobject) obj).getValue();
return value == null ? -1 : value.length();
} else {
return -1;
}
}
}
}
@@ -63,7 +63,7 @@ class DynamicPropertyAggregationFormula extends DynamicPropertyBase {
}
@Override
public boolean isDbLob() {
public boolean isLobForPlatform() {
return false;
}
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.deploy.id;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
import io.ebeaninternal.server.deploy.BeanProperty;
@@ -143,7 +144,7 @@ public interface IdBinder {
/**
* Binds multiple id value to a request.
*/
void addBindValues(SpiExpressionRequest request, Collection<?> ids);
void addBindValues(SpiExpressionBind request, Collection<?> ids);
/**
* Return the sql for binding the id using an IN clause.
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.deploy.id;
import io.ebean.bean.EntityBean;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -269,7 +270,7 @@ public final class IdBinderEmbedded implements IdBinder {
}
@Override
public void addBindValues(SpiExpressionRequest request, Collection<?> values) {
public void addBindValues(SpiExpressionBind request, Collection<?> values) {
for (Object value : values) {
final EntityBean bean = (EntityBean) value;
for (BeanProperty prop : props) {
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.deploy.id;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.bind.DataBind;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
@@ -130,7 +131,7 @@ final class IdBinderEmpty implements IdBinder {
}
@Override
public void addBindValues(SpiExpressionRequest request, Collection<?> ids) {
public void addBindValues(SpiExpressionBind request, Collection<?> ids) {
}
@Override
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.deploy.id;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
import io.ebeaninternal.server.core.InternString;
@@ -143,7 +144,7 @@ public final class IdBinderSimple implements IdBinder {
}
@Override
public void addBindValues(SpiExpressionRequest request, Collection<?> values) {
public void addBindValues(SpiExpressionBind request, Collection<?> values) {
List<Object> copy = new ArrayList<>(values);
copy.replaceAll(idValue -> convertSetId(idValue, null));
request.addBindValue(new MultiValueWrapper(copy));
@@ -1,8 +1,8 @@
package io.ebeaninternal.server.deploy.meta;
import io.ebean.DatabaseBuilder;
import io.ebean.annotation.Cache;
import io.ebean.annotation.Identity;
import io.ebean.DatabaseBuilder;
import io.ebean.config.TableName;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
@@ -18,9 +18,6 @@ import io.ebeaninternal.server.idgen.UuidV1IdGenerator;
import io.ebeaninternal.server.idgen.UuidV1RndIdGenerator;
import io.ebeaninternal.server.idgen.UuidV4IdGenerator;
import jakarta.persistence.Entity;
import jakarta.persistence.MappedSuperclass;
import java.lang.reflect.Field;
import java.util.*;
@@ -110,6 +107,10 @@ public class DeployBeanDescriptor<T> {
this.beanType = beanType;
}
public BindMaxLength bindMaxLength() {
return manager.bindMaxLength();
}
private String[] readPropertyNames() {
try {
Field field = beanType.getField("_ebean_props");
@@ -1,14 +1,17 @@
package io.ebeaninternal.server.deploy.meta;
import io.avaje.lang.Nullable;
import io.ebean.annotation.*;
import io.ebean.config.ScalarTypeConverter;
import io.ebean.config.dbplatform.DbDefaultValue;
import io.ebean.config.dbplatform.DbEncrypt;
import io.ebean.config.dbplatform.DbEncryptFunction;
import io.ebean.config.dbplatform.ExtraDbTypes;
import io.ebean.core.type.ScalarType;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.server.core.InternString;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BindMaxLength;
import io.ebeaninternal.server.deploy.DbMigrationInfo;
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
import io.ebeaninternal.server.el.ElPropertyValue;
@@ -1075,4 +1078,20 @@ public class DeployBeanProperty {
boolean isJsonType() {
return mutationDetection != null;
}
@Nullable
public BindMaxLength bindMaxLength() {
if (dbLength == 0) {
return null;
}
switch (dbType) {
case Types.VARCHAR:
case Types.BLOB:
case ExtraDbTypes.JSON:
return desc.bindMaxLength();
default:
return null;
}
}
}
@@ -81,7 +81,7 @@ abstract class AbstractExpression implements SpiExpression {
validation.validate(propName);
}
protected final ElPropertyValue getElProp(SpiExpressionRequest request) {
protected final ElPropertyValue getElProp(SpiExpressionBind request) {
return request.descriptor().elGetValue(propName);
}
}
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
/**
@@ -28,7 +29,7 @@ abstract class AbstractTextExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
// do nothing, only execute against document store
}
@@ -41,7 +41,7 @@ final class AllEqualsExpression extends NonPrepareExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
if (propMap.isEmpty()) {
return;
}
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import java.io.IOException;
@@ -55,7 +56,7 @@ final class ArrayContainsExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
for (Object value : values) {
request.addBindValue(value);
}
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
/**
@@ -42,7 +43,7 @@ final class ArrayIsEmptyExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
// nothing to bind
}
}
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.el.ElPropertyValue;
@@ -27,7 +28,7 @@ final class BetweenExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
ElPropertyValue prop = getElProp(request);
if (prop != null && prop.isDbEncrypted()) {
// bind the key as well as the value
@@ -54,7 +54,7 @@ final class BetweenPropertyExpression extends NonPrepareExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
request.addBindValue(val());
}
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
/**
@@ -47,7 +48,7 @@ final class BitwiseExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
request.addBindValue(flags);
request.addBindValue(match);
}
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.el.ElPropertyValue;
@@ -22,7 +23,7 @@ final class CaseInsensitiveEqualExpression extends AbstractValueExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
ElPropertyValue prop = getElProp(request);
if (prop != null && prop.isDbEncrypted()) {
// bind the key as well as the value
@@ -5,12 +5,7 @@ import io.ebean.LikeType;
import io.ebean.bean.EntityBean;
import io.ebean.event.BeanQueryRequest;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.NaturalKeyQueryData;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiExpressionValidation;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
@@ -177,8 +172,7 @@ final class DefaultExampleExpression implements SpiExpression, ExampleExpression
* Adds bind values to the request.
*/
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
for (SpiExpression item : list) {
item.addBindValues(request);
}
@@ -218,6 +218,21 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return query.update(transaction);
}
@Override
public FutureIds<T> findFutureIds() {
return query.findFutureIds();
}
@Override
public FutureRowCount<T> findFutureCount() {
return query.findFutureCount();
}
@Override
public FutureList<T> findFutureList() {
return query.findFutureList();
}
@Override
public PagedList<T> findPagedList() {
return query.findPagedList();
@@ -431,7 +446,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
for (SpiExpression expr : list) {
expr.addBindValues(request);
}
@@ -94,7 +94,7 @@ final class ExistsQueryExpression implements SpiExpression, UnsupportedDocStoreE
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
for (Object bindParam : bindParams) {
request.addBindValue(bindParam);
}
@@ -72,7 +72,7 @@ final class ExistsSqlQueryExpression implements SpiExpression, UnsupportedDocSto
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
for (Object bindParam : bindParams) {
request.addBindValue(bindParam);
}
@@ -49,6 +49,21 @@ public final class FilterExpressionList<T> extends DefaultExpressionList<T> {
return rootQuery.filterMany(prop);
}
@Override
public FutureIds<T> findFutureIds() {
return rootQuery.findFutureIds();
}
@Override
public FutureList<T> findFutureList() {
return rootQuery.findFutureList();
}
@Override
public FutureRowCount<T> findFutureCount() {
return rootQuery.findFutureCount();
}
@Override
public List<T> findList() {
return rootQuery.findList();
@@ -33,7 +33,7 @@ final class IdExpression extends NonPrepareExpression implements SpiExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
// 'flatten' EmbeddedId and multiple ID cases
// into an array of the underlying scalar field values
for (Object bindIdValue : request.descriptor().bindIdValues(value)) {
@@ -50,7 +50,7 @@ public final class IdInExpression extends NonPrepareExpression implements IdInCo
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
if (idCollection.isEmpty()) {
return;
}
@@ -2,10 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebean.bean.EntityBean;
import io.ebean.event.BeanQueryRequest;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.NaturalKeyQueryData;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.el.ElPropertyValue;
import io.ebeaninternal.server.persist.MultiValueWrapper;
@@ -95,7 +92,7 @@ public final class InExpression extends AbstractExpression implements IdInCommon
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
if (empty) {
return;
}
@@ -3,10 +3,7 @@ package io.ebeaninternal.server.expression;
import io.ebean.Pairs;
import io.ebean.Pairs.Entry;
import io.ebean.event.BeanQueryRequest;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.NaturalKeyQueryData;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.persist.MultiValueWrapper;
import java.util.ArrayList;
@@ -53,8 +50,7 @@ final class InPairsExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
// Note at this point entries may have been removed when used with l2 caching
// ... for each l2 cache hit an entry was removed
this.concatBindValues = new ArrayList<>(entries.size());
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.el.ElPropertyValue;
@@ -25,7 +26,7 @@ final class InRangeExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
ElPropertyValue prop = getElProp(request);
if (prop != null && prop.isDbEncrypted()) {
// bind the key twice, for both values
@@ -2,10 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebean.InTuples;
import io.ebean.service.SpiInTuples;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.NaturalKeyQueryData;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.*;
import java.util.List;
@@ -32,7 +29,7 @@ final class InTuplesExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
for (Object[] entry : entries) {
for (Object value : entry) {
requireNonNull(value);
@@ -1,10 +1,7 @@
package io.ebeaninternal.server.expression;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.el.ElPropertyValue;
@@ -25,7 +22,7 @@ final class IsEmptyExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
// no bind values
}
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import java.util.Objects;
@@ -91,7 +92,7 @@ final class JsonPathExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
if (value != null) {
// value is null for EXISTS/NOT EXISTS
request.addBindValue(value);
@@ -122,7 +122,7 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
for (SpiExpression expr : exprList.internalList()) {
expr.addBindValues(request);
}
@@ -328,6 +328,21 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
return exprList.exists();
}
@Override
public FutureIds<T> findFutureIds() {
return exprList.findFutureIds();
}
@Override
public FutureList<T> findFutureList() {
return exprList.findFutureList();
}
@Override
public FutureRowCount<T> findFutureCount() {
return exprList.findFutureCount();
}
@Override
public <A> List<A> findIds() {
return exprList.findIds();
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.expression;
import io.ebean.LikeType;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.el.ElPropertyValue;
@@ -18,7 +19,7 @@ final class LikeExpression extends AbstractValueExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
ElPropertyValue prop = getElProp(request);
if (prop != null && prop.isDbEncrypted()) {
// bind the key as well as the value
@@ -71,7 +72,7 @@ final class LikeExpression extends AbstractValueExpression {
return strValue().equals(that.strValue());
}
private static String getValue(String value, boolean caseInsensitive, LikeType type, SpiExpressionRequest request) {
private static String getValue(String value, boolean caseInsensitive, LikeType type, SpiExpressionBind request) {
if (caseInsensitive) {
value = value.toLowerCase();
}
@@ -2,12 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebean.Expression;
import io.ebean.event.BeanQueryRequest;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.NaturalKeyQueryData;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiExpressionValidation;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.deploy.BeanDescriptor;
/**
@@ -101,7 +96,7 @@ abstract class LogicExpression implements SpiExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
expOne.addBindValues(request);
expTwo.addBindValues(request);
}
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.expression;
import io.ebean.LikeType;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.el.ElPropertyValue;
@@ -16,8 +17,7 @@ final class NativeILikeExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
ElPropertyValue prop = getElProp(request);
if (prop != null && prop.isDbEncrypted()) {
// bind the key as well as the value
@@ -69,7 +69,7 @@ final class NoopExpression implements SpiExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
// nothing to do
}
@@ -2,12 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebean.Expression;
import io.ebean.event.BeanQueryRequest;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.NaturalKeyQueryData;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiExpressionValidation;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.deploy.BeanDescriptor;
final class NotExpression implements SpiExpression {
@@ -59,7 +54,7 @@ final class NotExpression implements SpiExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
exp.addBindValues(request);
}
@@ -1,10 +1,7 @@
package io.ebeaninternal.server.expression;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.el.ElPropertyValue;
@@ -43,7 +40,7 @@ final class NullExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
}
@@ -31,7 +31,7 @@ final class RawExpression extends NonPrepareExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
if (values != null) {
for (Object value : values) {
if (value instanceof Collection<?>) {
@@ -2,10 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebean.bean.EntityBean;
import io.ebean.plugin.ExpressionPath;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.NaturalKeyQueryData;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.el.ElPropertyValue;
public final class SimpleExpression extends AbstractValueExpression {
@@ -47,8 +44,7 @@ public final class SimpleExpression extends AbstractValueExpression {
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
ElPropertyValue prop = getElProp(request);
if (prop != null) {
if (prop.isAssocId()) {
@@ -74,7 +74,7 @@ final class SubQueryExpression extends AbstractExpression implements Unsupported
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
for (Object bindParam : bindParams) {
request.addBindValue(bindParam);
}
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import java.util.Arrays;
@@ -42,7 +43,7 @@ final class SubQueryRawExpression extends AbstractExpression implements Unsuppor
}
@Override
public void addBindValues(SpiExpressionRequest request) {
public void addBindValues(SpiExpressionBind request) {
for (Object bindParam : bindParams) {
request.addBindValue(bindParam);
}
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.expression.platform;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.expression.BitwiseOp;
/**
@@ -9,7 +8,7 @@ import io.ebeaninternal.server.expression.BitwiseOp;
abstract class BaseDbExpression implements DbExpressionHandler {
@Override
public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
public void bitwise(DbExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
final String bitOp = bitOp(operator);
request.append('(').property(propName).append(' ').append(bitOp).append(" ? ").append(compare).append(" ?)");
}
@@ -28,7 +27,7 @@ abstract class BaseDbExpression implements DbExpressionHandler {
/**
* Common alternative where the bitwise operation is a function (specifically bitand is used - H2 and Oracle).
*/
protected void bitwiseFunction(SpiExpressionRequest request, String propName, BitwiseOp operator, String compare) {
protected void bitwiseFunction(DbExpressionRequest request, String propName, BitwiseOp operator, String compare) {
final String funcName = functionName(operator);
request.append(funcName).append('(').property(propName).append(", ?) ").append(compare).append(" ?");
}
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.expression.platform;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.expression.Op;
/**
@@ -9,17 +8,17 @@ import io.ebeaninternal.server.expression.Op;
class BasicDbExpression extends BaseDbExpression {
@Override
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
public void json(DbExpressionRequest request, String propName, String path, Op operator, Object value) {
throw new RuntimeException("JSON expressions only supported on Postgres and Oracle");
}
@Override
public void arrayContains(SpiExpressionRequest request, String propName, boolean contains, Object... values) {
public void arrayContains(DbExpressionRequest request, String propName, boolean contains, Object... values) {
throw new RuntimeException("ARRAY expressions only supported on Postgres");
}
@Override
public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) {
public void arrayIsEmpty(DbExpressionRequest request, String propName, boolean empty) {
throw new RuntimeException("ARRAY expressions only supported on Postgres");
}
}
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.expression.platform;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.expression.BitwiseOp;
import io.ebeaninternal.server.expression.Op;
@@ -12,22 +11,22 @@ public interface DbExpressionHandler {
/**
* Write the db platform specific json expression.
*/
void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value);
void json(DbExpressionRequest request, String propName, String path, Op operator, Object value);
/**
* Add SQL for ARRAY CONTAINS expression.
*/
void arrayContains(SpiExpressionRequest request, String propName, boolean contains, Object... values);
void arrayContains(DbExpressionRequest request, String propName, boolean contains, Object... values);
/**
* Add SQL for ARRAY IS EMPTY expression.
*/
void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty);
void arrayIsEmpty(DbExpressionRequest request, String propName, boolean empty);
/**
* Add the bitwise expression.
*/
void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match);
void bitwise(DbExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match);
/**
* Performs a "CONCAT" operation for that platform.

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