mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
35
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7480904792 | ||
|
|
b12cfafc21 | ||
|
|
f07727651e | ||
|
|
6090eaa167 | ||
|
|
40eada4e80 | ||
|
|
2d375b3596 | ||
|
|
d864e2c723 | ||
|
|
e50c372562 | ||
|
|
e2cb033119 | ||
|
|
9620c57f19 | ||
|
|
07cc0fcbb6 | ||
|
|
6d1beb5c03 | ||
|
|
1667107422 | ||
|
|
de5cf1df2c | ||
|
|
a83114ced2 | ||
|
|
d6983422bf | ||
|
|
6d4b3ad84e | ||
|
|
a3df7919b5 | ||
|
|
6f1aa39cc9 | ||
|
|
f18c24c1d1 | ||
|
|
068401c29c | ||
|
|
6fbbd8b107 | ||
|
|
6379bd9e5d | ||
|
|
94d58dfa7c | ||
|
|
035fb80959 | ||
|
|
3b97f77083 | ||
|
|
a7d47202e6 | ||
|
|
199a9d3118 | ||
|
|
5df3ac4b04 | ||
|
|
782f77b688 | ||
|
|
1d570a233e | ||
|
|
4a6b58bd9b | ||
|
|
d64073bef0 | ||
|
|
6d8a9236f8 | ||
|
|
1665b4f2fa |
@@ -1,13 +0,0 @@
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
spaces_around_operators = true
|
||||
max_line_length = 130
|
||||
@@ -1,19 +0,0 @@
|
||||
|
||||
GITHUB ISSUES ARE STRICTLY CONTROLLED FOR THIS PROJECT.
|
||||
|
||||
Refer to http://ebean-orm.github.io/support for the policies controlling the use of github issues.
|
||||
Please post issues to the Ebean group https://groups.google.com/forum/#!forum/ebean first.
|
||||
|
||||
## Expected behavior
|
||||
|
||||
## Actual behavior
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
```java
|
||||
// some java code
|
||||
```
|
||||
|
||||
```console
|
||||
// some logging output
|
||||
```
|
||||
+3
-17
@@ -1,23 +1,9 @@
|
||||
*.autofetch
|
||||
*create-all.sql
|
||||
*drop-all.sql
|
||||
*.orig
|
||||
*.sql
|
||||
.classpath
|
||||
.project
|
||||
.settings/
|
||||
target/
|
||||
logs/
|
||||
log/
|
||||
ebean-autotune.xml
|
||||
ebean-profiling*.xml
|
||||
/db
|
||||
/mydb.db
|
||||
!src/test/ddl-review/*.sql
|
||||
profiling/
|
||||
|
||||
# Intellij project files
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
*uuid.state
|
||||
*.iml
|
||||
|
||||
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
dist: trusty
|
||||
sudo: required
|
||||
language: java
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
|
||||
git:
|
||||
depth: 3
|
||||
|
||||
addons:
|
||||
postgresql: "9.6"
|
||||
# apt:
|
||||
# packages:
|
||||
# - mysql-server-5.7
|
||||
# - mysql-client-core-5.7
|
||||
# - mysql-client-5.7
|
||||
|
||||
services:
|
||||
- docker
|
||||
- postgresql
|
||||
- mysql
|
||||
|
||||
before_script:
|
||||
- ./.travis/setup_database
|
||||
- mysql -u root -e 'CREATE DATABASE test_ebean;'
|
||||
- mysql -u root -e "CREATE USER 'test_ebean'@'localhost' IDENTIFIED BY 'test';"
|
||||
- mysql -u root -e "GRANT ALL ON test_ebean.* TO 'test_ebean'@'localhost';"
|
||||
|
||||
env:
|
||||
- EBEAN_DB=h2
|
||||
- EBEAN_DB=pg
|
||||
# - EBEAN_DB=mysql
|
||||
|
||||
install: true
|
||||
|
||||
script:
|
||||
- mvn clean test
|
||||
|
||||
after_failure:
|
||||
- ./.travis/print_surefire_reports
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.m2
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "\n=== SUREFIRE REPORTS ===\n"
|
||||
|
||||
for file in target/surefire-reports/*.txt
|
||||
do
|
||||
echo ${file}
|
||||
cat ${file}
|
||||
echo
|
||||
done
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "\n=== SETUP DATABASE ===\n"
|
||||
|
||||
#set -e
|
||||
#set -x
|
||||
|
||||
# Setup postgres' users and databases
|
||||
sudo -u postgres psql -c "CREATE USER unit WITH PASSWORD 'unit';"
|
||||
sudo -u postgres psql -c 'CREATE DATABASE unit WITH OWNER unit;'
|
||||
sudo -u postgres psql unit -c 'CREATE EXTENSION hstore;'
|
||||
sudo -u postgres psql unit -c 'CREATE EXTENSION pgcrypto;'
|
||||
#sudo -u postgres psql test2 -c 'CREATE EXTENSION postgis;'
|
||||
|
||||
@@ -1,298 +0,0 @@
|
||||
Overview of ebean.properties file
|
||||
=================================
|
||||
|
||||
|
||||
### DbMigration options
|
||||
|
||||
You can set individual values for different platforms when generating migrations
|
||||
|
||||
`dbmigration.platform.<PLATFORM>.databaseSequenceBatchSize`
|
||||
For DB's using sequences this is the number of sequence values prefetched.
|
||||
|
||||
`dbmigration.platform.<PLATFORM>.dbuuid`
|
||||
Control, how UUID generation should work - it affects DDL which column type is generated. Possible values:
|
||||
- BINARY enforces binary UUID
|
||||
- VARCHAR enforces varchar UUID
|
||||
- BINARY_OPTIMIZED enforces binary-optimized UUID (makes sense only with Type1 ID)
|
||||
- AUTO_BINARY use binary when platform does not support native UUID
|
||||
- AUTO_BINARY_OPTIMIZED use binary-optimized when platform does not support native UUID
|
||||
- AUTO_VARCHAR (default) use varchar when platform does not support UUID
|
||||
|
||||
`dbmigration.platform.<PLATFORM>.uuidStoreAsBinary`
|
||||
Same as setting dbuuid to BINARY
|
||||
|
||||
`dbmigration.platform.<PLATFORM>.geometrySRID`
|
||||
The Geometry SRID value (default 4326).
|
||||
|
||||
`dbmigration.platform.<PLATFORM>.idType`
|
||||
The ID type (IDENTITY, SEQUENCE, GENERATOR, EXTERNAL)
|
||||
|
||||
`dbmigration.platform.<PLATFORM>.mapping`
|
||||
Adjust the mapping. For example `BOOLEAN=integer(32);BIT=tinyint(3)`
|
||||
|
||||
|
||||
`ebean.migration.applyPrefix`
|
||||
Set this to "V" to be compatible with FlywayDB.
|
||||
|
||||
`ebean.migration.applySuffix`
|
||||
Defaults to '.sql'
|
||||
|
||||
`ebean.migration.dbusername`
|
||||
DB user used to run the DB migration.
|
||||
|
||||
`ebean.migration.dbpassword`
|
||||
DB password used to run the DB migration.
|
||||
|
||||
`ebean.migration.generate`
|
||||
Set to true if the DB migration should be generated on server start.
|
||||
|
||||
`ebean.migration.generatePendingDrop`
|
||||
The version of a pending drop that should be generated as the next migration.
|
||||
|
||||
`ebean.migration.includeGeneratedFileComment`
|
||||
TODO
|
||||
|
||||
`ebean.migration.metaTable`
|
||||
For running migration the DB table that holds migration execution status. Default 'db_migration'
|
||||
|
||||
`ebean.migration.migrationPath`
|
||||
Resource path for the migration xml and sql.
|
||||
|
||||
`ebean.migration.modelPath`
|
||||
Subdirectory the model xml files go into. Default 'model'
|
||||
|
||||
`ebean.migration.modelSuffix`
|
||||
Suffix. Default '.model.xml'
|
||||
|
||||
`ebean.migration.name`
|
||||
Description text that can be appended to the version to become the ddl script file name
|
||||
|
||||
`ebean.migration.patchInsertOn`
|
||||
migration versions that should be added to history without running.
|
||||
|
||||
`ebean.migration.patchResetChecksumOn`
|
||||
migration versions that should have their checksum reset and not run.
|
||||
Use this if you get a 'Checksum mismatch' error.
|
||||
|
||||
`ebean.migration.placeholders`
|
||||
A comma and equals delimited placeholders that are substituted in SQL scripts when running migration (used by DB Migration runner only).
|
||||
|
||||
`ebean.migration.platform`
|
||||
The database platform to generate migration DDL for.
|
||||
|
||||
`ebean.migration.run`
|
||||
Flag set to true means to run any outstanding migrations on startup.
|
||||
|
||||
`ebean.migration.version`
|
||||
The migration version name (typically FlywayDb compatible). Example: 1.1.1_2
|
||||
|
||||
|
||||
### Ebean UUID options
|
||||
|
||||
`ebean.uuidVersion`
|
||||
Controls, how the UUIDs are generated. Possible values
|
||||
- VERSION4 (default) generate random V4 UUIDs,
|
||||
- VERSION1 generate rfc4122 compliant Type 1 UUIDs (requires a state file)
|
||||
- VERSION1RND generate fake Type 1 UUIDs
|
||||
|
||||
Note, that V1 UUIDs in conjunction with AUTO_BINARY_OPTIMIZED will give you the best index performance, but you MUST understand how this works to avoid collisions.
|
||||
|
||||
`ebean.uuidStateFile`
|
||||
The state file that is Required to generate V1 UUIDs
|
||||
|
||||
|
||||
### DocStoreConfig
|
||||
|
||||
`ebean.docstore.active`
|
||||
True when the Document store integration is active/on.
|
||||
|
||||
`ebean.docstore.allowAllCertificates`
|
||||
Set to true such that the client allows connections to invalid/self signed SSL certificates.
|
||||
|
||||
`ebean.docstore.bulkBatchSize`
|
||||
The default batch size to use for the Bulk API calls.
|
||||
|
||||
`ebean.docstore.create`
|
||||
When true the Document store should create any document indexes that don't already exist.
|
||||
|
||||
`ebean.docstore.dropCreate`
|
||||
When true the Document store should drop and re-create document indexes.
|
||||
|
||||
`ebean.docstore.generateMapping`
|
||||
Set to true means Ebean will generate mapping files on startup.
|
||||
|
||||
`ebean.docstore.mappingPath`
|
||||
Resource path for the Document store mapping files.
|
||||
|
||||
`ebean.docstore.mappingSuffix`
|
||||
Suffix used for mapping files.
|
||||
|
||||
`ebean.docstore.password`
|
||||
Password credential that be used for authentication to document store.
|
||||
|
||||
`ebean.docstore.pathToResources`
|
||||
Location of resources that mapping files are generated into.
|
||||
|
||||
`ebean.docstore.persist`
|
||||
The default mode used by indexes. `DEFAULT|IGNORE|QUEUE|UPDATE`
|
||||
|
||||
`ebean.docstore.url`
|
||||
The URL of the Document store server. For example: http://localhost:9200.
|
||||
|
||||
`ebean.docstore.username`
|
||||
Credential that be used for authentication to document store.
|
||||
|
||||
### Ebean Autotune
|
||||
|
||||
`ebean.autoTune.mode`
|
||||
The autoTune mode `DEFAULT_OFF|DEFAULT_ON|DEFAULT_ONIFEMPTY`
|
||||
|
||||
`ebean.autoTune.profiling`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.profilingBase`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.profilingFile`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.profilingRate`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.profilingUpdateFrequency`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.queryTuning`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.queryTuningAddVersion`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.queryTuningFile`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.skipGarbageCollectionOnShutdown`
|
||||
TODO
|
||||
|
||||
`ebean.autoTune.skipProfileReportingOnShutdown`
|
||||
TODO
|
||||
|
||||
|
||||
### Ebean options
|
||||
`ebean.allQuotedIdentifiers`
|
||||
Quote all identifiers
|
||||
|
||||
`ebean.asOfSysPeriod`
|
||||
Column used to support history and 'As of' queries. This column is a timestamp range or equivalent.
|
||||
|
||||
`ebean.asOfViewSuffix`
|
||||
Suffix appended to the base table to derive the view that contains the union of the base table and the history table in order to support asOf queries.
|
||||
|
||||
`ebean.autoCommitMode`
|
||||
Set to true if the DataSource uses autoCommit. Indicates that Ebean should use autoCommit friendly Transactions and TransactionManager.
|
||||
|
||||
`ebean.autoReadOnlyDataSource`
|
||||
When true create a read only DataSource using readOnlyDataSourceConfig defaulting values from dataSourceConfig
|
||||
|
||||
`ebean.autostart`
|
||||
Should the server start all
|
||||
|
||||
`ebean.backgroundExecutorSchedulePoolSize`
|
||||
TODO
|
||||
|
||||
`ebean.backgroundExecutorShutdownSecs`
|
||||
TODO
|
||||
|
||||
and some more todos:
|
||||
`ebean.batch.mode`
|
||||
`ebean.batch.size`
|
||||
`ebean.changeLogAsync`
|
||||
`ebean.changeLogIncludeInserts`
|
||||
`ebean.classes`
|
||||
`ebean.collectQueryOrigins`
|
||||
`ebean.collectQueryStatsByNode`
|
||||
`ebean.currentUserProvider`
|
||||
`ebean.dataSourceJndiName`
|
||||
`ebean.dataTimeZone`
|
||||
`ebean.databaseBooleanFalse`
|
||||
`ebean.databaseBooleanTrue`
|
||||
`ebean.databasePlatform`
|
||||
`ebean.databasePlatformName`
|
||||
`ebean.databaseSequenceBatchSize`
|
||||
ebean.datasource.h2.adminpassword
|
||||
ebean.datasource.h2.adminusername
|
||||
`ebean.dbEncrypt`
|
||||
`ebean.dbOffline`
|
||||
ebean.ddl.createOnly
|
||||
ebean.ddl.generate
|
||||
ebean.ddl.header
|
||||
ebean.ddl.initSql
|
||||
ebean.ddl.run
|
||||
ebean.ddl.seedSql
|
||||
ebean.defaultDeleteMissingChildren
|
||||
ebean.defaultOrderById
|
||||
ebean.disableClasspathSearch
|
||||
ebean.disableL2Cache
|
||||
ebean.docStoreOnly
|
||||
ebean.docstore.active
|
||||
ebean.docstore.allowAllCertificates
|
||||
ebean.docstore.bulkBatchSize
|
||||
ebean.docstore.create
|
||||
ebean.docstore.dropCreate
|
||||
ebean.docstore.generateMapping
|
||||
ebean.docstore.mappingPath
|
||||
ebean.docstore.mappingSuffix
|
||||
ebean.docstore.password
|
||||
ebean.docstore.pathToResources
|
||||
ebean.docstore.persist
|
||||
ebean.docstore.url
|
||||
ebean.docstore.username
|
||||
ebean.encryptDeployManager
|
||||
ebean.encryptKeyManager
|
||||
ebean.encryptor
|
||||
ebean.explicitTransactionBeginMode
|
||||
ebean.expressionEqualsWithNullAsNoop
|
||||
ebean.expressionNativeIlike
|
||||
ebean.geometrySRID
|
||||
ebean.historyTableSuffix
|
||||
ebean.jdbcFetchSizeFindEach
|
||||
ebean.jdbcFetchSizeFindList
|
||||
ebean.jodaLocalTimeMode
|
||||
ebean.jsonDateTime
|
||||
ebean.jsonInclude
|
||||
ebean.lazyLoadBatchSize
|
||||
ebean.localTimeWithNanos
|
||||
ebean.namingConvention.schema
|
||||
ebean.namingConvention.sequenceFormat
|
||||
ebean.namingConvention.useForeignKeyPrefix
|
||||
ebean.namingconvention
|
||||
ebean.notifyL2CacheInForeground
|
||||
ebean.packages
|
||||
ebean.persistBatch
|
||||
ebean.persistBatchOnCascade
|
||||
ebean.persistBatchSize
|
||||
ebean.persistBatching
|
||||
ebean.persistenceContextScope
|
||||
ebean.profiling
|
||||
ebean.profiling.directory
|
||||
ebean.profiling.includeProfileIds
|
||||
ebean.profiling.minimumMicros
|
||||
ebean.profiling.profilesPerFile
|
||||
ebean.profiling.verbose
|
||||
ebean.queryBatchSize
|
||||
ebean.queryPlanTTLSeconds
|
||||
ebean.search.packages
|
||||
ebean.serverCachePlugin
|
||||
ebean.skipCacheAfterWrite
|
||||
ebean.slowQueryMillis
|
||||
ebean.tenant.catalogProvider
|
||||
ebean.tenant.currentTenantProvider
|
||||
ebean.tenant.mode
|
||||
ebean.tenant.partitionColumn
|
||||
ebean.tenant.schemaProvider
|
||||
ebean.updateAllPropertiesInBatch
|
||||
ebean.updateChangesOnly
|
||||
ebean.updatesDeleteMissingChildren
|
||||
ebean.useJavaxValidationNotNull
|
||||
ebean.useJtaTransactionManager
|
||||
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
EbeanORM
|
||||
|
||||
Copyright 2012 Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,17 +1,4 @@
|
||||
# Need help?
|
||||
Post questions or issues to the Ebean google group - https://groups.google.com/forum/#!forum/ebean
|
||||
|
||||
# Documentation
|
||||
Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
|
||||
|
||||
|
||||
## Maven cental links:
|
||||
[Maven central - ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.ebean%22%20AND%20a%3A%22ebean%22 "maven central ebean")
|
||||
|
||||
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
|
||||
|
||||
## Current versions
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean) - ebean
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent) - ebean-agent
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin) - ebean-maven-plugin
|
||||
avaje-ebeanorm-spring
|
||||
=====================
|
||||
|
||||
Spring integration with EbeanORM
|
||||
-153
@@ -1,153 +0,0 @@
|
||||
This is a short description how to run tests
|
||||
============================================
|
||||
|
||||
Run tests from maven
|
||||
--------------------
|
||||
|
||||
Just type `mvn test` - it will run the whole test suite with the settings
|
||||
from `src/test/resources/ebean.properties`.
|
||||
|
||||
Run tests from eclipse
|
||||
----------------------
|
||||
|
||||
Running tests requires, that the classes are enhanced. By default, the
|
||||
`BaseTestCase` tries to load the enhancer-agent in a very early stage. This
|
||||
also works for most test cases, but it does not work if you try to run a
|
||||
complete test-suite, as classes that are loaded before the enhancer-agent
|
||||
kicks in will not get enhanced. To solve this problem, you need either the
|
||||
[Eclipse-Enhancer-Plugin](https://github.com/ebean-orm-tools/ebean-eclipse-enhancer)
|
||||
or add the agent to your JVM arguments (Preferences->Installed JREs) or to
|
||||
your run configuration:
|
||||
`-javaagent:<USER_HOME>/.m2/repository/io/ebean/ebean-agent/<VERSION>/ebean-agent-<VERSION>.jar=debug=0`
|
||||
|
||||
|
||||
Platform Tests
|
||||
==============
|
||||
|
||||
By default, the `h2` platform is used. To test a different platform, add
|
||||
`-Ddatasource.default=xxx` to your maven command or JVM arguments.
|
||||
|
||||
'h2' platform
|
||||
-------------
|
||||
|
||||
Reqires no setup
|
||||
|
||||
run: `mvn clean test`
|
||||
|
||||
Current status: PASS
|
||||
Tests run: 1986, Failures: 0, Errors: 0, Skipped: 16
|
||||
|
||||
'pg' platform
|
||||
-------------
|
||||
|
||||
Reqirements
|
||||
- a locally installed PostgreSQL server with PostGis.
|
||||
- Create a user "unit" with password "unit" and a database "unit"
|
||||
- Give the user all permissions to that db
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=pg`
|
||||
|
||||
Current status: PASS
|
||||
Tests run: 2166, Failures: 0, Errors: 0, Skipped: 25
|
||||
|
||||
|
||||
|
||||
'mysql' platform
|
||||
-------------
|
||||
|
||||
Reqirements
|
||||
- a locally installed MySQL server.
|
||||
- Create a user "unit" with password "unit" and a database "unit"
|
||||
- Give the user all permissions to that db
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=mysql`
|
||||
|
||||
Current status: PASS
|
||||
Tests run: 2166, Failures: 0, Errors: 0, Skipped: 33
|
||||
|
||||
|
||||
|
||||
'sqlserver' platform
|
||||
--------------------
|
||||
|
||||
Reqires an installed sqlserver - e.g. https://hub.docker.com/r/microsoft/mssql-server-linux/
|
||||
|
||||
- Create a user "ebean" with password "ebean" and a database "ebean_unittest"
|
||||
- Adjust the connection string and/or username in ebean.properties
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=mssql`
|
||||
|
||||
Current status: PASS
|
||||
Tests run: 2166, Failures: 0, Errors: 0, Skipped: 39
|
||||
|
||||
|
||||
|
||||
'oracle' platform
|
||||
-----------------
|
||||
|
||||
Reqires a locally installed Oracle server.
|
||||
- Create a user "unit" with password "unit" with all permissions
|
||||
- The test wirtes directly to the "xe" SID - so do not use a productive server!
|
||||
- As the Oracle JDBC driver is only available on an oracle repository,
|
||||
you need a special maven setup as described [here](http://docs.oracle.com/middleware/1213/core/MAVEN/config_maven_repo.htm#MAVEN9010)
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=ora -Poracle`
|
||||
|
||||
Current status: FAIL
|
||||
Tests run: 1986, Failures: 17, Errors: 34, Skipped: 16
|
||||
|
||||
|
||||
|
||||
'db2' platform
|
||||
--------------
|
||||
|
||||
Reqires a locally installed DB2 Express-C server.
|
||||
- Create a user "unit" with password "unit" with all permissions
|
||||
- Install the db2jcc4 driver (see pom.xml)
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=db2 -Pdb2`
|
||||
|
||||
Current status: FAIL
|
||||
Tests run: 2166, Failures: 29, Errors: 58, Skipped: 30
|
||||
|
||||
|
||||
'sqlite' platform
|
||||
-----------------
|
||||
|
||||
Reqires no setup
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=sqlite`
|
||||
|
||||
Current status: FAIL
|
||||
Tests run: 1986, Failures: 24, Errors: 86, Skipped: 16
|
||||
|
||||
After some time, the db locks up, every test takes 3 seconds and fails with
|
||||
"the database file is locked"
|
||||
|
||||
|
||||
|
||||
'hsqldb' platform
|
||||
-----------------
|
||||
|
||||
Reqires no setup
|
||||
|
||||
run: `mvn clean test -Ddatasource.default=hsqldb`
|
||||
|
||||
Current status: FAIL
|
||||
Tests run: 1980, Failures: 3, Errors: 657, Skipped: 16
|
||||
|
||||
|
||||
@Rob FYI
|
||||
The problem is https://sourceforge.net/p/hsqldb/bugs/1364/
|
||||
In `InsertHandler.getPstmt` the `meta.getIdentityDbColumns()` contains
|
||||
'id' in lowercase. Changing that to uppercase gives me this result:
|
||||
`Tests run: 1986, Failures: 2, Errors: 18, Skipped: 16`
|
||||
(as quick hack I added temporary a toUpperCase to BindableIdScalar.getIdentityColumn)
|
||||
|
||||
|
||||
'sqlanywhere' platform
|
||||
----------------------
|
||||
|
||||
TODO: not yet tested
|
||||
|
||||
|
||||
@@ -1,397 +1,237 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>java8-parent</artifactId>
|
||||
<version>1.3</version>
|
||||
<artifactId>avaje-javaparent</artifactId>
|
||||
<version>1.2</version>
|
||||
</parent>
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>11.18.3</version>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<artifactId>ebean-spring</artifactId>
|
||||
<name>ebean-spring</name>
|
||||
<version>7.1.2</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
<url>http://ebean-orm.github.io/</url>
|
||||
<description>Support for Spring transactions and IOC setup of Ebean server config</description>
|
||||
|
||||
<properties>
|
||||
<jackson-core.version>2.9.5</jackson-core.version>
|
||||
<snakeyaml.version>1.21</snakeyaml.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<spring.framework.version>4.1.7.RELEASE</spring.framework.version>
|
||||
</properties>
|
||||
|
||||
<url>http://www.avaje.org</url>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-11.18.3</tag>
|
||||
<connection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm-spring.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm-spring.git</developerConnection>
|
||||
<url>https://github.com/ebean-orm/avaje-ebeanorm-spring.git</url>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<!-- Note: to use this profile, you need credentials for the oracle repository in your
|
||||
settings.xml as described here:
|
||||
http://docs.oracle.com/middleware/1213/core/MAVEN/config_maven_repo.htm#MAVEN9010 -->
|
||||
<id>oracle</id>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.oracle.jdbc</groupId>
|
||||
<artifactId>ojdbc8</artifactId>
|
||||
<version>12.2.0.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>maven.oracle.com</id>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<url>https://maven.oracle.com</url>
|
||||
<layout>default</layout>
|
||||
</repository>
|
||||
</repositories>
|
||||
</profile>
|
||||
<profile>
|
||||
<!-- Note: to use this profile, you need to download manually the db2jcc4 driver.
|
||||
After that, install it into your local maven repository:
|
||||
|
||||
mvn install:install-file \
|
||||
-Dfile=db2jcc4.jar \
|
||||
-DgroupId=com.ibm.jdbc \
|
||||
-DartifactId=db2jcc4 \
|
||||
-Dversion=4.23.42 \
|
||||
-Dpackaging=jar
|
||||
-->
|
||||
<id>db2</id>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.ibm.jdbc</groupId>
|
||||
<artifactId>db2jcc4</artifactId>
|
||||
<version>4.23.42</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
<dependencies>
|
||||
|
||||
<!--
|
||||
Projects are expected to explicit depend on version
|
||||
of slf4j that they want to use
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.25</version>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>[1.7,)</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Provided: Bring in explicitly -->
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>8.1.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
Exclude snakeyaml if you desire - it is not strictly required.
|
||||
-->
|
||||
<!-- Optional: Add to use AgentLoaderSupport -->
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>${snakeyaml.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
Class retention Nonnull and Nullable annotations
|
||||
to assist with IDE auto-completion with Ebean API
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-jsr305</artifactId>
|
||||
<version>1.1</version>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<artifactId>ebean-agent</artifactId>
|
||||
<version>8.1.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>2.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>4.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-datasource</artifactId>
|
||||
<version>3.2.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-classpath-scanner</artifactId>
|
||||
<version>3.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>11.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-runtime</artifactId>
|
||||
<version>4.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson-core.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope for JsonNode support -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson-core.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.transaction</groupId>
|
||||
<artifactId>jta</artifactId>
|
||||
<version>1.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope to read validation annotations Size etc -->
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>1.1.0.Final</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>2.9.7</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Provided scope for Postgres JSON/JSONB support -->
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>42.2.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Test scope -->
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>oracle</groupId>-->
|
||||
<!--<artifactId>oracle-jdbc</artifactId>-->
|
||||
<!--<version>7.0</version>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-docker-run</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Optional: Add to use AgentLoaderSupport -->
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-agentloader</artifactId>
|
||||
<version>2.1.2</version>
|
||||
<scope>test</scope>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Provided: Spring, bring in explicitly -->
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-agent</artifactId>
|
||||
<version>11.11.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Provided scope so that the H2HistoryTrigger can live in Ebean core
|
||||
and not require a separate module for it -->
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.196</version>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${spring.framework.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.15.1</version>
|
||||
<scope>test</scope>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>${spring.framework.version}</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aspects</artifactId>
|
||||
<version>${spring.framework.version}</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<version>${spring.framework.version}</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>2.3.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
<version>6.4.0.jre8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<!-- Do not upgrade to 6.0.6: https://bugs.mysql.com/bug.php?id=82896 -->
|
||||
<version>5.1.43</version>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${spring.framework.version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.composite</groupId>
|
||||
<artifactId>avaje-composite-testing</artifactId>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
<artifactId>avaje-composite-testing-ebean</artifactId>
|
||||
<version>4.1</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.moduuid</groupId>
|
||||
<artifactId>avaje-moduuid</artifactId>
|
||||
<version>2.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>11.11.1</version>
|
||||
<version>8.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
<id>main</id>
|
||||
<phase>process-test-classes</phase>
|
||||
<configuration>
|
||||
<transformArgs>debug=1</transformArgs>
|
||||
<classSource>target/test-classes</classSource>
|
||||
<packages>com.avaje.**</packages>
|
||||
<transformArgs>debug=9</transformArgs>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>testEnhance</goal>
|
||||
<goal>enhance</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<configuration>
|
||||
<useSystemClassLoader>false</useSystemClassLoader>
|
||||
<failIfNoTests>false</failIfNoTests>
|
||||
<includes>
|
||||
<include>**/Test*.java</include>
|
||||
<include>**/*Test.java</include>
|
||||
<include>**/*Tests.java</include>
|
||||
</includes>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<!-- transfer datasource.default parameter -->
|
||||
<name>datasource.default</name>
|
||||
<value>${datasource.default}</value>
|
||||
</property>
|
||||
<property>
|
||||
<!-- transfer dbClockDelta parameter -->
|
||||
<name>dbClockDelta</name>
|
||||
<value>${dbClockDelta}</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<doctitle>Ebean 10</doctitle>
|
||||
<overview>src/main/java/io/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
<excludePackageNames>io.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
|
||||
<docletArtifact>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>pygments-doclet</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</docletArtifact>
|
||||
<additionalparam>
|
||||
-Xdoclint:none
|
||||
-include-basedir ${project.basedir}
|
||||
-attributes "idseparator=-; project_name=${project.name}; \
|
||||
project_version=${project.version}; \
|
||||
project_desc=${project.description}"
|
||||
</additionalparam>
|
||||
<linksource>true</linksource>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings
|
||||
only. It has no influence on the Maven build itself. -->
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
<lifecycleMappingMetadata>
|
||||
<pluginExecutions>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>
|
||||
org.avaje.ebean
|
||||
</groupId>
|
||||
<artifactId>
|
||||
ebean-maven-plugin
|
||||
</artifactId>
|
||||
<versionRange>
|
||||
[3,4)
|
||||
</versionRange>
|
||||
<goals>
|
||||
<goal>enhance</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore />
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
<docletArtifact>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>pygments-doclet</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</docletArtifact>
|
||||
<additionalparam>
|
||||
-Xdoclint:none
|
||||
</additionalparam>
|
||||
<linksource>true</linksource>
|
||||
</configuration>
|
||||
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
Class-Path:
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.avaje.ebean.springsupport;
|
||||
|
||||
import org.avaje.agentloader.AgentLoader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* To Setup Enhancement in Spring
|
||||
* <bean class="org.ebean.AgentLoaderSupport">
|
||||
* <property name="debug" value="1" />
|
||||
* <property name="packages" value="org.ebean.**" />
|
||||
* </bean>
|
||||
* Created by guor on 2015/5/11.
|
||||
*/
|
||||
public class AgentLoaderSupport implements InitializingBean {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private int debug;
|
||||
private String packages;
|
||||
|
||||
public int getDebug() {
|
||||
return debug;
|
||||
}
|
||||
|
||||
public void setDebug(int debug) {
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
public String getPackages() {
|
||||
return packages;
|
||||
}
|
||||
|
||||
public void setPackages(String packages) {
|
||||
this.packages = packages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String args = "debug=" + getDebug() + ";packages=" + getPackages();
|
||||
if (!AgentLoader.loadAgentFromClasspath("avaje-ebeanorm-agent", args)) {
|
||||
logger.info("avaje-ebeanorm-agent not found in classpath - not dynamically loaded");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (C) 2009 the original author or authors
|
||||
* <p>
|
||||
* This file is part of Ebean.
|
||||
* <p>
|
||||
* Ebean is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* Ebean is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebean.springsupport.factory;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.EbeanServerFactory;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
/**
|
||||
* A Spring FactoryBean for constructing EbeanServer instances.
|
||||
*
|
||||
* @since 18.05.2009
|
||||
* @author E Mc Greal
|
||||
*/
|
||||
public class EbeanServerFactoryBean implements InitializingBean, FactoryBean<EbeanServer> {
|
||||
|
||||
/**
|
||||
* The Ebean server configuration.
|
||||
*/
|
||||
private ServerConfig serverConfig;
|
||||
|
||||
/**
|
||||
* The EbeanServer instance.
|
||||
*/
|
||||
private EbeanServer ebeanServer;
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
if (serverConfig == null) {
|
||||
throw new Exception("No ServerConig set. You must define a ServerConfig bean");
|
||||
}
|
||||
|
||||
// Create the new EbeanServer using the configuration
|
||||
this.ebeanServer = EbeanServerFactory.create(serverConfig);
|
||||
}
|
||||
|
||||
public EbeanServer getObject() throws Exception {
|
||||
return ebeanServer;
|
||||
}
|
||||
|
||||
public Class<? extends EbeanServer> getObjectType() {
|
||||
return EbeanServer.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true for EbeanServer.
|
||||
*/
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the server configuration.
|
||||
*/
|
||||
public ServerConfig getServerConfig() {
|
||||
return serverConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the server configuration.
|
||||
*/
|
||||
public void setServerConfig(ServerConfig serverConfig) {
|
||||
this.serverConfig = serverConfig;
|
||||
}
|
||||
}
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
* Copyright (C) 2009 the original author or authors
|
||||
* <p>
|
||||
* This file is part of Ebean.
|
||||
* <p>
|
||||
* Ebean is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* Ebean is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebean.springsupport.txn;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.jdbc.datasource.ConnectionHolder;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
import com.avaje.ebean.config.ExternalTransactionManager;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultTransactionThreadLocal;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionManager;
|
||||
|
||||
/**
|
||||
* A Spring aware TransactionScopeManager.
|
||||
*
|
||||
* <p>
|
||||
* Will look for Spring transactions and use them if they exist.
|
||||
* </p>
|
||||
*
|
||||
* @since 18.05.2009
|
||||
* @author E Mc Greal
|
||||
*/
|
||||
public class SpringAwareJdbcTransactionManager implements ExternalTransactionManager {
|
||||
|
||||
private final static Logger logger = Logger.getLogger(SpringAwareJdbcTransactionManager.class.getName());
|
||||
|
||||
/**
|
||||
* The data source.
|
||||
*/
|
||||
private DataSource dataSource;
|
||||
|
||||
/**
|
||||
* The Ebean transaction manager.
|
||||
*/
|
||||
private TransactionManager transactionManager;
|
||||
|
||||
/**
|
||||
* The EbeanServer name.
|
||||
*/
|
||||
private String serverName;
|
||||
|
||||
/**
|
||||
* Instantiates a new spring aware transaction scope manager.
|
||||
*/
|
||||
public SpringAwareJdbcTransactionManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise this with the Ebean internal transaction manager.
|
||||
*/
|
||||
public void setTransactionManager(Object txnMgr) {
|
||||
|
||||
// RB: At this stage not exposing TransactionManager to
|
||||
// the public API and hence the Object type and casting here
|
||||
|
||||
this.transactionManager = (TransactionManager) txnMgr;
|
||||
this.dataSource = transactionManager.getDataSource();
|
||||
this.serverName = transactionManager.getServerName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for a current Spring managed transaction and wraps/returns that as a Ebean transaction.
|
||||
* <p>
|
||||
* Returns null if there is no current spring transaction (lazy loading outside a spring txn etc).
|
||||
* </p>
|
||||
*/
|
||||
public Object getCurrentTransaction() {
|
||||
|
||||
// Get the current Spring ConnectionHolder associated to the current spring managed transaction
|
||||
ConnectionHolder holder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
|
||||
|
||||
if (holder == null || !holder.isSynchronizedWithTransaction()) {
|
||||
// no current Spring transaction
|
||||
SpiTransaction currentEbeanTransaction = DefaultTransactionThreadLocal.get(serverName);
|
||||
if (currentEbeanTransaction != null) {
|
||||
// NOT expecting this so log WARNING
|
||||
String msg = "SpringTransaction - no current spring txn BUT using current Ebean one " + currentEbeanTransaction.getId();
|
||||
logger.log(Level.WARNING, msg);
|
||||
|
||||
} else if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.log(Level.FINEST, "Spring Txn - no current transaction ");
|
||||
}
|
||||
return currentEbeanTransaction;
|
||||
}
|
||||
|
||||
SpringTxnListener springTxnLister = getSpringTxnListener();
|
||||
|
||||
if (springTxnLister != null) {
|
||||
// we have already seen this transaction
|
||||
return springTxnLister.getTransaction();
|
||||
|
||||
} else {
|
||||
// This is a new spring transaction that we have not seen before.
|
||||
// "wrap" it in a SpringJdbcTransaction for use with Ebean
|
||||
SpringJdbcTransaction newTrans = new SpringJdbcTransaction(holder, transactionManager);
|
||||
|
||||
// Create and register a Spring TransactionSynchronization for this transaction
|
||||
springTxnLister = createSpringTxnListener(newTrans);
|
||||
TransactionSynchronizationManager.registerSynchronization(springTxnLister);
|
||||
|
||||
// also put in Ebean ThreadLocal
|
||||
DefaultTransactionThreadLocal.set(serverName, newTrans);
|
||||
return newTrans;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for our specific transaction listener.
|
||||
* <p>
|
||||
* If it exists then we have already seen and "wrapped" this transaction.
|
||||
* </p>
|
||||
*/
|
||||
private SpringTxnListener getSpringTxnListener() {
|
||||
|
||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations();
|
||||
if (synchronizations != null) {
|
||||
// search for our specific listener
|
||||
for (int i = 0; i < synchronizations.size(); i++) {
|
||||
if (synchronizations.get(i) instanceof SpringTxnListener) {
|
||||
return (SpringTxnListener) synchronizations.get(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a listener to register with Spring to enable Ebean to be
|
||||
* notified when transactions commit and rollback.
|
||||
* <p>
|
||||
* This is used by Ebean to notify it's appropriate listeners and maintain it's server
|
||||
* cache etc.
|
||||
* </p>
|
||||
*/
|
||||
private SpringTxnListener createSpringTxnListener(SpringJdbcTransaction t) {
|
||||
return new SpringTxnListener(transactionManager, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* A Spring TransactionSynchronization that we register with Spring to get
|
||||
* notified when a Spring managed transaction has been committed or rolled
|
||||
* back.
|
||||
* <p>
|
||||
* When Ebean is notified (of the commit/rollback) it can then manage its
|
||||
* cache, notify BeanPersistListeners etc.
|
||||
* </p>
|
||||
*/
|
||||
private static class SpringTxnListener extends TransactionSynchronizationAdapter {
|
||||
|
||||
private final TransactionManager transactionManager;
|
||||
|
||||
private final SpringJdbcTransaction transaction;
|
||||
|
||||
private final String serverName;
|
||||
|
||||
private SpringTxnListener(TransactionManager transactionManager, SpringJdbcTransaction t) {
|
||||
this.transactionManager = transactionManager;
|
||||
this.transaction = t;
|
||||
this.serverName = transactionManager.getServerName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated Ebean wrapped transaction.
|
||||
*/
|
||||
public SpringJdbcTransaction getTransaction() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeCommit(boolean readOnly) {
|
||||
// Future note: for JPA2 locking we will
|
||||
// have beforeCommit events to fire
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(int status) {
|
||||
|
||||
switch (status) {
|
||||
case STATUS_COMMITTED:
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.fine("Spring Txn [" + transaction.getId() + "] committed");
|
||||
}
|
||||
transactionManager.notifyOfCommit(transaction);
|
||||
break;
|
||||
|
||||
case STATUS_ROLLED_BACK:
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.fine("Spring Txn [" + transaction.getId() + "] rollback");
|
||||
}
|
||||
transactionManager.notifyOfRollback(transaction, null);
|
||||
break;
|
||||
|
||||
default:
|
||||
// this should never happen
|
||||
String msg = "Invalid status " + status;
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
|
||||
// Remove this transaction object as it is completed
|
||||
DefaultTransactionThreadLocal.replace(serverName, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (C) 2009 the original author or authors
|
||||
* <p>
|
||||
* This file is part of Ebean.
|
||||
* <p>
|
||||
* Ebean is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* Ebean is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package com.avaje.ebean.springsupport.txn;
|
||||
|
||||
import org.springframework.jdbc.datasource.ConnectionHolder;
|
||||
|
||||
import com.avaje.ebeaninternal.server.transaction.ExternalJdbcTransaction;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionManager;
|
||||
|
||||
public class SpringJdbcTransaction extends ExternalJdbcTransaction {
|
||||
|
||||
private final ConnectionHolder holder;
|
||||
|
||||
public SpringJdbcTransaction(ConnectionHolder holder, TransactionManager manager) {
|
||||
super("s" + holder.hashCode(), true, holder.getConnection(), manager);
|
||||
this.holder = holder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return holder.isSynchronizedWithTransaction();
|
||||
}
|
||||
|
||||
public ConnectionHolder getConnectionHolder() {
|
||||
return holder;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.persistence.PessimisticLockException;
|
||||
|
||||
/**
|
||||
* Thrown when failing to acquire a pessimistic lock.
|
||||
* <p>
|
||||
* Typically when "select for update nowait" or "select for update" is being used and
|
||||
* the lock can not be obtained (as it is held by another transaction).
|
||||
* </p>
|
||||
*/
|
||||
public class AcquireLockException extends PessimisticLockException {
|
||||
private static final long serialVersionUID = -8585962352965876691L;
|
||||
|
||||
/**
|
||||
* Create with a message and cause.
|
||||
*/
|
||||
public AcquireLockException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Administrative control of AutoTune during runtime.
|
||||
*/
|
||||
public interface AutoTune {
|
||||
|
||||
/**
|
||||
* Fire a garbage collection (hint to the JVM). Assuming garbage collection
|
||||
* fires this will gather remaining usage profiling information.
|
||||
*/
|
||||
void collectProfiling();
|
||||
|
||||
/**
|
||||
* Output the profiling.
|
||||
* <p>
|
||||
* When profiling updates are applied to tuning at runtime this reports all tuning and profiling combined.
|
||||
* When profiling is not applied at runtime then this reports the diff report with new and diff entries relative
|
||||
* to the existing tuning.
|
||||
* </p>
|
||||
*/
|
||||
void reportProfiling();
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Background thread pool service for executing of tasks asynchronously.
|
||||
* <p>
|
||||
* This service is used internally by Ebean for executing background tasks such
|
||||
* as the {@link Query#findFutureList()} and also for executing background tasks
|
||||
* periodically.
|
||||
* </p>
|
||||
* <p>
|
||||
* This service has been made available so you can use it for your application
|
||||
* code if you want. It can be useful for some server caching implementations
|
||||
* (background population and trimming of the cache etc).
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface BackgroundExecutor {
|
||||
|
||||
/**
|
||||
* Execute a task in the background.
|
||||
*/
|
||||
void execute(Runnable r);
|
||||
|
||||
/**
|
||||
* Execute a task periodically with a fixed delay between each execution.
|
||||
* <p>
|
||||
* For example, execute a runnable every minute.
|
||||
* </p>
|
||||
* <p>
|
||||
* The delay is the time between executions no matter how long the task took.
|
||||
* That is, this method has the same behaviour characteristics as
|
||||
* {@link ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)}
|
||||
* </p>
|
||||
*/
|
||||
void executePeriodically(Runnable r, long delay, TimeUnit unit);
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Provides finder functionality for use with "Dependency Injection style" use of Ebean.
|
||||
* <p>
|
||||
* Note that typically users would extend BeanRepository rather than BeanFinder.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* public class CustomerFinder extends BeanFinder<Long,Customer> {
|
||||
*
|
||||
* @Inject
|
||||
* public CustomerFinder(EbeanServer server) {
|
||||
* super(Customer.class, server);
|
||||
* }
|
||||
*
|
||||
* // ... add customer specific finders
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <I> The ID type
|
||||
* @param <T> The Bean type
|
||||
*/
|
||||
public abstract class BeanFinder<I,T> {
|
||||
|
||||
protected final EbeanServer server;
|
||||
|
||||
protected final Class<T> type;
|
||||
|
||||
/**
|
||||
* Create with the given bean type and EbeanServer instance.
|
||||
*
|
||||
* @param type The bean type
|
||||
* @param server The EbeanServer instance typically created via Spring factory or equivalent.
|
||||
*/
|
||||
protected BeanFinder(Class<T> type, EbeanServer server) {
|
||||
this.type = type;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the EbeanServer to use.
|
||||
*/
|
||||
public EbeanServer db() {
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current transaction.
|
||||
*/
|
||||
public Transaction currentTransaction() {
|
||||
return db().currentTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the JDBC batch on the current transaction.
|
||||
*/
|
||||
public void flush() {
|
||||
db().flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return typically a different EbeanServer to the default.
|
||||
* <p>
|
||||
* This is equivalent to {@link Ebean#getServer(String)}
|
||||
*
|
||||
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is
|
||||
* returned.
|
||||
*/
|
||||
public EbeanServer db(String server) {
|
||||
return Ebean.getServer(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an entity reference for this ID.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
|
||||
*/
|
||||
@Nonnull
|
||||
public T ref(I id) {
|
||||
return db().getReference(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an entity by ID.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class, Object)}
|
||||
*/
|
||||
@Nullable
|
||||
public T findById(I id) {
|
||||
return db().find(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an entity by ID returning an Optional.
|
||||
*/
|
||||
@Nullable
|
||||
public Optional<T> findByIdOrEmpty(I id) {
|
||||
return db().find(type).setId(id).findOneOrEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bean by Id.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#delete(Class, Object)}
|
||||
*/
|
||||
public void deleteById(I id) {
|
||||
db().delete(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all entities of the given type.
|
||||
*/
|
||||
@Nonnull
|
||||
public List<T> findAll() {
|
||||
return query().findList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an update query.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows =
|
||||
* updateQuery()
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#update(Class)}
|
||||
*/
|
||||
protected UpdateQuery<T> updateQuery() {
|
||||
return db().update(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class)}
|
||||
*/
|
||||
protected Query<T> query() {
|
||||
return db().find(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a native sql query.
|
||||
*/
|
||||
protected Query<T> nativeSql(String nativeSql) {
|
||||
return db().findNative(type, nativeSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query using the ORM query language.
|
||||
*/
|
||||
protected Query<T> query(String ormQuery) {
|
||||
return db().createQuery(type, ormQuery);
|
||||
}
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Provides finder functionality for use with "Dependency Injection style" use of Ebean.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Repository
|
||||
* public class CustomerRepository extends BeanRepository<Long,Customer> {
|
||||
*
|
||||
* @Inject
|
||||
* public CustomerRepository(EbeanServer server) {
|
||||
* super(Customer.class, server);
|
||||
* }
|
||||
*
|
||||
* // ... add customer specific finders and persist logic
|
||||
*
|
||||
* public List<Customer> findByName(String nameStart) {
|
||||
* return query().where()
|
||||
* .istartsWith("name", nameStart)
|
||||
* .findList();
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @param <I> The ID type
|
||||
* @param <T> The Bean type
|
||||
*/
|
||||
public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
|
||||
/**
|
||||
* Create with the given bean type and EbeanServer instance.
|
||||
* <p>
|
||||
* Typically users would extend BeanRepository rather than BeanFinder.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Inject
|
||||
* public CustomerRepository(EbeanServer server) {
|
||||
* super(Customer.class, server);
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param type The bean type
|
||||
* @param server The EbeanServer instance typically created via Spring factory or equivalent
|
||||
*/
|
||||
protected BeanRepository(Class<T> type, EbeanServer server) {
|
||||
super(type, server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the entity bean as dirty.
|
||||
* <p>
|
||||
* This is used so that when a bean that is otherwise unmodified is updated the version
|
||||
* property is updated.
|
||||
* <p>
|
||||
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
|
||||
* dirty so that it is not skipped.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer = customerRepository.byId(id);
|
||||
*
|
||||
* // mark the bean as dirty so that a save() or update() will
|
||||
* // increment the version property
|
||||
*
|
||||
* customerRepository.markAsDirty(customer);
|
||||
* customerRepository.save(customer);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see EbeanServer#markAsDirty(Object)
|
||||
*/
|
||||
public void markAsDirty(T bean) {
|
||||
db().markAsDirty(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the property as unset or 'not loaded'.
|
||||
* <p>
|
||||
* This would be used to specify a property that we did not wish to include in a stateless update.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // populate an entity bean from JSON or whatever
|
||||
* Customer customer = ...;
|
||||
*
|
||||
* // mark the email property as 'unset' so that it is not
|
||||
* // included in a 'stateless update'
|
||||
* customerRepository.markPropertyUnset(customer, "email");
|
||||
*
|
||||
* customerRepository.update(customer);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyName the name of the property on the bean to be marked as 'unset'
|
||||
*/
|
||||
public void markPropertyUnset(T bean, String propertyName) {
|
||||
((EntityBean) bean)._ebean_getIntercept().setPropertyLoaded(propertyName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert or update this entity depending on its state.
|
||||
* <p>
|
||||
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
|
||||
* insert or an update based on that.
|
||||
*
|
||||
* @see EbeanServer#save(Object)
|
||||
*/
|
||||
public void save(T bean) {
|
||||
db().save(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save all the beans in the collection.
|
||||
*/
|
||||
public int saveAll(Collection<T> bean) {
|
||||
return db().saveAll(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this entity.
|
||||
*
|
||||
* @see EbeanServer#update(Object)
|
||||
*/
|
||||
public void update(T bean) {
|
||||
db().update(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert this entity.
|
||||
*
|
||||
* @see EbeanServer#insert(Object)
|
||||
*/
|
||||
public void insert(T bean) {
|
||||
db().insert(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete this bean.
|
||||
* <p>
|
||||
* This will return true if the bean was deleted successfully or JDBC batch is being used.
|
||||
* </p>
|
||||
* <p>
|
||||
* If there is no current transaction one will be created and committed for
|
||||
* you automatically.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the Bean does not have a version property (or loaded version property) and
|
||||
* the bean does not exist then this returns false indicating that nothing was
|
||||
* deleted. Note that, if JDBC batch mode is used then this always returns true.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#delete(Object)
|
||||
*/
|
||||
public boolean delete(T bean) {
|
||||
return db().delete(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all the beans in the collection.
|
||||
*/
|
||||
public int deleteAll(Collection<T> beans) {
|
||||
return db().deleteAll(beans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bean permanently without soft delete.
|
||||
* <p>
|
||||
* This is used when the bean contains a <code>@SoftDelete</code> property and we
|
||||
* want to perform a hard/permanent delete.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#deletePermanent(Object)
|
||||
*/
|
||||
public boolean deletePermanent(T bean) {
|
||||
return db().deletePermanent(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge this entity using the default merge options.
|
||||
* <p>
|
||||
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
|
||||
* insert or an update based on that.
|
||||
*
|
||||
* @see EbeanServer#merge(Object)
|
||||
*/
|
||||
public void merge(T bean) {
|
||||
db().merge(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge this entity using the specified merge options.
|
||||
* <p>
|
||||
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
|
||||
* insert or an update based on that.
|
||||
*
|
||||
* @see EbeanServer#merge(Object, MergeOptions)
|
||||
*/
|
||||
public void merge(T bean, MergeOptions options) {
|
||||
db().merge(bean, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes this entity from the database.
|
||||
*
|
||||
* @see EbeanServer#refresh(Object)
|
||||
*/
|
||||
public void refresh(T bean) {
|
||||
db().refresh(bean);
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides access to the internal state of an entity bean.
|
||||
*/
|
||||
public interface BeanState {
|
||||
|
||||
/**
|
||||
* Return true if this is a lazy loading reference bean.
|
||||
* <p>
|
||||
* If so the this bean only holds the Id property and will invoke lazy loading
|
||||
* if any other property is get or set.
|
||||
* </p>
|
||||
*/
|
||||
boolean isReference();
|
||||
|
||||
/**
|
||||
* Return true if the bean is new (and not yet saved).
|
||||
*/
|
||||
boolean isNew();
|
||||
|
||||
/**
|
||||
* Return true if the bean is new or dirty (and probably needs to be saved).
|
||||
*/
|
||||
boolean isNewOrDirty();
|
||||
|
||||
/**
|
||||
* Return true if the bean has been changed but not yet saved.
|
||||
*/
|
||||
boolean isDirty();
|
||||
|
||||
/**
|
||||
* This can be called with true to disable lazy loading on the bean.
|
||||
*/
|
||||
void setDisableLazyLoad(boolean disableLazyLoading);
|
||||
|
||||
/**
|
||||
* Return true if the bean has lazy loading disabled.
|
||||
*/
|
||||
boolean isDisableLazyLoad();
|
||||
|
||||
/**
|
||||
* Set the loaded state of the property given it's name.
|
||||
* <p>
|
||||
* Typically this would be used to set the loaded state of a property
|
||||
* to false to ensure that the specific property is excluded from a
|
||||
* stateless update.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // populate a bean via say JSON
|
||||
* User user = ...;
|
||||
*
|
||||
* // set loaded state on the email property to false so that
|
||||
* // the email property is not included in a stateless update
|
||||
* Ebean.getBeanState(user).setPropertyLoaded("email", false);
|
||||
*
|
||||
* user.update();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* This will throw an IllegalArgumentException if the property is unknown.
|
||||
*/
|
||||
void setPropertyLoaded(String propertyName, boolean loaded);
|
||||
|
||||
/**
|
||||
* For partially populated beans returns the properties that are loaded on the
|
||||
* bean.
|
||||
* <p>
|
||||
* Accessing another property will cause lazy loading to occur.
|
||||
* </p>
|
||||
*/
|
||||
Set<String> getLoadedProps();
|
||||
|
||||
/**
|
||||
* Return the set of changed properties.
|
||||
*/
|
||||
Set<String> getChangedProps();
|
||||
|
||||
/**
|
||||
* Return a map of the updated properties and their new and old values.
|
||||
*/
|
||||
Map<String, ValuePair> getDirtyValues();
|
||||
|
||||
/**
|
||||
* Return true if the bean is readOnly.
|
||||
* <p>
|
||||
* If a setter is called on a readOnly bean it will throw an exception.
|
||||
* </p>
|
||||
*/
|
||||
boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Set the readOnly status for the bean.
|
||||
*/
|
||||
void setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Advanced - Used to programmatically build a partially or fully loaded
|
||||
* entity bean. First create an entity bean via
|
||||
* {@link EbeanServer#createEntityBean(Class)}, then populate its properties
|
||||
* and then call this method specifying which properties where loaded or null
|
||||
* for a fully loaded entity bean.
|
||||
*/
|
||||
void setLoaded();
|
||||
|
||||
/**
|
||||
* Reset the bean putting it into NEW state such that a save() results in an insert.
|
||||
*/
|
||||
void resetForInsert();
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Enum to control the different cache modes for queryCache and beanCache.
|
||||
* <h3>Bean cache</h3>
|
||||
* <p>
|
||||
* The bean cache is automatically used by default on <code>@Cache</code> beans for
|
||||
* the following queries:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>findOne() by id</li>
|
||||
* <li>findOne() by natural key(s)</li>
|
||||
* <li>findList() by ids</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Bean caching needs to be explicitly turned on for queries that are findList() by natural keys.
|
||||
* </p>
|
||||
* <h3>Query cache</h3>
|
||||
* <p>
|
||||
* For query cache use note that you must be careful, what you do with the returned collection.
|
||||
* By default the returned collections are read only and you will get an exception if you try
|
||||
* to change them.
|
||||
* If you add ".setReadOnly(false)" to your query, you'll get a collection that is a clone from the
|
||||
* one in the cache. That means, changing does not affect the cache.
|
||||
* </p>
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
public enum CacheMode {
|
||||
|
||||
/**
|
||||
* Do not use cache.
|
||||
*/
|
||||
OFF(false, false),
|
||||
|
||||
/**
|
||||
* Use the cache and store a result when needed.
|
||||
*/
|
||||
ON(true, true),
|
||||
|
||||
/**
|
||||
* Only used for bean caching.
|
||||
* <p>
|
||||
* The bean cache is automatically used by default on <code>@Cache</code> beans for
|
||||
* the following queries:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>findOne() by id</li>
|
||||
* <li>findOne() by natural key(s)</li>
|
||||
* <li>findList() by ids</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Bean caching needs to be explicitly turned on for queries that are findList() by natural keys.
|
||||
* </p>
|
||||
*/
|
||||
AUTO(true, true),
|
||||
|
||||
/**
|
||||
* Do not read from cache, but put beans into the cache and invalidate parts of the cache as necessary.
|
||||
* <p>
|
||||
* Use this on a query if you want to get the fresh value from database and put it into the cache.
|
||||
*/
|
||||
PUT(false, true),
|
||||
|
||||
/**
|
||||
* GET only from the cache.
|
||||
* <p>
|
||||
* This mode does not put entries into the cache or invalidate parts of the cache.
|
||||
*/
|
||||
GET(true, false);
|
||||
|
||||
private boolean get;
|
||||
private boolean put;
|
||||
|
||||
CacheMode(boolean get, boolean put) {
|
||||
this.get = get;
|
||||
this.put = put;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if value is read from cache.
|
||||
*/
|
||||
public boolean isGet() {
|
||||
return get;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a newly loaded value (from database) is put into the cache.
|
||||
*/
|
||||
public boolean isPut() {
|
||||
return put;
|
||||
}
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* For making calls to stored procedures. Refer to the Ebean execute() method.
|
||||
* <p>
|
||||
* Note that UpdateSql is designed for general DML sql and CallableSql is
|
||||
* designed for use with stored procedures. Also note that when using this in
|
||||
* batch mode the out parameters are not read.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example 1:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = "{call sp_order_mod(?,?)}";
|
||||
*
|
||||
* CallableSql cs = Ebean.createCallableSql(sql);
|
||||
* cs.setParameter(1, "turbo");
|
||||
* cs.registerOut(2, Types.INTEGER);
|
||||
*
|
||||
* Ebean.execute(cs);
|
||||
*
|
||||
* // read the out parameter
|
||||
* Integer returnValue = (Integer) cs.getObject(2);
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example 2:<br>
|
||||
* Includes batch mode, table modification information and label. Note that the
|
||||
* label is really only to help people reading the transaction logs to identify
|
||||
* the procedure called etc.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = "{call sp_insert_order(?,?)}";
|
||||
*
|
||||
* CallableSql cs = Ebean.createCallableSql(sql);
|
||||
*
|
||||
* // Inform Ebean this stored procedure inserts into the
|
||||
* // oe_order table and inserts + updates the oe_order_detail table.
|
||||
* // this is used to invalidate objects in the cache
|
||||
* cs.addModification("oe_order", true, false, false);
|
||||
* cs.addModification("oe_order_detail", true, true, false);
|
||||
*
|
||||
* Transaction t = Ebean.startTransaction();
|
||||
*
|
||||
* // execute using JDBC batching 10 statements at a time
|
||||
* t.setBatchMode(true);
|
||||
* t.setBatchSize(10);
|
||||
* try {
|
||||
* cs.setParameter(1, "Was");
|
||||
* cs.setParameter(2, "Banana");
|
||||
* Ebean.execute(cs);
|
||||
*
|
||||
* cs.setParameter(1, "Here");
|
||||
* cs.setParameter(2, "Kumera");
|
||||
* Ebean.execute(cs);
|
||||
*
|
||||
* cs.setParameter(1, "More");
|
||||
* cs.setParameter(2, "Apple");
|
||||
* Ebean.execute(cs);
|
||||
*
|
||||
* // Ebean.externalModification("oe_order",true,false,false);
|
||||
* // Ebean.externalModification("oe_order_detail",true,true,false);
|
||||
* Ebean.commitTransaction();
|
||||
*
|
||||
* } finally {
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @see SqlUpdate
|
||||
* @see Ebean#execute(CallableSql)
|
||||
*/
|
||||
public interface CallableSql {
|
||||
|
||||
/**
|
||||
* Return the label that is put into the transaction log.
|
||||
*/
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* Set the label that is put in the transaction log.
|
||||
*/
|
||||
CallableSql setLabel(String label);
|
||||
|
||||
/**
|
||||
* Return the statement execution timeout.
|
||||
*/
|
||||
int getTimeout();
|
||||
|
||||
/**
|
||||
* Return the callable sql.
|
||||
*/
|
||||
String getSql();
|
||||
|
||||
/**
|
||||
* Set the statement execution timeout. Zero implies unlimited time.
|
||||
* <p>
|
||||
* This is set to the underlying CallableStatement.
|
||||
* </p>
|
||||
*/
|
||||
CallableSql setTimeout(int secs);
|
||||
|
||||
/**
|
||||
* Set the callable sql.
|
||||
*/
|
||||
CallableSql setSql(String sql);
|
||||
|
||||
/**
|
||||
* Bind a parameter that is bound as a IN parameter.
|
||||
* <p>
|
||||
* position starts at value 1 (not 0) to be consistent with CallableStatement.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is designed so that you do not need to set params in index order. You
|
||||
* can set/register param 2 before param 1 etc.
|
||||
* </p>
|
||||
*
|
||||
* @param position the index position of the parameter.
|
||||
* @param value the value of the parameter.
|
||||
*/
|
||||
CallableSql bind(int position, Object value);
|
||||
|
||||
/**
|
||||
* Bind a positioned parameter (same as bind method).
|
||||
*
|
||||
* @param position the index position of the parameter.
|
||||
* @param value the value of the parameter.
|
||||
*/
|
||||
CallableSql setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Register an OUT parameter.
|
||||
* <p>
|
||||
* Note that position starts at value 1 (not 0) to be consistent with
|
||||
* CallableStatement.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is designed so that you do not need to register params in index order.
|
||||
* You can set/register param 2 before param 1 etc.
|
||||
* </p>
|
||||
*
|
||||
* @param position the index position of the parameter (starts with 1).
|
||||
* @param type the jdbc type of the OUT parameter that will be read.
|
||||
*/
|
||||
CallableSql registerOut(int position, int type);
|
||||
|
||||
/**
|
||||
* Return an OUT parameter value.
|
||||
* <p>
|
||||
* position starts at value 1 (not 0) to be consistent with CallableStatement.
|
||||
* </p>
|
||||
* <p>
|
||||
* This can only be called after the CallableSql has been executed. When run
|
||||
* in batch mode you effectively can't use this method.
|
||||
* </p>
|
||||
*/
|
||||
Object getObject(int position);
|
||||
|
||||
/**
|
||||
* You can extend this object and override this method for more advanced
|
||||
* stored procedure calls. This would be the case when ResultSets are returned
|
||||
* etc.
|
||||
*/
|
||||
boolean executeOverride(CallableStatement cstmt) throws SQLException;
|
||||
|
||||
/**
|
||||
* Add table modification information to the TransactionEvent.
|
||||
* <p>
|
||||
* This would be similar to using the
|
||||
* <code>Ebean.externalModification()</code> method. It may be easier and make
|
||||
* more sense to set it here with the CallableSql.
|
||||
* </p>
|
||||
* <p>
|
||||
* For UpdateSql the table modification information is derived by parsing the
|
||||
* sql to determine the table name and whether it was an insert, update or
|
||||
* delete.
|
||||
* </p>
|
||||
*/
|
||||
CallableSql addModification(String tableName, boolean inserts, boolean updates, boolean deletes);
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package io.ebean;
|
||||
/**
|
||||
* Enumeration to use with {@link Query#setCountDistinct(CountDistinctOrder)}.
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*
|
||||
*/
|
||||
public enum CountDistinctOrder {
|
||||
NO_ORDERING,
|
||||
|
||||
/** order by attribute ascending */
|
||||
ATTR_ASC,
|
||||
|
||||
/** order by attribute descending */
|
||||
ATTR_DESC,
|
||||
|
||||
/** order by count ascending and attribute ascending */
|
||||
COUNT_ASC_ATTR_ASC,
|
||||
|
||||
/** order by count ascending and attribute descending */
|
||||
COUNT_ASC_ATTR_DESC,
|
||||
|
||||
/** order by count descending and attribute ascending */
|
||||
COUNT_DESC_ATTR_ASC,
|
||||
|
||||
/** order by count descending and attribute descending */
|
||||
COUNT_DESC_ATTR_DESC,
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
/**
|
||||
* Holds a distinct value with it's count.
|
||||
* (Used with {@link Query#findSingleAttributeList()} and {@link Query#setCountDistinct(CountDistinctOrder)}.)
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
public class CountedValue<A> implements Serializable {
|
||||
private static final long serialVersionUID = -2267971668356749695L;
|
||||
|
||||
private final A value;
|
||||
private final long count;
|
||||
|
||||
public CountedValue(A value, long count) {
|
||||
this.value = value;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public A getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return count + ": " + value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
/**
|
||||
* Thrown when a foreign key constraint is enforced.
|
||||
*/
|
||||
public class DataIntegrityException extends PersistenceException {
|
||||
private static final long serialVersionUID = -6740171949170180970L;
|
||||
|
||||
/**
|
||||
* Create with a message and cause.
|
||||
*/
|
||||
public DataIntegrityException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Bean holding the details to update the document store.
|
||||
*/
|
||||
public final class DocStoreQueueEntry {
|
||||
|
||||
/**
|
||||
* Action to either update or delete a document from the index.
|
||||
*/
|
||||
public enum Action {
|
||||
|
||||
/**
|
||||
* Action is to update a document in the doc store.
|
||||
*/
|
||||
INDEX(1),
|
||||
|
||||
/**
|
||||
* Action is to delete a document from the doc store..
|
||||
*/
|
||||
DELETE(2),
|
||||
|
||||
/**
|
||||
* An update is required based on a change to a nested/embedded object at a given path.
|
||||
*/
|
||||
NESTED(3);
|
||||
|
||||
int value;
|
||||
|
||||
Action(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value associated with this action type.
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private final Action type;
|
||||
|
||||
private final String queueId;
|
||||
|
||||
private final String path;
|
||||
|
||||
private final Object beanId;
|
||||
|
||||
/**
|
||||
* Construct for an INDEX or DELETE action.
|
||||
*/
|
||||
public DocStoreQueueEntry(Action type, String queueId, Object beanId) {
|
||||
this(type, queueId, null, beanId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for an NESTED/embedded path invalidation action.
|
||||
*/
|
||||
public DocStoreQueueEntry(Action type, String queueId, String path, Object beanId) {
|
||||
this.type = type;
|
||||
this.queueId = queueId;
|
||||
this.path = path;
|
||||
this.beanId = beanId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the event type.
|
||||
*/
|
||||
public Action getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associate queueId.
|
||||
*/
|
||||
public String getQueueId() {
|
||||
return queueId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path if this is a nested update.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean id (which matches the document id).
|
||||
*/
|
||||
public Object getBeanId() {
|
||||
return beanId;
|
||||
}
|
||||
}
|
||||
@@ -1,310 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebeanservice.docstore.api.DocQueryRequest;
|
||||
import io.ebeanservice.docstore.api.RawDoc;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Document storage operations.
|
||||
*/
|
||||
public interface DocumentStore {
|
||||
|
||||
/**
|
||||
* Update the associated document store using the result of the query.
|
||||
* <p>
|
||||
* This will execute the query against the database creating a document for each
|
||||
* bean graph and sending this to the document store.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that the select and fetch paths of the query is set for you to match the
|
||||
* document structure needed based on <code>@DocStore</code> and <code>@DocStoreEmbedded</code>
|
||||
* so what this query requires is the predicates only.
|
||||
* </p>
|
||||
* <p>
|
||||
* This query will be executed using findEach so it is safe to use a query
|
||||
* that will fetch a lot of beans. The default bulkBatchSize is used.
|
||||
* </p>
|
||||
*
|
||||
* @param query The query that selects object to send to the document store.
|
||||
*/
|
||||
<T> void indexByQuery(Query<T> query);
|
||||
|
||||
/**
|
||||
* Update the associated document store index using the result of the query additionally specifying a
|
||||
* bulkBatchSize to use for sending the messages to ElasticSearch.
|
||||
*
|
||||
* @param query The query that selects object to send to the document store.
|
||||
* @param bulkBatchSize The batch size to use when bulk sending to the document store.
|
||||
*/
|
||||
<T> void indexByQuery(Query<T> query, int bulkBatchSize);
|
||||
|
||||
/**
|
||||
* Update the document store for all beans of this type.
|
||||
* <p>
|
||||
* This is the same as indexByQuery where the query has no predicates and so fetches all rows.
|
||||
* </p>
|
||||
*/
|
||||
void indexAll(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the bean by fetching it's content from the document store.
|
||||
* If the document is not found null is returned.
|
||||
* <p>
|
||||
* Typically this is called indirectly by findOne() on the query.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer =
|
||||
* server.find(Customer.class)
|
||||
* .setUseDocStore(true)
|
||||
* .setId(42)
|
||||
* .findOne();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Nullable
|
||||
<T> T find(DocQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the find list query. This request is prepared to execute secondary queries.
|
||||
* <p>
|
||||
* Typically this is called indirectly by findList() on the query that has setUseDocStore(true).
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> newCustomers =
|
||||
* server.find(Customer.class)
|
||||
* .setUseDocStore(true)
|
||||
* .where().eq("status, Customer.Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
<T> List<T> findList(DocQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the query against the document store returning the paged list.
|
||||
* <p>
|
||||
* The query should have <code>firstRow</code> or <code>maxRows</code> set prior to calling this method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Typically this is called indirectly by findPagedList() on the query that has setUseDocStore(true).
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Customer> newCustomers =
|
||||
* server.find(Customer.class)
|
||||
* .setUseDocStore(true)
|
||||
* .where().eq("status, Customer.Status.NEW)
|
||||
* .setMaxRows(50)
|
||||
* .findPagedList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
<T> PagedList<T> findPagedList(DocQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the query against the document store with the expectation of a large set of results
|
||||
* that are processed in a scrolling resultSet fashion.
|
||||
* <p>
|
||||
* For example, with the ElasticSearch doc store this uses SCROLL.
|
||||
* </p>
|
||||
* <p>
|
||||
* Typically this is called indirectly by findEach() on the query that has setUseDocStore(true).
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* server.find(Order.class)
|
||||
* .setUseDocStore(true)
|
||||
* .where()... // perhaps add predicates
|
||||
* .findEach((Order order) -> {
|
||||
* // process the bean ...
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
<T> void findEach(DocQueryRequest<T> query, Consumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query against the document store with the expectation of a large set of results
|
||||
* that are processed in a scrolling resultSet fashion.
|
||||
* <p>
|
||||
* Unlike findEach() this provides the opportunity to stop iterating through the large query.
|
||||
* </p>
|
||||
* <p>
|
||||
* For example, with the ElasticSearch doc store this uses SCROLL.
|
||||
* </p>
|
||||
* <p>
|
||||
* Typically this is called indirectly by findEachWhile() on the query that has setUseDocStore(true).
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* server.find(Order.class)
|
||||
* .setUseDocStore(true)
|
||||
* .where()... // perhaps add predicates
|
||||
* .findEachWhile(new Predicate<Order>() {
|
||||
* @Override
|
||||
* public void accept(Order bean) {
|
||||
* // process the bean
|
||||
*
|
||||
* // return true to continue, false to stop
|
||||
* // boolean shouldContinue = ...
|
||||
* return shouldContinue;
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
<T> void findEachWhile(DocQueryRequest<T> query, Predicate<T> consumer);
|
||||
|
||||
/**
|
||||
* Find each processing raw documents.
|
||||
*
|
||||
* @param indexNameType The full index name and type
|
||||
* @param rawQuery The query to execute
|
||||
* @param consumer Consumer to process each document
|
||||
*/
|
||||
void findEach(String indexNameType, String rawQuery, Consumer<RawDoc> consumer);
|
||||
|
||||
/**
|
||||
* Find each processing raw documents stopping when the predicate returns false.
|
||||
*
|
||||
* @param indexNameType The full index name and type
|
||||
* @param rawQuery The query to execute
|
||||
* @param consumer Consumer to process each document until false is returned
|
||||
*/
|
||||
void findEachWhile(String indexNameType, String rawQuery, Predicate<RawDoc> consumer);
|
||||
|
||||
/**
|
||||
* Process the queue entries sending updates to the document store or queuing them for later processing.
|
||||
*/
|
||||
long process(List<DocStoreQueueEntry> queueEntries) throws IOException;
|
||||
|
||||
/**
|
||||
* Drop the index from the document store (similar to DDL drop table).
|
||||
* <pre>{@code
|
||||
*
|
||||
* DocumentStore documentStore = server.docStore();
|
||||
*
|
||||
* documentStore.dropIndex("product_copy");
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
void dropIndex(String indexName);
|
||||
|
||||
/**
|
||||
* Create an index given a mapping file as a resource in the classPath (similar to DDL create table).
|
||||
* <pre>{@code
|
||||
*
|
||||
* DocumentStore documentStore = server.docStore();
|
||||
*
|
||||
* // uses product_copy.mapping.json resource
|
||||
* // ... to define mappings for the index
|
||||
*
|
||||
* documentStore.createIndex("product_copy", null);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param indexName the name of the new index
|
||||
* @param alias the alias of the index
|
||||
*/
|
||||
void createIndex(String indexName, String alias);
|
||||
|
||||
/**
|
||||
* Modify the settings on an index.
|
||||
* <p>
|
||||
* For example, this can be used be used to set elasticSearch refresh_interval
|
||||
* on an index before a bulk update.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // refresh_interval -1 ... disable refresh while bulk loading
|
||||
*
|
||||
* Map<String,Object> settings = new LinkedHashMap<>();
|
||||
* settings.put("refresh_interval", "-1");
|
||||
*
|
||||
* documentStore.indexSettings("product", settings);
|
||||
*
|
||||
* }</pre>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // refresh_interval 1s ... restore after bulk loading
|
||||
*
|
||||
* Map<String,Object> settings = new LinkedHashMap<>();
|
||||
* settings.put("refresh_interval", "1s");
|
||||
*
|
||||
* documentStore.indexSettings("product", settings);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param indexName the name of the index to update settings on
|
||||
* @param settings the settings to set on the index
|
||||
*/
|
||||
void indexSettings(String indexName, Map<String, Object> settings);
|
||||
|
||||
/**
|
||||
* Copy the index to a new index.
|
||||
* <p>
|
||||
* This copy process does not use the database but instead will copy from the source index to a destination index.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* long copyCount = documentStore.copyIndex(Product.class, "product_copy");
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The bean type of the source index
|
||||
* @param newIndex The name of the index to copy to
|
||||
* @return the number of documents copied to the new index
|
||||
*/
|
||||
long copyIndex(Class<?> beanType, String newIndex);
|
||||
|
||||
/**
|
||||
* Copy entries from an index to a new index but limiting to documents that have been
|
||||
* modified since the sinceEpochMillis time.
|
||||
* <p>
|
||||
* To support this the document needs to have a <code>@WhenModified</code> property.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* long copyCount = documentStore.copyIndex(Product.class, "product_copy", sinceMillis);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The bean type of the source index
|
||||
* @param newIndex The name of the index to copy to
|
||||
* @return the number of documents copied to the new index
|
||||
*/
|
||||
long copyIndex(Class<?> beanType, String newIndex, long sinceEpochMillis);
|
||||
|
||||
/**
|
||||
* Copy from a source index to a new index taking only the documents
|
||||
* matching the given query.
|
||||
* <pre>{@code
|
||||
*
|
||||
* // predicates to select the source documents to copy
|
||||
* Query<Product> query = server.find(Product.class)
|
||||
* .where()
|
||||
* .ge("whenModified", new Timestamp(since))
|
||||
* .ge("name", "A")
|
||||
* .lt("name", "D")
|
||||
* .query();
|
||||
*
|
||||
* // copy from the source index to "product_copy" index
|
||||
* long copyCount = documentStore.copyIndex(query, "product_copy", 1000);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param query The query to select the source documents to copy
|
||||
* @param newIndex The target index to copy the documents to
|
||||
* @param bulkBatchSize The ElasticSearch bulk batch size, if 0 uses the default.
|
||||
* @return The number of documents copied to the new index.
|
||||
*/
|
||||
long copyIndex(Query<?> query, String newIndex, int bulkBatchSize);
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Query for performing native SQL queries that return DTO Bean's.
|
||||
* <p>
|
||||
* These beans are just normal classes. They must have public constructors
|
||||
* and setters.
|
||||
* <p>
|
||||
* Constructors with arguments are used if the number of constructor arguments
|
||||
* matches the number of columns in the resultSet.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the number of columns in the resultSet is greater than the largest constructor
|
||||
* then the largest constructor is used for the first columns and remaining columns
|
||||
* are mapped by setter methods.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // CustomerDto is just a 'bean like' class
|
||||
* // with public constructor(s) and public setter methods
|
||||
*
|
||||
* String sql = "select id, name from customer where name like :name and status_code = :status";
|
||||
*
|
||||
* List<CustomerDto> beans =
|
||||
* Ebean.findDto(CustomrDto.class, sql)
|
||||
* .setParameter("name", "Acme%")
|
||||
* .setParameter("status", "ACTIVE")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public interface DtoQuery<T> {
|
||||
|
||||
/**
|
||||
* Execute the query returning a list.
|
||||
*/
|
||||
@Nonnull
|
||||
List<T> findList();
|
||||
|
||||
/**
|
||||
* Execute the query iterating a row at a time.
|
||||
* <p>
|
||||
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
|
||||
* </p>
|
||||
*/
|
||||
void findEach(Consumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query iterating a row at a time with the ability to stop consuming part way through.
|
||||
* <p>
|
||||
* Returning false after processing a row stops the iteration through the query results.
|
||||
* </p>
|
||||
* <p>
|
||||
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
|
||||
* </p>
|
||||
*/
|
||||
void findEachWhile(Predicate<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query returning a single bean.
|
||||
*/
|
||||
@Nullable
|
||||
T findOne();
|
||||
|
||||
/**
|
||||
* Execute the query returning an optional bean.
|
||||
*/
|
||||
@Nonnull
|
||||
Optional<T> findOneOrEmpty();
|
||||
|
||||
/**
|
||||
* The same as bind for named parameters.
|
||||
*/
|
||||
DtoQuery<T> setParameter(String name, Object value);
|
||||
|
||||
/**
|
||||
* The same as bind for positioned parameters.
|
||||
*/
|
||||
DtoQuery<T> setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set the index of the first row of the results to return.
|
||||
*/
|
||||
DtoQuery<T> setFirstRow(int firstRow);
|
||||
|
||||
/**
|
||||
* Set the maximum number of query results to return.
|
||||
*/
|
||||
DtoQuery<T> setMaxRows(int maxRows);
|
||||
|
||||
/**
|
||||
* When resultSet columns are not able to be mapped to a bean property then instead of
|
||||
* throwing effectively skip reading that column.
|
||||
*/
|
||||
DtoQuery<T> setRelaxedMode();
|
||||
|
||||
/**
|
||||
* Set a label on the query to make it easier to identify queries related to query execution statistics.
|
||||
*
|
||||
* @param label A label that is unique to the DTO bean type.
|
||||
*/
|
||||
DtoQuery<T> setLabel(String label);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
DtoQuery<T> 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>
|
||||
*/
|
||||
DtoQuery<T> setBufferFetchSizeHint(int bufferFetchSizeHint);
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Thrown when a duplicate is attempted on a unique constraint.
|
||||
*/
|
||||
public class DuplicateKeyException extends DataIntegrityException {
|
||||
private static final long serialVersionUID = -4771932723285724817L;
|
||||
|
||||
/**
|
||||
* Create with a message and cause.
|
||||
*/
|
||||
public DuplicateKeyException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,145 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.config.ContainerConfig;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.service.SpiContainer;
|
||||
import io.ebean.service.SpiContainerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* Creates EbeanServer instances.
|
||||
* <p>
|
||||
* This uses either a ServerConfig or properties in the ebean.properties file to
|
||||
* configure and create a EbeanServer instance.
|
||||
* </p>
|
||||
* <p>
|
||||
* The EbeanServer instance can either be registered with the Ebean singleton or
|
||||
* not. The Ebean singleton effectively holds a map of EbeanServers by a name.
|
||||
* If the EbeanServer is registered with the Ebean singleton you can retrieve it
|
||||
* later via {@link Ebean#getServer(String)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* One EbeanServer can be nominated as the 'default/primary' EbeanServer. Many
|
||||
* methods on the Ebean singleton such as {@link Ebean#find(Class)} are just a
|
||||
* convenient way of using the 'default/primary' EbeanServer.
|
||||
* </p>
|
||||
*/
|
||||
public class EbeanServerFactory {
|
||||
|
||||
|
||||
private static SpiContainer container;
|
||||
|
||||
static {
|
||||
EbeanVersion.getVersion(); // initalizes the version class and logs the version.
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the container with clustering configuration.
|
||||
* <p>
|
||||
* Call this prior to creating any EbeanServer instances or alternatively set the
|
||||
* ContainerConfig on the ServerConfig when creating the first EbeanServer instance.
|
||||
*/
|
||||
public static synchronized void initialiseContainer(ContainerConfig containerConfig) {
|
||||
getContainer(containerConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using ebean.properties to configure the server.
|
||||
*/
|
||||
public static synchronized EbeanServer create(String name) {
|
||||
|
||||
// construct based on loading properties files
|
||||
// and if invoked by Ebean then it handles registration
|
||||
SpiContainer serverFactory = getContainer(null);
|
||||
return serverFactory.createServer(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using the ServerConfig object to configure the server.
|
||||
*/
|
||||
public static synchronized EbeanServer create(ServerConfig config) {
|
||||
|
||||
if (config.getName() == null) {
|
||||
throw new PersistenceException("The name is null (it is required)");
|
||||
}
|
||||
|
||||
EbeanServer server = createInternal(config);
|
||||
|
||||
if (config.isRegister()) {
|
||||
PrimaryServer.setSkip(true);
|
||||
Ebean.register(server, config.isDefaultServer());
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using the ServerConfig additionally specifying a classLoader to use as the context class loader.
|
||||
*/
|
||||
public static synchronized EbeanServer createWithContextClassLoader(ServerConfig config, ClassLoader classLoader) {
|
||||
|
||||
ClassLoader currentContextLoader = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
try {
|
||||
return EbeanServerFactory.create(config);
|
||||
|
||||
} finally {
|
||||
// set the currentContextLoader back
|
||||
Thread.currentThread().setContextClassLoader(currentContextLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown gracefully all EbeanServers cleaning up any resources as required.
|
||||
* <p>
|
||||
* This is typically invoked via JVM shutdown hook and not explicitly called.
|
||||
* </p>
|
||||
*/
|
||||
public static synchronized void shutdown() {
|
||||
container.shutdown();
|
||||
}
|
||||
|
||||
|
||||
private static EbeanServer createInternal(ServerConfig config) {
|
||||
|
||||
return getContainer(config.getContainerConfig()).createServer(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the EbeanContainer initialising it if necessary.
|
||||
*
|
||||
* @param containerConfig the configuration controlling clustering communication
|
||||
*/
|
||||
private static SpiContainer getContainer(ContainerConfig containerConfig) {
|
||||
|
||||
// thread safe in that all calling methods are synchronized
|
||||
if (container != null) {
|
||||
return container;
|
||||
}
|
||||
|
||||
if (containerConfig == null) {
|
||||
// effectively load configuration from ebean.properties
|
||||
Properties properties = PrimaryServer.getProperties();
|
||||
containerConfig = new ContainerConfig();
|
||||
containerConfig.loadFromProperties(properties);
|
||||
}
|
||||
container = createContainer(containerConfig);
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the container instance using the configuration.
|
||||
*/
|
||||
protected static SpiContainer createContainer(ContainerConfig containerConfig) {
|
||||
|
||||
Iterator<SpiContainerFactory> factories = ServiceLoader.load(SpiContainerFactory.class).iterator();
|
||||
if (factories.hasNext()) {
|
||||
return factories.next().create(containerConfig);
|
||||
}
|
||||
throw new IllegalStateException("Service loader didn't find a SpiContainerFactory?");
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
/**
|
||||
* Class to determine the ebean version. (
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*
|
||||
*/
|
||||
public class EbeanVersion {
|
||||
private EbeanVersion() {
|
||||
|
||||
}
|
||||
private static final Logger logger = LoggerFactory.getLogger(EbeanVersion.class);
|
||||
|
||||
private static String version = "unknown";
|
||||
static {
|
||||
try {
|
||||
Properties prop = new Properties();
|
||||
try (InputStream in = Ebean.class.getResourceAsStream("/META-INF/maven/io.ebean/ebean/pom.properties")) {
|
||||
if (in != null) {
|
||||
prop.load(in);
|
||||
in.close();
|
||||
version = prop.getProperty("version");
|
||||
}
|
||||
}
|
||||
logger.info("ebean version: {}", version);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Could not determine ebean version: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ebean version (read from /META-INF/maven/io.ebean/ebean/pom.properties)
|
||||
*/
|
||||
public static String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Query by Example expression.
|
||||
* <p>
|
||||
* Pass in an example entity and for each non-null scalar properties an
|
||||
* expression is added.
|
||||
* </p>
|
||||
* <p>
|
||||
* By Default this case sensitive, will ignore numeric zero values and will use
|
||||
* a Like for string values (you must put in your own wildcards).
|
||||
* </p>
|
||||
* <p>
|
||||
* To get control over the options you can create an ExampleExpression and set
|
||||
* those options such as case insensitive etc.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* // create an example bean and set the properties
|
||||
* // with the query parameters you want
|
||||
* Customer example = new Customer();
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
* List<Customer> list =
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* // pass the bean into the where() clause
|
||||
* .exampleLike(example)
|
||||
* // you can add other expressions to the same query
|
||||
* .gt("id", 2)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* Similarly you can create an ExampleExpression
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer example = new Customer();
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
* // create a ExampleExpression with more control
|
||||
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO)
|
||||
* .includeZeros();
|
||||
*
|
||||
* List<Customer> list =
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .add(qbe)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public interface ExampleExpression extends Expression {
|
||||
|
||||
/**
|
||||
* By calling this method zero value properties are going to be included in
|
||||
* the expression.
|
||||
* <p>
|
||||
* By default numeric zero values are excluded as they can result from
|
||||
* primitive int and long types.
|
||||
* </p>
|
||||
*/
|
||||
ExampleExpression includeZeros();
|
||||
|
||||
/**
|
||||
* Set case insensitive to true.
|
||||
*/
|
||||
ExampleExpression caseInsensitive();
|
||||
|
||||
/**
|
||||
* Use startsWith expression for string properties.
|
||||
*/
|
||||
ExampleExpression useStartsWith();
|
||||
|
||||
/**
|
||||
* Use contains expression for string properties.
|
||||
*/
|
||||
ExampleExpression useContains();
|
||||
|
||||
/**
|
||||
* Use endsWith expression for string properties.
|
||||
*/
|
||||
ExampleExpression useEndsWith();
|
||||
|
||||
/**
|
||||
* Use equal to expression for string properties.
|
||||
*/
|
||||
ExampleExpression useEqualTo();
|
||||
|
||||
}
|
||||
@@ -1,333 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Expression factory for creating standard expressions for WHERE and HAVING
|
||||
* clauses.
|
||||
* <p>
|
||||
* Generally you will only need to use this object for creating OR, JUNCTION or
|
||||
* CONJUNCTION expressions. To create simple expressions you will most likely
|
||||
* just use the methods on the ExpressionList object that is returned via
|
||||
* {@link Query#where()}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This provides a convenient way to create expressions for the 'Default'
|
||||
* server. It is actually a short cut for using the ExpressionFactory of the
|
||||
* 'default' EbeanServer.
|
||||
* <p>
|
||||
* See also {@link Ebean#getExpressionFactory()}
|
||||
* </p>
|
||||
* <p>
|
||||
* Creates standard common expressions for using in a Query Where or Having
|
||||
* clause.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Example: Using an Expr.or() method
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.where(
|
||||
* Expr.or(Expr.eq("status", Order.NEW),
|
||||
* Expr.gt("orderDate", lastWeek));
|
||||
*
|
||||
* List<Order> list = query.findList();
|
||||
* ...
|
||||
* }</pre>
|
||||
*
|
||||
* @see Query#where()
|
||||
*/
|
||||
public class Expr {
|
||||
|
||||
private Expr() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
public static Expression eq(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().eq(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not Equal To - property not equal to the given value.
|
||||
*/
|
||||
public static Expression ne(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().ne(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case Insensitive Equal To - property equal to the given value (typically
|
||||
* using a lower() function to make it case insensitive).
|
||||
*/
|
||||
public static Expression ieq(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().ieq(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
public static Expression between(String propertyName, Object value1, Object value2) {
|
||||
|
||||
return Ebean.getExpressionFactory().between(propertyName, value1, value2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Between - value between two given properties.
|
||||
*/
|
||||
public static Expression between(String lowProperty, String highProperty, Object value) {
|
||||
|
||||
return Ebean.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Greater Than - property greater than the given value.
|
||||
*/
|
||||
public static Expression gt(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().gt(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Greater Than or Equal to - property greater than or equal to the given
|
||||
* value.
|
||||
*/
|
||||
public static Expression ge(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().ge(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Less Than - property less than the given value.
|
||||
*/
|
||||
public static Expression lt(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().lt(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Less Than or Equal to - property less than or equal to the given value.
|
||||
*/
|
||||
public static Expression le(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().le(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Null - property is null.
|
||||
*/
|
||||
public static Expression isNull(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNull(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Not Null - property is not null.
|
||||
*/
|
||||
public static Expression isNotNull(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNotNull(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive {@link #exampleLike(Object)}
|
||||
*/
|
||||
public static ExampleExpression iexampleLike(Object example) {
|
||||
return Ebean.getExpressionFactory().iexampleLike(example);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the query by Example expression which is case sensitive and using
|
||||
* LikeType.RAW (you need to add you own wildcards % and _).
|
||||
*/
|
||||
public static ExampleExpression exampleLike(Object example) {
|
||||
return Ebean.getExpressionFactory().exampleLike(example);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the query by Example expression specifying more options.
|
||||
*/
|
||||
public static ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType) {
|
||||
return Ebean.getExpressionFactory().exampleLike(example, caseInsensitive, likeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like - property like value where the value contains the SQL wild card
|
||||
* characters % (percentage) and _ (underscore).
|
||||
*/
|
||||
public static Expression like(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().like(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive Like - property like value where the value contains the
|
||||
* SQL wild card characters % (percentage) and _ (underscore). Typically uses
|
||||
* a lower() function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression ilike(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().ilike(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts With - property like value%.
|
||||
*/
|
||||
public static Expression startsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().startsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive Starts With - property like value%. Typically uses a
|
||||
* lower() function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression istartsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().istartsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends With - property like %value.
|
||||
*/
|
||||
public static Expression endsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().endsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive Ends With - property like %value. Typically uses a lower()
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression iendsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().iendsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains - property like %value%.
|
||||
*/
|
||||
public static Expression contains(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().contains(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive Contains - property like %value%. Typically uses a lower()
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression icontains(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().icontains(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* For collection properties that are empty (have not existing elements).
|
||||
*/
|
||||
public static Expression isEmpty(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isEmpty(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* For collection properties that are not empty (have existing elements).
|
||||
*/
|
||||
public static Expression isNotEmpty(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNotEmpty(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the array of values.
|
||||
*/
|
||||
public static Expression in(String propertyName, Object[] values) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - using a subQuery.
|
||||
*/
|
||||
public static Expression in(String propertyName, Query<?> subQuery) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the collection of values.
|
||||
*/
|
||||
public static Expression in(String propertyName, Collection<?> values) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Id Equal to - ID property is equal to the value.
|
||||
*/
|
||||
public static Expression idEq(Object value) {
|
||||
return Ebean.getExpressionFactory().idEq(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* All Equal - Map containing property names and their values.
|
||||
* <p>
|
||||
* Expression where all the property names in the map are equal to the
|
||||
* corresponding value.
|
||||
* </p>
|
||||
*
|
||||
* @param propertyMap a map keyed by property names.
|
||||
*/
|
||||
public static Expression allEq(Map<String, Object> propertyMap) {
|
||||
return Ebean.getExpressionFactory().allEq(propertyMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw expression with a single parameter.
|
||||
* <p>
|
||||
* The raw expression should contain a single ? at the location of the
|
||||
* parameter.
|
||||
* </p>
|
||||
*/
|
||||
public static Expression raw(String raw, Object value) {
|
||||
return Ebean.getExpressionFactory().raw(raw, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw expression with an array of parameters.
|
||||
* <p>
|
||||
* The raw expression should contain the same number of ? as there are
|
||||
* parameters.
|
||||
* </p>
|
||||
*/
|
||||
public static Expression raw(String raw, Object[] values) {
|
||||
return Ebean.getExpressionFactory().raw(raw, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw expression with no parameters.
|
||||
*/
|
||||
public static Expression raw(String raw) {
|
||||
return Ebean.getExpressionFactory().raw(raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* And - join two expressions with a logical and.
|
||||
*/
|
||||
public static Expression and(Expression expOne, Expression expTwo) {
|
||||
|
||||
return Ebean.getExpressionFactory().and(expOne, expTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Or - join two expressions with a logical or.
|
||||
*/
|
||||
public static Expression or(Expression expOne, Expression expTwo) {
|
||||
|
||||
return Ebean.getExpressionFactory().or(expOne, expTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate the expression (prefix it with NOT).
|
||||
*/
|
||||
public static Expression not(Expression exp) {
|
||||
|
||||
return Ebean.getExpressionFactory().not(exp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by AND's.
|
||||
*/
|
||||
public static <T> Junction<T> conjunction(Query<T> query) {
|
||||
|
||||
return Ebean.getExpressionFactory().conjunction(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
*/
|
||||
public static <T> Junction<T> disjunction(Query<T> query) {
|
||||
|
||||
return Ebean.getExpressionFactory().disjunction(query);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* An expression that is part of a WHERE or HAVING clause.
|
||||
*/
|
||||
public interface Expression {
|
||||
|
||||
}
|
||||
@@ -1,445 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.search.Match;
|
||||
import io.ebean.search.MultiMatch;
|
||||
import io.ebean.search.TextCommonTerms;
|
||||
import io.ebean.search.TextQueryString;
|
||||
import io.ebean.search.TextSimple;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Expression factory for creating standard expressions.
|
||||
* <p>
|
||||
* Creates standard common expressions for using in a Query Where or Having
|
||||
* clause.
|
||||
* </p>
|
||||
* <p>
|
||||
* You will often not use this class directly but instead just add expressions
|
||||
* via the methods on ExpressionList such as
|
||||
* {@link ExpressionList#gt(String, Object)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* The ExpressionList is returned from {@link Query#where()}.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* // Example: fetch orders where status equals new or orderDate > lastWeek.
|
||||
*
|
||||
* Expression newOrLastWeek =
|
||||
* Expr.or(Expr.eq("status", Order.Status.NEW),
|
||||
* Expr.gt("orderDate", lastWeek));
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.where().add(newOrLastWeek);
|
||||
* List<Order> list = query.findList();
|
||||
* ...
|
||||
* }</pre>
|
||||
*
|
||||
* @see Query#where()
|
||||
*/
|
||||
public interface ExpressionFactory {
|
||||
|
||||
/**
|
||||
* Path exists - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonExists(String propertyName, String path);
|
||||
|
||||
/**
|
||||
* Path does not exist - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonNotExists(String propertyName, String path);
|
||||
|
||||
/**
|
||||
* Equal to - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonEqualTo(String propertyName, String path, Object val);
|
||||
|
||||
/**
|
||||
* Not Equal to - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonNotEqualTo(String propertyName, String path, Object val);
|
||||
|
||||
/**
|
||||
* Greater than - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonGreaterThan(String propertyName, String path, Object val);
|
||||
|
||||
/**
|
||||
* Greater than or equal to - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonGreaterOrEqual(String propertyName, String path, Object val);
|
||||
|
||||
/**
|
||||
* Less than - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonLessThan(String propertyName, String path, Object val);
|
||||
|
||||
/**
|
||||
* Less than or equal to - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonLessOrEqualTo(String propertyName, String path, Object val);
|
||||
|
||||
/**
|
||||
* Between - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonBetween(String propertyName, String path, Object lowerValue, Object upperValue);
|
||||
|
||||
/**
|
||||
* Array contains all the given values.
|
||||
* <p>
|
||||
* Array support is effectively limited to Postgres at this time.
|
||||
* </p>
|
||||
*/
|
||||
Expression arrayContains(String propertyName, Object... values);
|
||||
|
||||
/**
|
||||
* Array does not contain the given values.
|
||||
* <p>
|
||||
* Array support is effectively limited to Postgres at this time.
|
||||
* </p>
|
||||
*/
|
||||
Expression arrayNotContains(String propertyName, Object... values);
|
||||
|
||||
/**
|
||||
* Array is empty - for the given array property.
|
||||
* <p>
|
||||
* Array support is effectively limited to Postgres at this time.
|
||||
* </p>
|
||||
*/
|
||||
Expression arrayIsEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Array is not empty - for the given array property.
|
||||
* <p>
|
||||
* Array support is effectively limited to Postgres at this time.
|
||||
* </p>
|
||||
*/
|
||||
Expression arrayIsNotEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
Expression eq(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Not Equal To - property not equal to the given value.
|
||||
*/
|
||||
Expression ne(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Case Insensitive Equal To - property equal to the given value (typically
|
||||
* using a lower() function to make it case insensitive).
|
||||
*/
|
||||
Expression ieq(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case Insensitive Equal To that allows for named parameter use.
|
||||
*/
|
||||
Expression ieqObject(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
Expression between(String propertyName, Object value1, Object value2);
|
||||
|
||||
/**
|
||||
* Between - value between two given properties.
|
||||
*/
|
||||
Expression betweenProperties(String lowProperty, String highProperty, Object value);
|
||||
|
||||
/**
|
||||
* Greater Than - property greater than the given value.
|
||||
*/
|
||||
Expression gt(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Greater Than or Equal to - property greater than or equal to the given
|
||||
* value.
|
||||
*/
|
||||
Expression ge(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than - property less than the given value.
|
||||
*/
|
||||
Expression lt(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than or Equal to - property less than or equal to the given value.
|
||||
*/
|
||||
Expression le(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Is Null - property is null.
|
||||
*/
|
||||
Expression isNull(String propertyName);
|
||||
|
||||
/**
|
||||
* Is Not Null - property is not null.
|
||||
*/
|
||||
Expression isNotNull(String propertyName);
|
||||
|
||||
/**
|
||||
* Case insensitive {@link #exampleLike(Object)}
|
||||
*/
|
||||
ExampleExpression iexampleLike(Object example);
|
||||
|
||||
/**
|
||||
* Create the query by Example expression which is case sensitive and using
|
||||
* LikeType.RAW (you need to add you own wildcards % and _).
|
||||
*/
|
||||
ExampleExpression exampleLike(Object example);
|
||||
|
||||
/**
|
||||
* Create the query by Example expression specifying more options.
|
||||
*/
|
||||
ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType);
|
||||
|
||||
/**
|
||||
* Like with support for named parameters.
|
||||
*/
|
||||
Expression like(String propertyName, Object value, boolean caseInsensitive, LikeType likeType);
|
||||
|
||||
/**
|
||||
* Like - property like value where the value contains the SQL wild card
|
||||
* characters % (percentage) and _ (underscore).
|
||||
*/
|
||||
Expression like(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Like - property like value where the value contains the
|
||||
* SQL wild card characters % (percentage) and _ (underscore). Typically uses
|
||||
* a lower() function to make the expression case insensitive.
|
||||
*/
|
||||
Expression ilike(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Starts With - property like value%.
|
||||
*/
|
||||
Expression startsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Starts With - property like value%. Typically uses a
|
||||
* lower() function to make the expression case insensitive.
|
||||
*/
|
||||
Expression istartsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Ends With - property like %value.
|
||||
*/
|
||||
Expression endsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Ends With - property like %value. Typically uses a lower()
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
Expression iendsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Contains - property like %value%.
|
||||
*/
|
||||
Expression contains(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Contains - property like %value%. Typically uses a lower()
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
Expression icontains(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* In expression using pairs of value objects.
|
||||
*/
|
||||
Expression inPairs(Pairs pairs);
|
||||
|
||||
/**
|
||||
* In - property has a value in the array of values.
|
||||
*/
|
||||
Expression in(String propertyName, Object[] values);
|
||||
|
||||
/**
|
||||
* In - using a subQuery.
|
||||
*/
|
||||
Expression in(String propertyName, Query<?> subQuery);
|
||||
|
||||
/**
|
||||
* In - property has a value in the collection of values.
|
||||
*/
|
||||
Expression in(String propertyName, Collection<?> values);
|
||||
|
||||
/**
|
||||
* Not In - property has a value in the array of values.
|
||||
*/
|
||||
Expression notIn(String propertyName, Object[] values);
|
||||
|
||||
/**
|
||||
* Not In - property has a value in the collection of values.
|
||||
*/
|
||||
Expression notIn(String propertyName, Collection<?> values);
|
||||
|
||||
/**
|
||||
* Not In - using a subQuery.
|
||||
*/
|
||||
Expression notIn(String propertyName, Query<?> subQuery);
|
||||
|
||||
/**
|
||||
* Exists expression
|
||||
*/
|
||||
Expression exists(Query<?> subQuery);
|
||||
|
||||
/**
|
||||
* Not exists expression
|
||||
*/
|
||||
Expression notExists(Query<?> subQuery);
|
||||
|
||||
/**
|
||||
* Is empty expression for collection properties.
|
||||
*/
|
||||
Expression isEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Is not empty expression for collection properties.
|
||||
*/
|
||||
Expression isNotEmpty(String propertyName);
|
||||
|
||||
/**
|
||||
* Id Equal to - ID property is equal to the value.
|
||||
*/
|
||||
Expression idEq(Object value);
|
||||
|
||||
/**
|
||||
* Id IN a list of Id values.
|
||||
*/
|
||||
Expression idIn(Object... idValues);
|
||||
|
||||
/**
|
||||
* Id IN a collection of Id values.
|
||||
*/
|
||||
Expression idIn(Collection<?> idCollection);
|
||||
|
||||
/**
|
||||
* All Equal - Map containing property names and their values.
|
||||
* <p>
|
||||
* Expression where all the property names in the map are equal to the
|
||||
* corresponding value.
|
||||
* </p>
|
||||
*
|
||||
* @param propertyMap a map keyed by property names.
|
||||
*/
|
||||
Expression allEq(Map<String, Object> propertyMap);
|
||||
|
||||
/**
|
||||
* Add expression for ANY of the given bit flags to be set.
|
||||
*
|
||||
* @param propertyName The property that holds the flags value
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
Expression bitwiseAny(String propertyName, long flags);
|
||||
|
||||
/**
|
||||
* Add expression for ALL of the given bit flags to be set.
|
||||
*
|
||||
* @param propertyName The property that holds the flags value
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
Expression bitwiseAll(String propertyName, long flags);
|
||||
|
||||
/**
|
||||
* Add bitwise AND expression of the given bit flags to compare with the match/mask.
|
||||
*
|
||||
* @param propertyName The property that holds the flags value
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
Expression bitwiseAnd(String propertyName, long flags, long match);
|
||||
|
||||
/**
|
||||
* Add raw expression with a single parameter.
|
||||
* <p>
|
||||
* The raw expression should contain a single ? at the location of the
|
||||
* parameter.
|
||||
* </p>
|
||||
*/
|
||||
Expression raw(String raw, Object value);
|
||||
|
||||
/**
|
||||
* Add raw expression with an array of parameters.
|
||||
* <p>
|
||||
* The raw expression should contain the same number of ? as there are
|
||||
* parameters.
|
||||
* </p>
|
||||
*/
|
||||
Expression raw(String raw, Object[] values);
|
||||
|
||||
/**
|
||||
* Add raw expression with no parameters.
|
||||
*/
|
||||
Expression raw(String raw);
|
||||
|
||||
/**
|
||||
* Create a Text Match expression (currently doc store/Elastic only).
|
||||
*/
|
||||
Expression textMatch(String propertyName, String search, Match options);
|
||||
|
||||
/**
|
||||
* Create a Text Multi match expression (currently doc store/Elastic only).
|
||||
*/
|
||||
Expression textMultiMatch(String query, MultiMatch options);
|
||||
|
||||
/**
|
||||
* Create a text simple query expression (currently doc store/Elastic only).
|
||||
*/
|
||||
Expression textSimple(String search, TextSimple options);
|
||||
|
||||
/**
|
||||
* Create a text query string expression (currently doc store/Elastic only).
|
||||
*/
|
||||
Expression textQueryString(String search, TextQueryString options);
|
||||
|
||||
/**
|
||||
* Create a text common terms expression (currently doc store/Elastic only).
|
||||
*/
|
||||
Expression textCommonTerms(String search, TextCommonTerms options);
|
||||
|
||||
/**
|
||||
* And - join two expressions with a logical and.
|
||||
*/
|
||||
Expression and(Expression expOne, Expression expTwo);
|
||||
|
||||
/**
|
||||
* Or - join two expressions with a logical or.
|
||||
*/
|
||||
Expression or(Expression expOne, Expression expTwo);
|
||||
|
||||
/**
|
||||
* Negate the expression (prefix it with NOT).
|
||||
*/
|
||||
Expression not(Expression exp);
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by AND's.
|
||||
*/
|
||||
<T> Junction<T> conjunction(Query<T> query);
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
*/
|
||||
<T> Junction<T> disjunction(Query<T> query);
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by AND's.
|
||||
*/
|
||||
<T> Junction<T> conjunction(Query<T> query, ExpressionList<T> parent);
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
*/
|
||||
<T> Junction<T> disjunction(Query<T> query, ExpressionList<T> parent);
|
||||
|
||||
/**
|
||||
* Return a Text query junction for MUST, SHOULD or MUST NOT.
|
||||
* <p>
|
||||
* This is doc store Elastic only.
|
||||
* </p>
|
||||
*/
|
||||
<T> Junction<T> junction(Junction.Type type, Query<T> query, ExpressionList<T> parent);
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,452 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
import java.time.Clock;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* The extended API for EbeanServer.
|
||||
* <p>
|
||||
* This provides the finder methods that take an explicit transaction rather than obtaining
|
||||
* the transaction from the usual mechanism (which is ThreadLocal based).
|
||||
* </p>
|
||||
* <p>
|
||||
* In general we only want to use this ExtendedServer API when we want to avoid / bypass
|
||||
* the use of the mechanism to get the current transaction and instead explicitly supply
|
||||
* the transaction to use.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that in all cases the transaction supplied can be null and in this case the EbeanServer
|
||||
* will use the normal mechanism to obtain the transaction to use.
|
||||
* </p>
|
||||
*/
|
||||
public interface ExtendedServer {
|
||||
|
||||
/**
|
||||
* Return the NOW time from the Clock.
|
||||
*/
|
||||
long clockNow();
|
||||
|
||||
/**
|
||||
* Set the Clock to use for <code>@WhenCreated</code> and <code>@WhenModified</code>.
|
||||
* <p>
|
||||
* Note that we only expect to change the Clock for testing purposes.
|
||||
* </p>
|
||||
*/
|
||||
void setClock(Clock clock);
|
||||
|
||||
/**
|
||||
* Return the number of 'top level' or 'root' entities this query should return.
|
||||
*
|
||||
* @see Query#findCount()
|
||||
* @see Query#findFutureCount()
|
||||
*/
|
||||
<T> int findCount(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Return the Id values of the query as a List.
|
||||
*
|
||||
* @see Query#findIds()
|
||||
*/
|
||||
@Nonnull
|
||||
<A, T> List<A> findIds(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Return a QueryIterator for the query.
|
||||
* <p>
|
||||
* Generally using {@link #findEach(Query, Consumer, Transaction)} or
|
||||
* {@link #findEachWhile(Query, Predicate, Transaction)} is preferred
|
||||
* to findIterate(). The reason is that those methods automatically take care of
|
||||
* closing the queryIterator (and the underlying jdbc statement and resultSet).
|
||||
* </p>
|
||||
* <p>
|
||||
* This is similar to findEach in that not all the result beans need to be held
|
||||
* in memory at the same time and as such is good for processing large queries.
|
||||
* </p>
|
||||
*
|
||||
* @see Query#findIterate()
|
||||
* @see Query#findEach(Consumer)
|
||||
* @see Query#findEachWhile(Predicate)
|
||||
*/
|
||||
@Nonnull
|
||||
<T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query visiting the each bean one at a time.
|
||||
* <p>
|
||||
* Unlike findList() this is suitable for processing a query that will return
|
||||
* a very large resultSet. The reason is that not all the result beans need to be
|
||||
* held in memory at the same time and instead processed one at a time.
|
||||
* </p>
|
||||
* <p>
|
||||
* Internally this query using a PersistenceContext scoped to each bean (and the
|
||||
* beans associated object graph).
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* ebeanServer.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .findEach((Order order) -> {
|
||||
*
|
||||
* // do something with the order bean
|
||||
* System.out.println(" -- processing order ... " + order);
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see Query#findEach(Consumer)
|
||||
* @see Query#findEachWhile(Predicate)
|
||||
*/
|
||||
<T> void findEach(Query<T> query, Consumer<T> consumer, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query visiting the each bean one at a time.
|
||||
* <p>
|
||||
* Compared to findEach() this provides the ability to stop processing the query
|
||||
* results early by returning false for the Predicate.
|
||||
* </p>
|
||||
* <p>
|
||||
* Unlike findList() this is suitable for processing a query that will return
|
||||
* a very large resultSet. The reason is that not all the result beans need to be
|
||||
* held in memory at the same time and instead processed one at a time.
|
||||
* </p>
|
||||
* <p>
|
||||
* Internally this query using a PersistenceContext scoped to each bean (and the
|
||||
* beans associated object graph).
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* ebeanServer.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .findEachWhile((Order order) -> {
|
||||
*
|
||||
* // do something with the order bean
|
||||
* System.out.println(" -- processing order ... " + order);
|
||||
*
|
||||
* boolean carryOnProcessing = ...
|
||||
* return carryOnProcessing;
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see Query#findEach(Consumer)
|
||||
* @see Query#findEachWhile(Predicate)
|
||||
*/
|
||||
<T> void findEachWhile(Query<T> query, Predicate<T> consumer, Transaction transaction);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
@Nonnull
|
||||
<T> List<Version<T>> findVersions(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute a query returning a list of beans.
|
||||
* <p>
|
||||
* Generally you are able to use {@link Query#findList()} rather than
|
||||
* explicitly calling this method. You could use this method if you wish to
|
||||
* explicitly control the transaction used for the query.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* .where().ilike("name", "rob%")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T> the type of entity bean to fetch.
|
||||
* @param query the query to execute.
|
||||
* @param transaction the transaction to use (can be null).
|
||||
* @return the list of fetched beans.
|
||||
* @see Query#findList()
|
||||
*/
|
||||
@Nonnull
|
||||
<T> List<T> findList(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* 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>
|
||||
*
|
||||
* @param query the query to execute the row count on
|
||||
* @param transaction the transaction (can be null).
|
||||
* @return a Future object for the row count query
|
||||
* @see Query#findFutureCount()
|
||||
*/
|
||||
@Nonnull
|
||||
<T> FutureRowCount<T> findFutureCount(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* 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>
|
||||
*
|
||||
* @param query the query to execute the fetch Id's on
|
||||
* @param transaction the transaction (can be null).
|
||||
* @return a Future object for the list of Id's
|
||||
* @see Query#findFutureIds()
|
||||
*/
|
||||
@Nonnull
|
||||
<T> FutureIds<T> findFutureIds(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute find list query in a background thread returning a FutureList object.
|
||||
* <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>
|
||||
* 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.
|
||||
*
|
||||
* @param query the query to execute in the background
|
||||
* @param transaction the transaction (can be null).
|
||||
* @return a Future object for the list result of the query
|
||||
* @see Query#findFutureList()
|
||||
*/
|
||||
@Nonnull
|
||||
<T> FutureList<T> findFutureList(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query using firstRow and maxRows.
|
||||
* <p>
|
||||
* The benefit of using this over findList() is that it provides functionality to get the
|
||||
* total row count etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* If maxRows is not set on the query prior to calling findPagedList() then a
|
||||
* PersistenceException is thrown.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Order> pagedList = Ebean.find(Order.class)
|
||||
* .setFirstRow(50)
|
||||
* .setMaxRows(20)
|
||||
* .findPagedList();
|
||||
*
|
||||
* // fetch the total row count in the background
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* List<Order> orders = pagedList.getList();
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @return The PagedList
|
||||
* @see Query#findPagedList()
|
||||
*/
|
||||
@Nonnull
|
||||
<T> PagedList<T> findPagedList(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query returning a set of entity beans.
|
||||
* <p>
|
||||
* Generally you are able to use {@link Query#findSet()} rather than
|
||||
* explicitly calling this method. You could use this method if you wish to
|
||||
* explicitly control the transaction used for the query.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Set<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* .where().ilike("name", "rob%")
|
||||
* .findSet();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T> the type of entity bean to fetch.
|
||||
* @param query the query to execute
|
||||
* @param transaction the transaction to use (can be null).
|
||||
* @return the set of fetched beans.
|
||||
* @see Query#findSet()
|
||||
*/
|
||||
@Nonnull
|
||||
<T> Set<T> findSet(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query returning the entity beans in a Map.
|
||||
* <p>
|
||||
* Generally you are able to use {@link Query#findMap()} rather than
|
||||
* explicitly calling this method. You could use this method if you wish to
|
||||
* explicitly control the transaction used for the query.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the type of entity bean to fetch.
|
||||
* @param query the query to execute.
|
||||
* @param transaction the transaction to use (can be null).
|
||||
* @return the map of fetched beans.
|
||||
* @see Query#findMap()
|
||||
*/
|
||||
@Nonnull
|
||||
<K, T> Map<K, T> findMap(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query returning a list of values for a single property.
|
||||
* <p>
|
||||
* <h3>Example 1:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* .select("name")
|
||||
* .orderBy().asc("name")
|
||||
* .findSingleAttributeList();
|
||||
*
|
||||
* }</pre>
|
||||
* <h3>Example 2:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .where().eq("status", Customer.Status.NEW)
|
||||
* .orderBy().asc("name")
|
||||
* .setMaxRows(100)
|
||||
* .findSingleAttributeList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @return the list of values for the selected property
|
||||
* @see Query#findSingleAttributeList()
|
||||
*/
|
||||
@Nonnull
|
||||
<A, T> List<A> findSingleAttributeList(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query returning at most one entity bean or null (if no matching
|
||||
* bean is found).
|
||||
* <p>
|
||||
* This will throw a NonUniqueResultException if the query finds more than one result.
|
||||
* </p>
|
||||
* <p>
|
||||
* Generally you are able to use {@link Query#findOne()} rather than
|
||||
* explicitly calling this method. You could use this method if you wish to
|
||||
* explicitly control the transaction used for the query.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the type of entity bean to fetch.
|
||||
* @param query the query to execute.
|
||||
* @param transaction the transaction to use (can be null).
|
||||
* @return the list of fetched beans.
|
||||
* @throws NonUniqueResultException if more than one result was found
|
||||
* @see Query#findOne()
|
||||
*/
|
||||
@Nullable
|
||||
<T> T findOne(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Similar to findOne() but returns an Optional (rather than nullable).
|
||||
*/
|
||||
@Nonnull
|
||||
<T> Optional<T> findOneOrEmpty(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute as a delete query deleting the 'root level' beans that match the predicates
|
||||
* in the query.
|
||||
* <p>
|
||||
* Note that if the query includes joins then the generated delete statement may not be
|
||||
* optimal depending on the database platform.
|
||||
* </p>
|
||||
*
|
||||
* @param query the query used for the delete
|
||||
* @param transaction the transaction to use (can be null)
|
||||
* @param <T> the type of entity bean to fetch.
|
||||
* @return the number of beans/rows that were deleted
|
||||
*/
|
||||
<T> int delete(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the update query returning the number of rows updated.
|
||||
* <p>
|
||||
* The update query must be created using {@link EbeanServer#update(Class)}.
|
||||
* </p>
|
||||
*
|
||||
* @param query the update query to execute
|
||||
* @param transaction the optional transaction to use for the update (can be null)
|
||||
* @param <T> the type of entity bean
|
||||
* @return The number of rows updated
|
||||
*/
|
||||
<T> int update(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the sql query returning a list of MapBean.
|
||||
* <p>
|
||||
* Generally you are able to use {@link SqlQuery#findList()} rather than
|
||||
* explicitly calling this method. You could use this method if you wish to
|
||||
* explicitly control the transaction used for the query.
|
||||
* </p>
|
||||
*
|
||||
* @param query the query to execute.
|
||||
* @param transaction the transaction to use (can be null).
|
||||
* @return the list of fetched MapBean.
|
||||
* @see SqlQuery#findList()
|
||||
*/
|
||||
@Nonnull
|
||||
List<SqlRow> findList(SqlQuery query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the SqlQuery iterating a row at a time.
|
||||
* <p>
|
||||
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
|
||||
* </p>
|
||||
*/
|
||||
void findEach(SqlQuery query, Consumer<SqlRow> consumer, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the SqlQuery iterating a row at a time with the ability to stop consuming part way through.
|
||||
* <p>
|
||||
* Returning false after processing a row stops the iteration through the query results.
|
||||
* </p>
|
||||
* <p>
|
||||
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
|
||||
* </p>
|
||||
*/
|
||||
void findEachWhile(SqlQuery query, Predicate<SqlRow> consumer, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the sql query returning a single MapBean or null.
|
||||
* <p>
|
||||
* This will throw a PersistenceException if the query found more than one
|
||||
* result.
|
||||
* </p>
|
||||
* <p>
|
||||
* Generally you are able to use {@link SqlQuery#findOne()} rather than
|
||||
* explicitly calling this method. You could use this method if you wish to
|
||||
* explicitly control the transaction used for the query.
|
||||
* </p>
|
||||
*
|
||||
* @param query the query to execute.
|
||||
* @param transaction the transaction to use (can be null).
|
||||
* @return the fetched MapBean or null if none was found.
|
||||
* @see SqlQuery#findOne()
|
||||
*/
|
||||
@Nullable
|
||||
SqlRow findOne(SqlQuery query, Transaction transaction);
|
||||
|
||||
}
|
||||
@@ -1,268 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Defines the configuration options for a "query fetch" or a
|
||||
* "lazy loading fetch". This gives you the ability to use multiple smaller
|
||||
* queries to populate an object graph as opposed to a single large query.
|
||||
* <p>
|
||||
* The primary goal is to provide efficient ways of loading complex object
|
||||
* graphs avoiding SQL Cartesian product and issues around populating object
|
||||
* graphs that have multiple *ToMany relationships.
|
||||
* </p>
|
||||
* <p>
|
||||
* It also provides the ability to control the lazy loading queries (batch size,
|
||||
* selected properties and fetches) to avoid N+1 queries etc.
|
||||
* <p>
|
||||
* There can also be cases loading across a single OneToMany where 2 SQL queries
|
||||
* using Ebean FetchConfig.query() can be more efficient than one SQL query.
|
||||
* When the "One" side is wide (lots of columns) and the cardinality difference
|
||||
* is high (a lot of "Many" beans per "One" bean) then this can be more
|
||||
* efficient loaded as 2 SQL queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
* // Normal fetch join results in a single SQL query
|
||||
* List<Order> list = Ebean.find(Order.class).fetch("details").findList();
|
||||
*
|
||||
* // Find Orders join details using a single SQL query
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL queries
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // This will use 2 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using 2 "query joins"
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("customer", new FetchConfig().queryFirst(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
|
||||
* // query 3) find customer where id in (?,?,?,?,?) // first 5 customers
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using "query joins" and partial objects
|
||||
* </p>
|
||||
* <p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .select("status, shipDate")
|
||||
* .fetch("details", "quantity, price", new FetchConfig().query())
|
||||
* .fetch("details.product", "sku, name")
|
||||
* .fetch("customer", "name", new FetchConfig().queryFirst(5))
|
||||
* .fetch("customer.contacts")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order (status, shipDate)
|
||||
* // query 2) find orderDetail (quantity, price) fetch product (sku, name) where
|
||||
* // order.id in (?,? ...)
|
||||
* // query 3) find customer (name) fetch contacts (*) fetch shippingAddress (*)
|
||||
* // where id in (?,?,?,?,?)
|
||||
*
|
||||
* // Note: the fetch of "details.product" is automatically included into the
|
||||
* // fetch of "details"
|
||||
* //
|
||||
* // Note: the fetch of "customer.contacts" and "customer.shippingAddress"
|
||||
* // are automatically included in the fetch of "customer"
|
||||
* }</pre>
|
||||
* <p>
|
||||
* You can use query() and lazy together on a single join. The query is executed
|
||||
* immediately and the lazy defines the batch size to use for further lazy
|
||||
* loading (if lazy loading is invoked).
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .fetch("customer", new FetchConfig().query(10).lazy(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find customer where id in (?,?,?,?,?,?,?,?,?,?) // first 10 customers
|
||||
* // .. then if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <p>
|
||||
* Example of controlling the lazy loading query:
|
||||
* </p>
|
||||
* <p>
|
||||
* This gives us the ability to optimise the lazy loading query for a given use
|
||||
* case.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer","name", new FetchConfig().lazy(5))
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .where().eq("status",Order.Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order where status = Order.Status.NEW
|
||||
* //
|
||||
* // .. if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @author mario
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class FetchConfig implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int lazyBatchSize = -1;
|
||||
|
||||
private int queryBatchSize = -1;
|
||||
|
||||
private boolean queryAll;
|
||||
|
||||
/**
|
||||
* Construct the fetch configuration object.
|
||||
*/
|
||||
public FetchConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this path should be lazy loaded using the default batch load
|
||||
* size.
|
||||
*/
|
||||
public FetchConfig lazy() {
|
||||
this.lazyBatchSize = 0;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this path should be lazy loaded with a specified batch size.
|
||||
*
|
||||
* @param lazyBatchSize the batch size for lazy loading
|
||||
*/
|
||||
public FetchConfig lazy(int lazyBatchSize) {
|
||||
this.lazyBatchSize = lazyBatchSize;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
* <p>
|
||||
* This will use the default batch size for separate query which is 100.
|
||||
* </p>
|
||||
*/
|
||||
public FetchConfig query() {
|
||||
this.queryBatchSize = 0;
|
||||
this.queryAll = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
* <p>
|
||||
* The queryBatchSize is the number of parent id's that this separate query
|
||||
* will load per batch.
|
||||
* </p>
|
||||
* <p>
|
||||
* This will load all beans on this path eagerly unless a {@link #lazy(int)}
|
||||
* is also used.
|
||||
* </p>
|
||||
*
|
||||
* @param queryBatchSize the batch size used to load beans on this path
|
||||
*/
|
||||
public FetchConfig query(int queryBatchSize) {
|
||||
this.queryBatchSize = queryBatchSize;
|
||||
// queryAll true as long as a lazy batch size has not already been set
|
||||
this.queryAll = (lazyBatchSize == -1);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the first batch of beans on this path.
|
||||
* This is similar to {@link #query(int)} but only fetches the first batch.
|
||||
* <p>
|
||||
* If there are more parent beans than the batch size then they will not be
|
||||
* loaded eagerly but instead use lazy loading.
|
||||
* </p>
|
||||
*
|
||||
* @param queryBatchSize the number of parent beans this path is populated for
|
||||
*/
|
||||
public FetchConfig queryFirst(int queryBatchSize) {
|
||||
this.queryBatchSize = queryBatchSize;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size for lazy loading.
|
||||
*/
|
||||
public int getLazyBatchSize() {
|
||||
return lazyBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size for separate query load.
|
||||
*/
|
||||
public int getQueryBatchSize() {
|
||||
return queryBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the query fetch should fetch 'all' rather than just the
|
||||
* 'first' batch.
|
||||
*/
|
||||
public boolean isQueryAll() {
|
||||
return queryAll;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
FetchConfig that = (FetchConfig) o;
|
||||
if (lazyBatchSize != that.lazyBatchSize) return false;
|
||||
if (queryBatchSize != that.queryBatchSize) return false;
|
||||
return queryAll == that.queryAll;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = lazyBatchSize;
|
||||
result = 92821 * result + queryBatchSize;
|
||||
result = 92821 * result + (queryAll ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides paths and properties for an object graph that can be used to control what parts of the object graph
|
||||
* is fetching (select and fetch clauses) and also can be used to control JSON marshalling (what parts of the object
|
||||
* graph are included in the JSON).
|
||||
*/
|
||||
public interface FetchPath {
|
||||
|
||||
/**
|
||||
* Return true if the path is included in this FetchPath.
|
||||
*/
|
||||
boolean hasPath(String path);
|
||||
|
||||
/**
|
||||
* Return the properties at the given path.
|
||||
*/
|
||||
Set<String> getProperties(String path);
|
||||
|
||||
/**
|
||||
* Apply the fetch path to the query.
|
||||
*/
|
||||
<T> void apply(Query<T> query);
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides support for filtering and sorting lists of entities without going
|
||||
* back to the database.
|
||||
* <p>
|
||||
* That is, it uses local in-memory sorting and filtering of a list of entity
|
||||
* beans. It is not used in a Database query or invoke a Database query.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can optionally specify a sortByClause and if so, the sort will always
|
||||
* execute prior to the filter expressions. You can specify any number of filter
|
||||
* expressions and they are effectively joined by logical "AND".
|
||||
* </p>
|
||||
* <p>
|
||||
* The result of the filter method will leave the original list unmodified and
|
||||
* return a new List instance.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // get a list of entities (query execution statistics in this case)
|
||||
*
|
||||
* List<MetaQueryStatistic> list =
|
||||
* Ebean.find(MetaQueryStatistic.class).findList();
|
||||
*
|
||||
* long nowMinus24Hrs = System.currentTimeMillis() - 24 * (1000 * 60 * 60);
|
||||
*
|
||||
* // sort and filter the list returning a filtered list...
|
||||
*
|
||||
* List<MetaQueryStatistic> filteredList =
|
||||
* Ebean.filter(MetaQueryStatistic.class)
|
||||
* .sort("avgTimeMicros desc")
|
||||
* .gt("executionCount", 0)
|
||||
* .gt("lastQueryTime", nowMinus24Hrs)
|
||||
* .eq("autoTuned", true)
|
||||
* .maxRows(10)
|
||||
* .filter(list);
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* The propertyNames can traverse the object graph (e.g. customer.name) by using
|
||||
* dot notation. If any point during the object graph traversal to get a
|
||||
* property value is null then null is returned.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // examples of property names that
|
||||
* // ... will traverse the object graph
|
||||
* // ... where customer is a property of our bean
|
||||
*
|
||||
* customer.name
|
||||
* customer.shippingAddress.city
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // get a list of entities (query execution statistics)
|
||||
*
|
||||
* List<Order> orders =
|
||||
* Ebean.find(Order.class).findList();
|
||||
*
|
||||
* // Apply a filter...
|
||||
*
|
||||
* List<Order> filteredOrders =
|
||||
* Ebean.filter(Order.class)
|
||||
* .startsWith("customer.name", "Rob")
|
||||
* .eq("customer.shippingAddress.city", "Auckland")
|
||||
* .filter(orders);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T> the entity bean type
|
||||
*/
|
||||
public interface Filter<T> {
|
||||
|
||||
/**
|
||||
* Specify a sortByClause.
|
||||
* <p>
|
||||
* The sort (if specified) will always execute first followed by the filter
|
||||
* expressions.
|
||||
* </p>
|
||||
* <p>
|
||||
* Refer to {@link Ebean#sort(List, String)} for more detail.
|
||||
* </p>
|
||||
*/
|
||||
Filter<T> sort(String sortByClause);
|
||||
|
||||
/**
|
||||
* Specify the maximum number of rows/elements to return.
|
||||
*/
|
||||
Filter<T> maxRows(int maxRows);
|
||||
|
||||
/**
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
Filter<T> eq(String prop, Object value);
|
||||
|
||||
/**
|
||||
* Not Equal To - property not equal to the given value.
|
||||
*/
|
||||
Filter<T> ne(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Case Insensitive Equal To.
|
||||
*/
|
||||
Filter<T> ieq(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
Filter<T> between(String propertyName, Object value1, Object value2);
|
||||
|
||||
/**
|
||||
* Greater Than - property greater than the given value.
|
||||
*/
|
||||
Filter<T> gt(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Greater Than or Equal to - property greater than or equal to the given
|
||||
* value.
|
||||
*/
|
||||
Filter<T> ge(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than - property less than the given value.
|
||||
*/
|
||||
Filter<T> lt(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than or Equal to - property less than or equal to the given value.
|
||||
*/
|
||||
Filter<T> le(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Is Null - property is null.
|
||||
*/
|
||||
Filter<T> isNull(String propertyName);
|
||||
|
||||
/**
|
||||
* Is Not Null - property is not null.
|
||||
*/
|
||||
Filter<T> isNotNull(String propertyName);
|
||||
|
||||
/**
|
||||
* Starts With.
|
||||
*/
|
||||
Filter<T> startsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Starts With.
|
||||
*/
|
||||
Filter<T> istartsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Ends With.
|
||||
*/
|
||||
Filter<T> endsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Ends With.
|
||||
*/
|
||||
Filter<T> iendsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Contains - property contains the string "value".
|
||||
*/
|
||||
Filter<T> contains(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Contains.
|
||||
*/
|
||||
Filter<T> icontains(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* In - property has a value contained in the set of values.
|
||||
*/
|
||||
Filter<T> in(String propertyName, Set<?> values);
|
||||
|
||||
/**
|
||||
* Apply the filter to the list returning a new list of the matching elements
|
||||
* in the sorted order.
|
||||
* <p>
|
||||
* The sourceList will remain unmodified.
|
||||
* </p>
|
||||
*
|
||||
* @return Returns a new list with the sorting and filters applied.
|
||||
*/
|
||||
List<T> filter(List<T> sourceList);
|
||||
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Intended to be used as a base class for 'Finder' implementations that can then
|
||||
* be injected or used as public static fields on the associated entity bean.
|
||||
* <p>
|
||||
* These 'finders' are a place to organise all the finder methods for that bean type
|
||||
* and specific finder methods are expected to be added (find by unique properties etc).
|
||||
* </p>
|
||||
* <h3>Testing</h3>
|
||||
* <p>
|
||||
* For testing the mocki-ebean project has the ability to replace the finder implementation
|
||||
* <p>
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* public class CustomerFinder extends Finder<Long,Customer> {
|
||||
*
|
||||
* public CustomerFinder() {
|
||||
* super(Customer.class);
|
||||
* }
|
||||
*
|
||||
* // Add your customer finder methods ...
|
||||
*
|
||||
* public Customer byName(String name) {
|
||||
* return query().eq("name", name).findOne();
|
||||
* }
|
||||
*
|
||||
* public List<Customer> findNew() {
|
||||
* return query().where()
|
||||
* .eq("status", Customer.Status.NEW)
|
||||
* .orderBy("name")
|
||||
* .findList()
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final CustomerFinder find = new CustomerFinder();
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public class Finder<I, T> {
|
||||
|
||||
/**
|
||||
* The entity bean type.
|
||||
*/
|
||||
private final Class<T> type;
|
||||
|
||||
/**
|
||||
* The name of the EbeanServer, null for the default server.
|
||||
*/
|
||||
private final String serverName;
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean.
|
||||
* <pre>{@code
|
||||
*
|
||||
* public class CustomerFinder extends Finder<Customer> {
|
||||
*
|
||||
* public CustomerFinder() {
|
||||
* super(Customer.class);
|
||||
* }
|
||||
*
|
||||
* // ... add extra customer specific finder methods
|
||||
* }
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final CustomerFinder find = new CustomerFinder();
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public Finder(Class<T> type) {
|
||||
this.type = type;
|
||||
this.serverName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean and specific server name.
|
||||
*/
|
||||
public Finder(Class<T> type, String serverName) {
|
||||
this.type = type;
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current transaction.
|
||||
*/
|
||||
public Transaction currentTransaction() {
|
||||
return db().currentTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the JDBC batch on the current transaction.
|
||||
*/
|
||||
public void flush() {
|
||||
db().flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' EbeanServer.
|
||||
* <p>
|
||||
* This provides full access to the API such as explicit transaction demarcation etc.
|
||||
*/
|
||||
public EbeanServer db() {
|
||||
return Ebean.getServer(serverName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return typically a different EbeanServer to the default.
|
||||
* <p>
|
||||
* This is equivalent to {@link Ebean#getServer(String)}
|
||||
*
|
||||
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is
|
||||
* returned.
|
||||
*/
|
||||
public EbeanServer db(String server) {
|
||||
return Ebean.getServer(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an entity reference for this ID.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
|
||||
*/
|
||||
@Nonnull
|
||||
public T ref(I id) {
|
||||
return db().getReference(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an entity by ID.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class, Object)}
|
||||
*/
|
||||
@Nullable
|
||||
public T byId(I id) {
|
||||
return db().find(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bean by Id.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#delete(Class, Object)}
|
||||
*/
|
||||
public void deleteById(I id) {
|
||||
db().delete(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all entities of the given type.
|
||||
*/
|
||||
@Nonnull
|
||||
public List<T> all() {
|
||||
return query().findList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an update query.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows =
|
||||
* finder.update()
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#update(Class)}
|
||||
*/
|
||||
public UpdateQuery<T> update() {
|
||||
return db().update(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class)}
|
||||
*/
|
||||
public Query<T> query() {
|
||||
return db().find(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a native sql query.
|
||||
*/
|
||||
public Query<T> nativeSql(String nativeSql) {
|
||||
return db().findNative(type, nativeSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query using the ORM query language.
|
||||
*/
|
||||
public Query<T> query(String ormQuery) {
|
||||
return db().createQuery(type, ormQuery);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
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();
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* FutureList represents the result of a background query execution that will
|
||||
* return a list of entities.
|
||||
* <p>
|
||||
* It extends the java.util.concurrent.Future with the ability to cancel the
|
||||
* query, check if it is finished and get the resulting list waiting for the
|
||||
* query to finish (ie. the standard features of java.util.concurrent.Future).
|
||||
* </p>
|
||||
* <p>
|
||||
* A simple example:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // create a query to find all orders
|
||||
* Query<Order> query = Ebean.find(Order.class);
|
||||
*
|
||||
* // execute the query in a background thread
|
||||
* // immediately returning the futureList
|
||||
* FutureList<Order> futureList = query.findFutureList();
|
||||
*
|
||||
* // do something else ...
|
||||
*
|
||||
* if (!futureList.isDone()){
|
||||
* // we can cancel the query execution. This will cancel
|
||||
* // the underlying query if that is supported by the JDBC
|
||||
* // driver and database
|
||||
* futureList.cancel(true);
|
||||
* }
|
||||
*
|
||||
* if (!futureList.isCancelled()){
|
||||
* // wait for the query to finish and return the list
|
||||
* List<Order> list = futureList.get();
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public interface FutureList<T> extends Future<List<T>> {
|
||||
|
||||
/**
|
||||
* Return the query that is being executed by a background thread.
|
||||
*/
|
||||
Query<T> getQuery();
|
||||
|
||||
/**
|
||||
* Same as {@link #get()} but wraps InterruptedException and ExecutionException in the
|
||||
* unchecked PersistenceException.
|
||||
*
|
||||
* @return The query list result
|
||||
* @throws PersistenceException when a InterruptedException or ExecutionException occurs.
|
||||
*/
|
||||
List<T> getUnchecked();
|
||||
|
||||
/**
|
||||
* Same as {@link #get(long, java.util.concurrent.TimeUnit)} but wraps InterruptedException
|
||||
* and ExecutionException in the unchecked PersistenceException.
|
||||
*
|
||||
* @return The query list result
|
||||
* @throws TimeoutException if the wait timed out
|
||||
* @throws PersistenceException if a InterruptedException or ExecutionException occurs.
|
||||
*/
|
||||
List<T> getUnchecked(long timeout, TimeUnit unit) throws TimeoutException;
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Represents the result of a background query execution for the total row count
|
||||
* for a query.
|
||||
* <p>
|
||||
* It extends the java.util.concurrent.Future.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the BeanType
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface FutureRowCount<T> extends Future<Integer> {
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Represents a Conjunction or a Disjunction.
|
||||
* <p>
|
||||
* Basically with a Conjunction you join together many expressions with AND, and
|
||||
* with a Disjunction you join together many expressions with OR.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note: where() always takes you to the top level WHERE expression list.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* Query q =
|
||||
* Ebean.find(Person.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .like("name", "Rob%")
|
||||
* .eq("status", Status.NEW)
|
||||
*
|
||||
* // where() returns us to the top level expression list
|
||||
* .where().gt("id", 10);
|
||||
*
|
||||
* // read as...
|
||||
* // where ( ((name like Rob%) or (status = NEW)) AND (id > 10) )
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Note: endJunction() takes you to the parent expression list
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query q =
|
||||
* Ebean.find(Person.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .like("name", "Rob%")
|
||||
* .eq("status", Status.NEW)
|
||||
* .endJunction()
|
||||
*
|
||||
* // endJunction().. takes us to the 'parent' expression list
|
||||
* // which in this case is the top level (same as where())
|
||||
*
|
||||
* .gt("id", 10);
|
||||
*
|
||||
* // read as...
|
||||
* // where ( ((name like Rob%) or (status = NEW)) AND (id > 10) )
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example of a nested disjunction.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* Query<Customer> q =
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .and()
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endAnd()
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endAnd()
|
||||
* .order().asc("name");
|
||||
*
|
||||
* q.findList();
|
||||
* String s = q.getGeneratedSql();
|
||||
*
|
||||
* // this produces an expression like:
|
||||
* ( name like ? and c.anniversary = ? ) or (c.status = ? and c.id > ? )
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public interface Junction<T> extends Expression, ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* The type of Junction used in full text expressions.
|
||||
*/
|
||||
enum Type {
|
||||
|
||||
/**
|
||||
* AND group.
|
||||
*/
|
||||
AND(" and ", "", false),
|
||||
|
||||
/**
|
||||
* OR group.
|
||||
*/
|
||||
OR(" or ", "", false),
|
||||
|
||||
/**
|
||||
* NOT group.
|
||||
*/
|
||||
NOT(" and ", "not ", false),
|
||||
|
||||
/**
|
||||
* FILTER group (for internal use only).
|
||||
*/
|
||||
FILTER("filter", "", true),
|
||||
|
||||
/**
|
||||
* Text search AND group.
|
||||
*/
|
||||
MUST("must", "", true),
|
||||
|
||||
/**
|
||||
* Text search NOT group.
|
||||
*/
|
||||
MUST_NOT("must_not", "", true),
|
||||
|
||||
/**
|
||||
* Text search OR group.
|
||||
*/
|
||||
SHOULD("should", "", true);
|
||||
|
||||
private String prefix;
|
||||
private String literal;
|
||||
private boolean text;
|
||||
|
||||
Type(String literal, String prefix, boolean text) {
|
||||
this.literal = literal;
|
||||
this.prefix = prefix;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the literal value for this type.
|
||||
*/
|
||||
public String literal() {
|
||||
return literal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the prefix value for this type.
|
||||
*/
|
||||
public String prefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a text type.
|
||||
*/
|
||||
public boolean isText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Used to specify the type of like matching used.
|
||||
*/
|
||||
public enum LikeType {
|
||||
|
||||
/**
|
||||
* You need to put in your own wildcards - no escaping is performed.
|
||||
*/
|
||||
RAW,
|
||||
|
||||
/**
|
||||
* The % wildcard is added to the end of the search word and search word is escaped.
|
||||
*/
|
||||
STARTS_WITH,
|
||||
|
||||
/**
|
||||
* The % wildcard is added to the beginning of the search word and search word is escaped.
|
||||
*/
|
||||
ENDS_WITH,
|
||||
|
||||
/**
|
||||
* The % wildcard is added to the beginning and end of the search word and search word is escaped.
|
||||
*/
|
||||
CONTAINS,
|
||||
|
||||
/**
|
||||
* Uses equal to rather than a LIKE with wildcards.
|
||||
* <p>
|
||||
* This is mainly here to be available for use with ExampleExpression.
|
||||
* </p>
|
||||
*/
|
||||
EQUAL_TO
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Options used to control a merge. Use MergeOptionsBuilder to create an instance.
|
||||
* <p>
|
||||
* Instances of MergeOptions are thread safe and safe to share across threads.
|
||||
*/
|
||||
public interface MergeOptions {
|
||||
|
||||
/**
|
||||
* Returns true if Id values are supplied by the client.
|
||||
* <p>
|
||||
* This would be the case when for example a mobile creates data in it's own local database
|
||||
* and then sync's. In this case often the id values are UUID.
|
||||
*/
|
||||
boolean isClientGeneratedIds();
|
||||
|
||||
/**
|
||||
* Return true if delete permanent should be used and false for 'normal' delete that allows soft deletes.
|
||||
*/
|
||||
boolean isDeletePermanent();
|
||||
|
||||
/**
|
||||
* Return the paths included in the merge.
|
||||
*/
|
||||
Set<String> paths();
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Builds a MergeOptions which is immutable and thread safe.
|
||||
*/
|
||||
public class MergeOptionsBuilder {
|
||||
|
||||
private static final MOptions DEFAULT_OPTIONS = new MOptions();
|
||||
|
||||
private Set<String> paths = new LinkedHashSet<>();
|
||||
|
||||
private boolean clientGeneratedIds;
|
||||
|
||||
private boolean deletePermanent;
|
||||
|
||||
/**
|
||||
* Return the default options.
|
||||
*/
|
||||
public static MergeOptions defaultOptions() {
|
||||
return DEFAULT_OPTIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a path that will included in the merge.
|
||||
*
|
||||
* @param path The path relative to the root type.
|
||||
* @return The builder to chain another addPath() or build().
|
||||
*/
|
||||
public MergeOptionsBuilder addPath(String path) {
|
||||
paths.add(path);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if Id values are supplied by the client.
|
||||
* <p>
|
||||
* This would be the case when for example a mobile creates data in it's own local database
|
||||
* and then sync's. In this case often the id values are UUID.
|
||||
*/
|
||||
public MergeOptionsBuilder setClientGeneratedIds() {
|
||||
this.clientGeneratedIds = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set that deletions should use delete permanent (rather than default which allows soft deletes).
|
||||
*/
|
||||
public MergeOptionsBuilder setDeletePermanent() {
|
||||
this.deletePermanent = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and return the MergeOptions instance.
|
||||
*/
|
||||
public MergeOptions build() {
|
||||
return new MOptions(paths, clientGeneratedIds, deletePermanent);
|
||||
}
|
||||
|
||||
private static class MOptions implements MergeOptions {
|
||||
|
||||
private final boolean clientGeneratedIds;
|
||||
private final boolean deletePermanent;
|
||||
private final Set<String> paths;
|
||||
|
||||
private MOptions(){
|
||||
this.clientGeneratedIds = false;
|
||||
this.paths = new LinkedHashSet<>();
|
||||
this.deletePermanent = false;
|
||||
}
|
||||
|
||||
private MOptions(Set<String> paths, boolean clientGeneratedIds, boolean deletePermanent) {
|
||||
this.paths = paths;
|
||||
this.clientGeneratedIds = clientGeneratedIds;
|
||||
this.deletePermanent = deletePermanent;
|
||||
}
|
||||
|
||||
public Set<String> paths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClientGeneratedIds() {
|
||||
return clientGeneratedIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeletePermanent() {
|
||||
return deletePermanent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,286 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
/**
|
||||
* A MappedSuperclass base class that provides convenience methods for inserting, updating and
|
||||
* deleting beans.
|
||||
* <p>
|
||||
* By having your entity beans extend this it provides a 'Active Record' style programming model for
|
||||
* Ebean users.
|
||||
* <p>
|
||||
* Note that there is a ebean-mocker project that enables you to use Mockito or similar
|
||||
* tools to still mock out the underlying 'default EbeanServer' for testing purposes.
|
||||
* <p>
|
||||
* You may choose not use this Model mapped superclass if you don't like the 'Active Record' style
|
||||
* or if you believe it 'pollutes' your entity beans.
|
||||
* <p>
|
||||
* You can use Dependency Injection like Guice or Spring to construct and wire a EbeanServer instance
|
||||
* and have that same instance used with this Model and Finder. The way that works is that when the
|
||||
* DI container creates the EbeanServer instance it can be registered with the Ebean singleton. In this
|
||||
* way the EbeanServer instance can be injected as per normal Guice / Spring dependency injection and
|
||||
* that same instance also used to support the Model and Finder active record style.
|
||||
* <p>
|
||||
* If you choose to use the Model mapped superclass you will probably also chose to additionally add
|
||||
* a {@link Finder} as a public static field to complete the active record pattern and provide a
|
||||
* relatively nice clean way to write queries.
|
||||
* <p>
|
||||
* <h3>Typical common @MappedSuperclass</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Typically there is a common base model that has some
|
||||
* // common properties like the ones below
|
||||
*
|
||||
* @MappedSuperclass
|
||||
* public class BaseModel extends Model {
|
||||
*
|
||||
* @Id Long id;
|
||||
*
|
||||
* @Version Long version;
|
||||
*
|
||||
* @WhenCreated Timestamp whenCreated;
|
||||
*
|
||||
* @WhenUpdated Timestamp whenUpdated;
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Extend the Model</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Extend the mappedSuperclass
|
||||
*
|
||||
* @Entity @Table(name="o_account")
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* String name;
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Modal: save()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Active record style ... save(), delete() etc
|
||||
* Customer customer = new Customer();
|
||||
* customer.setName("AC234");
|
||||
*
|
||||
* // save() method inherited from Model
|
||||
* customer.save();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public abstract class Model {
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' EbeanServer.
|
||||
* <p>
|
||||
* This provides full access to the API such as explicit transaction demarcation etc.
|
||||
* <p>
|
||||
* Example:
|
||||
* <pre>{@code
|
||||
*
|
||||
* Transaction transaction = Customer.db().beginTransaction();
|
||||
* try {
|
||||
*
|
||||
* // turn off cascade persist for this transaction
|
||||
* transaction.setPersistCascade(false);
|
||||
*
|
||||
* // extra control over jdbc batching for this transaction
|
||||
* transaction.setBatchGetGeneratedKeys(false);
|
||||
* transaction.setBatchMode(true);
|
||||
* transaction.setBatchSize(20);
|
||||
*
|
||||
* Customer customer = new Customer();
|
||||
* customer.setName("Roberto");
|
||||
* customer.save();
|
||||
*
|
||||
* Customer otherCustomer = new Customer();
|
||||
* otherCustomer.setName("Franko");
|
||||
* otherCustomer.save();
|
||||
*
|
||||
* transaction.commit();
|
||||
*
|
||||
* } finally {
|
||||
* transaction.end();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static EbeanServer db() {
|
||||
return Ebean.getDefaultServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a named EbeanServer that is typically different to the default server.
|
||||
* <p>
|
||||
* If you are using multiple databases then each database has a name and maps to a single
|
||||
* EbeanServer. You can use this method to get an EbeanServer for another database.
|
||||
*
|
||||
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is returned.
|
||||
*/
|
||||
public static EbeanServer db(String server) {
|
||||
return Ebean.getServer(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the entity bean as dirty.
|
||||
* <p>
|
||||
* This is used so that when a bean that is otherwise unmodified is updated the version
|
||||
* property is updated.
|
||||
* <p>
|
||||
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
|
||||
* dirty so that it is not skipped.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer = Customer.find.byId(id);
|
||||
*
|
||||
* // mark the bean as dirty so that a save() or update() will
|
||||
* // increment the version property
|
||||
* customer.markAsDirty();
|
||||
* customer.save();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see EbeanServer#markAsDirty(Object)
|
||||
*/
|
||||
public void markAsDirty() {
|
||||
db().markAsDirty(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the property as unset or 'not loaded'.
|
||||
* <p>
|
||||
* This would be used to specify a property that we did not wish to include in a stateless update.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // populate an entity bean from JSON or whatever
|
||||
* User user = ...;
|
||||
*
|
||||
* // mark the email property as 'unset' so that it is not
|
||||
* // included in a 'stateless update'
|
||||
* user.markPropertyUnset("email");
|
||||
*
|
||||
* user.update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyName the name of the property on the bean to be marked as 'unset'
|
||||
*/
|
||||
public void markPropertyUnset(String propertyName) {
|
||||
((EntityBean) this)._ebean_getIntercept().setPropertyLoaded(propertyName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert or update this entity depending on its state.
|
||||
* <p>
|
||||
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
|
||||
* insert or an update based on that.
|
||||
*
|
||||
* @see EbeanServer#save(Object)
|
||||
*/
|
||||
public void save() {
|
||||
db().save(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush any batched changes to the database.
|
||||
* <p>
|
||||
* When using JDBC batch flushing occurs automatically at commit() time or when the batch size
|
||||
* is reached. This provides the ability to manually flush the batch.
|
||||
* </p>
|
||||
*/
|
||||
public void flush() {
|
||||
db().flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this entity.
|
||||
*
|
||||
* @see EbeanServer#update(Object)
|
||||
*/
|
||||
public void update() {
|
||||
db().update(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert this entity.
|
||||
*
|
||||
* @see EbeanServer#insert(Object)
|
||||
*/
|
||||
public void insert() {
|
||||
db().insert(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete this bean.
|
||||
* <p>
|
||||
* This will return true if the bean was deleted successfully or JDBC batch is being used.
|
||||
* </p>
|
||||
* <p>
|
||||
* If there is no current transaction one will be created and committed for
|
||||
* you automatically.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the Bean does not have a version property (or loaded version property) and
|
||||
* the bean does not exist then this returns false indicating that nothing was
|
||||
* deleted. Note that, if JDBC batch mode is used then this always returns true.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#delete(Object)
|
||||
*/
|
||||
public boolean delete() {
|
||||
return db().delete(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bean permanently without soft delete.
|
||||
* <p>
|
||||
* This is used when the bean contains a <code>@SoftDelete</code> property and we
|
||||
* want to perform a hard/permanent delete.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#deletePermanent(Object)
|
||||
*/
|
||||
public boolean deletePermanent() {
|
||||
return db().deletePermanent(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an update using this entity against the specified server.
|
||||
*/
|
||||
public void update(String server) {
|
||||
db(server).update(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an insert using this entity against the specified server.
|
||||
*/
|
||||
public void insert(String server) {
|
||||
db(server).insert(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a delete using this entity against the specified server.
|
||||
*/
|
||||
public boolean delete(String server) {
|
||||
return db(server).delete(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes this entity from the database.
|
||||
*
|
||||
* @see EbeanServer#refresh(Object)
|
||||
*/
|
||||
public void refresh() {
|
||||
db().refresh(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,416 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents an Order By for a Query.
|
||||
* <p>
|
||||
* Is a ordered list of OrderBy.Property objects each specifying a property and
|
||||
* whether it is ascending or descending order.
|
||||
* </p>
|
||||
* <p>
|
||||
* Typically you will not construct an OrderBy yourself but use one that exists
|
||||
* on the Query object.
|
||||
* </p>
|
||||
*/
|
||||
public final class OrderBy<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 9157089257745730539L;
|
||||
|
||||
private transient Query<T> query;
|
||||
|
||||
private final List<Property> list;
|
||||
|
||||
/**
|
||||
* Create an empty OrderBy with no associated query.
|
||||
*/
|
||||
public OrderBy() {
|
||||
this.list = new ArrayList<>(3);
|
||||
}
|
||||
|
||||
private OrderBy(List<Property> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an orderBy parsing the order by clause.
|
||||
* <p>
|
||||
* The order by clause follows SQL order by clause with comma's between each
|
||||
* property and optionally "asc" or "desc" to represent ascending or
|
||||
* descending order respectively.
|
||||
* </p>
|
||||
*/
|
||||
public OrderBy(String orderByClause) {
|
||||
this(null, orderByClause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a given query and order by clause.
|
||||
*/
|
||||
public OrderBy(Query<T> query, String orderByClause) {
|
||||
this.query = query;
|
||||
this.list = new ArrayList<>(3);
|
||||
parse(orderByClause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the ascending/descending order on all the properties.
|
||||
*/
|
||||
public void reverse() {
|
||||
for (Property aList : list) {
|
||||
aList.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property with ascending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> asc(String propertyName) {
|
||||
|
||||
list.add(new Property(propertyName, true));
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property with descending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> desc(String propertyName) {
|
||||
|
||||
list.add(new Property(propertyName, false));
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the property is known to be contained in the order by clause.
|
||||
*/
|
||||
public boolean containsProperty(String propertyName) {
|
||||
|
||||
for (Property aList : list) {
|
||||
if (propertyName.equals(aList.getProperty())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this OrderBy with the path trimmed.
|
||||
*/
|
||||
public OrderBy<T> copyWithTrim(String path) {
|
||||
List<Property> newList = new ArrayList<>(list.size());
|
||||
for (Property aList : list) {
|
||||
newList.add(aList.copyWithTrim(path));
|
||||
}
|
||||
return new OrderBy<>(newList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties for this OrderBy.
|
||||
*/
|
||||
public List<Property> getProperties() {
|
||||
// not returning an Immutable list at this point
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this OrderBy does not have any properties.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated query if there is one.
|
||||
*/
|
||||
public Query<T> getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate this OrderBy with a query.
|
||||
*/
|
||||
public void setQuery(Query<T> query) {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of the OrderBy.
|
||||
*/
|
||||
public OrderBy<T> copy() {
|
||||
|
||||
OrderBy<T> copy = new OrderBy<>();
|
||||
for (Property aList : list) {
|
||||
copy.add(aList.copy());
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the order by by parsing a raw expression.
|
||||
*/
|
||||
public void add(String rawExpression) {
|
||||
parse(rawExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property to the order by.
|
||||
*/
|
||||
public void add(Property p) {
|
||||
list.add(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return list.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the OrderBy in string format.
|
||||
*/
|
||||
public String toStringFormat() {
|
||||
if (list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Property property = list.get(i);
|
||||
if (i > 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(property.toStringFormat());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof OrderBy<?>)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OrderBy<?> e = (OrderBy<?>) obj;
|
||||
return e.list.equals(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash value for this OrderBy. This can be to determine logical
|
||||
* equality for OrderBy clauses.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return list.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the orderBy removing any current order by properties.
|
||||
* <p>
|
||||
* This is intended to be used when some code creates a query with a
|
||||
* 'default' order by clause and some other code may clear the 'default'
|
||||
* order by clause and replace.
|
||||
* </p>
|
||||
*/
|
||||
public OrderBy<T> clear() {
|
||||
list.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A property and its ascending descending order.
|
||||
*/
|
||||
public static final class Property implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1546009780322478077L;
|
||||
|
||||
private String property;
|
||||
|
||||
private boolean ascending;
|
||||
|
||||
private String nulls;
|
||||
|
||||
private String highLow;
|
||||
|
||||
public Property(String property, boolean ascending) {
|
||||
this.property = property;
|
||||
this.ascending = ascending;
|
||||
}
|
||||
|
||||
public Property(String property, boolean ascending, String nulls, String highLow) {
|
||||
this.property = property;
|
||||
this.ascending = ascending;
|
||||
this.nulls = nulls;
|
||||
this.highLow = highLow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this Property with the path trimmed.
|
||||
*/
|
||||
public Property copyWithTrim(String path) {
|
||||
return new Property(property.substring(path.length() + 1), ascending, nulls, highLow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc = property.hashCode();
|
||||
hc = hc * 92821 + (ascending ? 0 : 1);
|
||||
hc = hc * 92821 + (nulls == null ? 0 : nulls.hashCode());
|
||||
hc = hc * 92821 + (highLow == null ? 0 : highLow.hashCode());
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Property)) {
|
||||
return false;
|
||||
}
|
||||
Property e = (Property) obj;
|
||||
if (ascending != e.ascending) return false;
|
||||
if (!property.equals(e.property)) return false;
|
||||
if (nulls != null ? !nulls.equals(e.nulls) : e.nulls != null) return false;
|
||||
return highLow != null ? highLow.equals(e.highLow) : e.highLow == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toStringFormat();
|
||||
}
|
||||
|
||||
public String toStringFormat() {
|
||||
if (nulls == null) {
|
||||
if (ascending) {
|
||||
return property;
|
||||
} else {
|
||||
return property + " desc";
|
||||
}
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(property);
|
||||
if (!ascending) {
|
||||
sb.append(" ").append("desc");
|
||||
}
|
||||
sb.append(" ").append(nulls).append(" ").append(highLow);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the ascending/descending order for this property.
|
||||
*/
|
||||
public void reverse() {
|
||||
this.ascending = !ascending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim off the pathPrefix.
|
||||
*/
|
||||
public void trim(String pathPrefix) {
|
||||
property = property.substring(pathPrefix.length() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this property.
|
||||
*/
|
||||
public Property copy() {
|
||||
return new Property(property, ascending, nulls, highLow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property name.
|
||||
*/
|
||||
public String getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the property name.
|
||||
*/
|
||||
public void setProperty(String property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the order is ascending.
|
||||
*/
|
||||
public boolean isAscending() {
|
||||
return ascending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the order is ascending.
|
||||
*/
|
||||
public void setAscending(boolean ascending) {
|
||||
this.ascending = ascending;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void parse(String orderByClause) {
|
||||
|
||||
if (orderByClause == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] chunks = orderByClause.split(",");
|
||||
for (String chunk : chunks) {
|
||||
String[] pairs = chunk.split(" ");
|
||||
Property p = parseProperty(pairs);
|
||||
if (p != null) {
|
||||
list.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Property parseProperty(String[] pairs) {
|
||||
if (pairs.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<String> wordList = new ArrayList<>(pairs.length);
|
||||
for (String pair : pairs) {
|
||||
if (!isEmptyString(pair)) {
|
||||
wordList.add(pair);
|
||||
}
|
||||
}
|
||||
if (wordList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (wordList.size() == 1) {
|
||||
return new Property(wordList.get(0), true);
|
||||
}
|
||||
if (wordList.size() == 2) {
|
||||
boolean asc = isAscending(wordList.get(1));
|
||||
return new Property(wordList.get(0), asc);
|
||||
}
|
||||
if (wordList.size() == 4) {
|
||||
// nulls high or nulls low as 3rd and 4th
|
||||
boolean asc = isAscending(wordList.get(1));
|
||||
return new Property(wordList.get(0), asc, wordList.get(2), wordList.get(3));
|
||||
}
|
||||
String m = "Expecting a 1, 2 or 4 words in [" + Arrays.toString(pairs) + "] but got " + wordList;
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
|
||||
private boolean isAscending(String s) {
|
||||
s = s.toLowerCase();
|
||||
if (s.startsWith("asc")) {
|
||||
return true;
|
||||
}
|
||||
if (s.startsWith("desc")) {
|
||||
return false;
|
||||
}
|
||||
String m = "Expecting [" + s + "] to be asc or desc?";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
|
||||
private boolean isEmptyString(String s) {
|
||||
return s == null || s.isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Represents a page of results.
|
||||
* <p>
|
||||
* The benefit of using PagedList over just using the normal Query with
|
||||
* {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} is that it additionally wraps
|
||||
* functionality that can call {@link Query#findFutureCount()} to determine total row count,
|
||||
* total page count etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* Internally this works using {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} on
|
||||
* the query. This translates into SQL that uses limit offset, rownum or row_number function to
|
||||
* limit the result set.
|
||||
* </p>
|
||||
* <p>
|
||||
* <h4>Example: typical use including total row count</h4>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // We want to find the first 50 new orders
|
||||
* // ... so we don't really need setFirstRow(0)
|
||||
*
|
||||
* PagedList<Order> pagedList
|
||||
* = ebeanServer.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .setFirstRow(0)
|
||||
* .setMaxRows(50)
|
||||
* .findPagedList();
|
||||
*
|
||||
* // Optional: initiate the loading of the total
|
||||
* // row count in a background thread
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // get the total row count (from the future)
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h4>Example: No total row count required</h4>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // If you are not getting the 'first page' often
|
||||
* // you do not bother getting the total row count again
|
||||
* // so instead just get the page list of data
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T> the entity bean type
|
||||
* @see Query#findPagedList()
|
||||
*/
|
||||
public interface PagedList<T> {
|
||||
|
||||
/**
|
||||
* Initiate the loading of the total row count in the background.
|
||||
* <pre>{@code
|
||||
*
|
||||
* // initiate the loading of the total row count
|
||||
* // in a background thread
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // get the total row count (from the future)
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Also note that using loadRowCount() and getTotalRowCount() rather than getFutureRowCount()
|
||||
* means that exceptions ExecutionException, InterruptedException, TimeoutException are instead
|
||||
* wrapped in the unchecked PersistenceException (which might be preferrable).
|
||||
* </p>
|
||||
*/
|
||||
void loadCount();
|
||||
|
||||
/**
|
||||
* Return the Future row count. You might get this if you wish to cancel the total row count query
|
||||
* or specify a timeout for the row count query.
|
||||
* <p>
|
||||
* The loadRowCount() & getTotalRowCount() methods internally make use of this getFutureRowCount() method.
|
||||
* Generally I expect people to prefer loadRowCount() & getTotalRowCount() over getFutureRowCount().
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // initiate the row count query in the background thread
|
||||
* Future<Integer> rowCount = pagedList.getFutureRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // now get the total count with a timeout
|
||||
* Integer totalRowCount = rowCount.get(30, TimeUnit.SECONDS);
|
||||
*
|
||||
* // or ge the total count without a timeout
|
||||
* Integer totalRowCountViaFuture = rowCount.get();
|
||||
*
|
||||
* // which is actually the same as ...
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Nonnull
|
||||
Future<Integer> getFutureCount();
|
||||
|
||||
/**
|
||||
* Return the list of entities for this page.
|
||||
*/
|
||||
@Nonnull
|
||||
List<T> getList();
|
||||
|
||||
/**
|
||||
* Return the total row count for all pages.
|
||||
* <p>
|
||||
* If loadRowCount() has already been called then the row count query is already executing in a background thread
|
||||
* and this gets the associated Future and gets the value waiting for the future to finish.
|
||||
* </p>
|
||||
* <p>
|
||||
* If loadRowCount() has not been called then this executes the find row count query and returns the result and this
|
||||
* will just occur in the current thread and not use a background thread.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Optional: initiate the loading of the total
|
||||
* // row count in a background thread
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // get the total row count (which was being executed
|
||||
* // in a background thread if loadRowCount() was used)
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
int getTotalCount();
|
||||
|
||||
/**
|
||||
* Return the total number of pages based on the page size and total row count.
|
||||
* <p>
|
||||
* This method requires that the total row count has been fetched and will invoke
|
||||
* the total row count query if it has not already been invoked.
|
||||
* </p>
|
||||
*/
|
||||
int getTotalPageCount();
|
||||
|
||||
/**
|
||||
* Return the page size used for this query. This is the same value as maxRows used by the query.
|
||||
*/
|
||||
int getPageSize();
|
||||
|
||||
/**
|
||||
* Return the index position of this page (Zero based).
|
||||
* <p>
|
||||
* This is a calculated value based on firstRow/maxRows.
|
||||
* </p>
|
||||
*/
|
||||
int getPageIndex();
|
||||
|
||||
/**
|
||||
* Return true if there is a next page.
|
||||
* <p>
|
||||
* This method requires that the total row count has been fetched and will invoke
|
||||
* the total row count query if it has not already been invoked.
|
||||
* </p>
|
||||
*/
|
||||
boolean hasNext();
|
||||
|
||||
/**
|
||||
* Return true if there is a previous page.
|
||||
*/
|
||||
boolean hasPrev();
|
||||
|
||||
/**
|
||||
* Helper method to return a "X to Y of Z" string for this page where X is the first row, Y the
|
||||
* last row and Z the total row count.
|
||||
* <p>
|
||||
* This method requires that the total row count has been fetched and will invoke
|
||||
* the total row count query if it has not already been invoked.
|
||||
* </p>
|
||||
*
|
||||
* @param to String to put between the first and last row
|
||||
* @param of String to put between the last row and the total row count
|
||||
* @return String of the format XtoYofZ.
|
||||
*/
|
||||
String getDisplayXtoYofZ(String to, String of);
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Holds a list of value object pairs.
|
||||
* <p>
|
||||
* This feature is to enable use of L2 cache with complex natural keys with findList() queries in cases where the
|
||||
* IN clause is not a single property but instead a pair of properties.
|
||||
* </p>
|
||||
* <p>
|
||||
* These queries can have predicates that can be translated into a list of complex natural keys such that the L2
|
||||
* cache can be hit with these keys to obtain some or all of the beans from L2 cache rather than the DB.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // where a bean is annotated with a complex
|
||||
* // natural key made of several properties
|
||||
* @Cache(naturalKey = {"store","code","sku"})
|
||||
*
|
||||
*
|
||||
* Pairs pairs = new Pairs("sku", "code");
|
||||
* pairs.add("sj2", 1000);
|
||||
* pairs.add("sj2", 1001);
|
||||
* pairs.add("pf3", 1000);
|
||||
*
|
||||
* List<OCachedNatKeyBean3> list = Ebean.find(OCachedNatKeyBean3.class)
|
||||
* .where()
|
||||
* .eq("store", "def")
|
||||
* .inPairs(pairs) // IN clause with 'pairs' of values
|
||||
* .orderBy("sku desc")
|
||||
*
|
||||
* // query expressions cover the natural key properties
|
||||
* // so we can choose to hit the L2 bean cache if we want
|
||||
* .setUseCache(true)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
* <h3>Important implementation Note</h3>
|
||||
* <p>
|
||||
* When binding many pairs of values we want to be able to utilise a DB index (as this type of query usually means the
|
||||
* pairs are a unique key/index or part of a unique key/index and highly selective). Currently we know we can do this
|
||||
* on any DB that supports expression/formula based indexes.
|
||||
* using a DB string concatenation formula
|
||||
* </p>
|
||||
* <p>
|
||||
* This means, the implementation converts the list of pairs into a list of strings via concatenation and we use a
|
||||
* DB concatenation formula to match. We see SQL like:
|
||||
* </p>
|
||||
* <pre>{@code sql
|
||||
*
|
||||
* ...
|
||||
* where t0.store = ? and (t0.sku||'-'||t0.code) in (?, ? )
|
||||
*
|
||||
* // bind values like: "sj2-1000", "pf3-1000"
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* We often create a DB expression index to match the DB concat formula like:
|
||||
* </p>
|
||||
* <pre>{@code sql
|
||||
*
|
||||
* create index ix_name on table_name ((sku || '-' || code));
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public class Pairs {
|
||||
|
||||
private final String property0;
|
||||
private final String property1;
|
||||
|
||||
private final List<Entry> entries = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Character between the values when combined via DB varchar concatenation.
|
||||
*/
|
||||
private String concatSeparator = "-";
|
||||
|
||||
/**
|
||||
* Optional suffix added to DB varchar concatenation formula.
|
||||
*/
|
||||
private String concatSuffix;
|
||||
|
||||
/**
|
||||
* Create with 2 property names.
|
||||
*
|
||||
* @param property0 The property of the first value
|
||||
* @param property1 The property of the second value
|
||||
*/
|
||||
public Pairs(String property0, String property1) {
|
||||
this.property0 = property0;
|
||||
this.property1 = property1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a pair of value objects.
|
||||
* <p>
|
||||
* Both values are expected to be immutable with equals and hashCode implementations.
|
||||
* </p>
|
||||
*
|
||||
* @param a Value of the first property
|
||||
* @param b Value of the second property
|
||||
*/
|
||||
public Pairs add(Object a, Object b) {
|
||||
entries.add(new Entry(a, b));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first property name.
|
||||
*/
|
||||
public String getProperty0() {
|
||||
return property0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the second property name.
|
||||
*/
|
||||
public String getProperty1() {
|
||||
return property1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the value pairs.
|
||||
*/
|
||||
public List<Entry> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the separator character used with DB varchar concatenation to combine the 2 values.
|
||||
*/
|
||||
public String getConcatSeparator() {
|
||||
return concatSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the separator character used with DB varchar concatenation to combine the 2 values.
|
||||
*/
|
||||
public Pairs setConcatSeparator(String concatSeparator) {
|
||||
this.concatSeparator = concatSeparator;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a suffix used with DB varchar concatenation to combine the 2 values.
|
||||
*/
|
||||
public String getConcatSuffix() {
|
||||
return concatSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a suffix used with DB varchar concatenation to combine the 2 values.
|
||||
*/
|
||||
public Pairs setConcatSuffix(String concatSuffix) {
|
||||
this.concatSuffix = concatSuffix;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "p0:" + property0 + " p1:" + property1 + " entries:" + entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* A pair of 2 value objects.
|
||||
* <p>
|
||||
* Used to support inPairs() expression.
|
||||
*/
|
||||
public static class Entry {
|
||||
|
||||
private final Object a;
|
||||
private final Object b;
|
||||
|
||||
/**
|
||||
* Create with values for property0 and property1 respectively.
|
||||
*
|
||||
* @param a Value of the first property
|
||||
* @param b Value of the second property
|
||||
*/
|
||||
public Entry(Object a, Object b) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + a + "," + b + "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value for the first property.
|
||||
*/
|
||||
public Object getA() {
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value for the second property.
|
||||
*/
|
||||
public Object getB() {
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Entry that = (Entry) o;
|
||||
return a.equals(that.a) && b.equals(that.b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = a.hashCode();
|
||||
result = 92821 * result + b.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Defines the scope for PersistenceContext.
|
||||
* <p/>
|
||||
* Ebean has traditionally used Transaction scope for the PersistenceContext. This is used to change the scope to
|
||||
* use (by default) and explicitly set the scope to use for an individual query.
|
||||
*
|
||||
* @see io.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)
|
||||
* @see Query#setPersistenceContextScope(PersistenceContextScope)
|
||||
*/
|
||||
public enum PersistenceContextScope {
|
||||
|
||||
/**
|
||||
* PersistenceContext is scoped to the transaction.
|
||||
* <p/>
|
||||
* If a transaction spans 2 or more queries that fetch the same bean in terms of same type
|
||||
* and same Id value then they share the same bean instance.
|
||||
* <p/>
|
||||
* You may want to change to use QUERY scope when you want a query executing in a transaction to effectively
|
||||
* ignore beans that have already been loaded (by other queries in the same transaction) and instead get a
|
||||
* 'fresh copy' of the bean.
|
||||
*/
|
||||
TRANSACTION,
|
||||
|
||||
/**
|
||||
* PersistenceContext is scoped to the query.
|
||||
* <p/>
|
||||
* This means that for this query running in an existing transaction then it will effectively ignore any beans
|
||||
* that have already been queried/loaded by prior queries in the same transaction.
|
||||
* <p/>
|
||||
* You may use QUERY scope on a query that is executed in a transaction and you want to get a 'fresh copy' of the bean.
|
||||
*/
|
||||
QUERY
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
/**
|
||||
* Captures and wraps IOException's occurring during ElasticSearch processing etc.
|
||||
*/
|
||||
public class PersistenceIOException extends PersistenceException {
|
||||
|
||||
private static final long serialVersionUID = -7630050437148176148L;
|
||||
|
||||
public PersistenceIOException(String msg, Exception cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
public PersistenceIOException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.config.properties.PropertiesLoader;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Provides singleton state for the default server.
|
||||
* <p/>
|
||||
* Intended for internal use as part of bootup, construction, registration of the default server.
|
||||
*/
|
||||
class PrimaryServer {
|
||||
|
||||
private static Properties globalProperties;
|
||||
|
||||
private static String defaultServerName;
|
||||
|
||||
private static boolean skip;
|
||||
|
||||
/**
|
||||
* Set whether to skip automatically creating the primary server.
|
||||
*/
|
||||
static synchronized void setSkip(boolean skip) {
|
||||
PrimaryServer.skip = skip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true to skip automatically creating the primary server.
|
||||
*/
|
||||
static synchronized boolean isSkip() {
|
||||
return skip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default server name.
|
||||
*/
|
||||
static synchronized String getDefaultServerName() {
|
||||
getProperties();
|
||||
return defaultServerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default configuration Properties.
|
||||
*/
|
||||
static synchronized Properties getProperties() {
|
||||
if (globalProperties == null) {
|
||||
globalProperties = PropertiesLoader.load();
|
||||
}
|
||||
if (defaultServerName == null) {
|
||||
defaultServerName = determineDefaultServerName();
|
||||
}
|
||||
return globalProperties;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine and return the default server name checking system environment variables and then global properties.
|
||||
*/
|
||||
private static String determineDefaultServerName() {
|
||||
|
||||
String defaultServerName = System.getenv("EBEAN_DB");
|
||||
defaultServerName = System.getProperty("db", defaultServerName);
|
||||
defaultServerName = System.getProperty("ebean_db", defaultServerName);
|
||||
if (isEmpty(defaultServerName)) {
|
||||
defaultServerName = System.getProperty("datasource.default");
|
||||
if (isEmpty(defaultServerName)) {
|
||||
defaultServerName = System.getProperty("ebean.default.datasource");
|
||||
if (isEmpty(defaultServerName)) {
|
||||
defaultServerName = globalProperties.getProperty("datasource.default");
|
||||
if (isEmpty(defaultServerName)) {
|
||||
defaultServerName = globalProperties.getProperty("ebean.default.datasource");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (defaultServerName == null) {
|
||||
defaultServerName = "db";
|
||||
}
|
||||
return defaultServerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the string is null or empty.
|
||||
*/
|
||||
private static boolean isEmpty(String value) {
|
||||
return value == null || value.trim().isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* A location for profiling transactions and queries.
|
||||
* <p>
|
||||
* Typically represents a class method in the form of class file and line of code that started
|
||||
* the transaction or invoked the query.
|
||||
* </p>
|
||||
*/
|
||||
public interface ProfileLocation {
|
||||
|
||||
/**
|
||||
* Create and return a new ProfileLocation.
|
||||
*/
|
||||
static ProfileLocation create() {
|
||||
return XServiceProvider.profileLocationFactory().create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new ProfileLocation with a given lineNumber and label.
|
||||
*/
|
||||
static ProfileLocation create(int lineNumber, String label) {
|
||||
return XServiceProvider.profileLocationFactory().create(lineNumber, label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new ProfileLocation with a given location.
|
||||
*/
|
||||
static ProfileLocation createAt(String location) {
|
||||
return XServiceProvider.profileLocationFactory().createAt(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the location description.
|
||||
*/
|
||||
String obtain();
|
||||
|
||||
/**
|
||||
* Return a short version of the location description.
|
||||
*/
|
||||
String shortDescription();
|
||||
|
||||
/**
|
||||
* Add execution time.
|
||||
*/
|
||||
void add(long executionTime);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,84 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Used to provide iteration over query results.
|
||||
* <p>
|
||||
* This can be used when you want to process a very large number of results and
|
||||
* means that you don't have to hold all the results in memory at once (unlike
|
||||
* findList(), findSet() etc where all the beans are held in the List or Set
|
||||
* etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that findIterate (and findEach and findEachWhile) uses a "per graph"
|
||||
* persistence context scope and adjusts jdbc fetch buffer size for large
|
||||
* queries. As such it is better to use findList for small queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
|
||||
* when you have finished iterating the results. Use "try with resources" or ensure it
|
||||
* is closed in a finally block.
|
||||
* </p>
|
||||
* <h3>Try finally style</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* QueryIterator<Customer> it = query.findIterate();
|
||||
* try {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer ...
|
||||
* }
|
||||
* } finally {
|
||||
* // close the underlying resources
|
||||
* it.close();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Try with resources style</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // try with resources
|
||||
* try (QueryIterator<Customer> it = query.findIterate()) {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer ...
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T> the type of entity bean in the iteration
|
||||
*/
|
||||
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if the iteration has more elements.
|
||||
*/
|
||||
@Override
|
||||
boolean hasNext();
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
*/
|
||||
@Override
|
||||
T next();
|
||||
|
||||
/**
|
||||
* Remove is not allowed.
|
||||
*/
|
||||
@Override
|
||||
void remove();
|
||||
|
||||
/**
|
||||
* Close the underlying resources held by this iterator.
|
||||
*/
|
||||
@Override
|
||||
void close();
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* The type of the query being executed.
|
||||
*/
|
||||
public enum QueryType {
|
||||
|
||||
/**
|
||||
* A find query.
|
||||
*/
|
||||
FIND,
|
||||
|
||||
/**
|
||||
* An update query.
|
||||
*/
|
||||
UPDATE,
|
||||
|
||||
/**
|
||||
* A delete query.
|
||||
*/
|
||||
DELETE
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Used to build object graphs based on a raw SQL statement (rather than
|
||||
* generated by Ebean).
|
||||
* <p>
|
||||
* If you don't want to build object graphs you can use {@link SqlQuery} instead
|
||||
* which returns {@link SqlRow} objects rather than entity beans.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Unparsed RawSql:</b>
|
||||
* </p>
|
||||
* <p>
|
||||
* When RawSql is created via {@link RawSqlBuilder#unparsed(String)} then Ebean can not
|
||||
* modify the SQL at all. It can't add any extra expressions into the SQL.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Parsed RawSql:</b>
|
||||
* </p>
|
||||
* <p>
|
||||
* When RawSql is created via {@link RawSqlBuilder#parse(String)} then Ebean will parse the
|
||||
* SQL and find places in the SQL where it can add extra where expressions, add
|
||||
* extra having expressions or replace the order by clause. If you want to
|
||||
* explicitly tell Ebean where these insertion points are you can place special
|
||||
* strings into your SQL ({@code ${where}} or {@code ${andWhere}} and {@code ${having}} or
|
||||
* {@code ${andHaving})}.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the SQL already includes a WHERE clause put in {@code ${andWhere}} in the location
|
||||
* you want Ebean to add any extra where expressions. If the SQL doesn't have a
|
||||
* WHERE clause put {@code ${where}} in instead. Similarly you can put in {@code ${having}} or
|
||||
* {@code ${andHaving}} where you want Ebean put add extra having expressions.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Aggregates:</b>
|
||||
* </p>
|
||||
* <p>
|
||||
* Often RawSql will be used with Aggregate functions (sum, avg, max etc). The
|
||||
* follow example shows an example based on Total Order Amount -
|
||||
* sum(d.order_qty*d.unit_price).
|
||||
* </p>
|
||||
* <p>
|
||||
* We can use a OrderAggregate bean that has a @Sql to indicate it is based
|
||||
* on RawSql and not based on a real DB Table or DB View. It has some properties
|
||||
* to hold the values for the aggregate functions (sum etc) and a @OneToOne
|
||||
* to Order.
|
||||
* </p>
|
||||
* <p>
|
||||
* <h3>Example OrderAggregate</h3>
|
||||
* <pre>{@code
|
||||
* ...
|
||||
* // @Sql indicates to that this bean
|
||||
* // is based on RawSql rather than a table
|
||||
*
|
||||
* @Entity
|
||||
* @Sql
|
||||
* public class OrderAggregate {
|
||||
*
|
||||
* @OneToOne
|
||||
* Order order;
|
||||
*
|
||||
* Double totalAmount;
|
||||
*
|
||||
* Double totalItems;
|
||||
*
|
||||
* // getters and setters
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Example 1:</h3>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = " select order_id, o.status, c.id, c.name, sum(d.order_qty*d.unit_price) as totalAmount"
|
||||
* + " from o_order o"
|
||||
* + " join o_customer c on c.id = o.kcustomer_id "
|
||||
* + " join o_order_detail d on d.order_id = o.id " + " group by order_id, o.status ";
|
||||
*
|
||||
* RawSql rawSql = RawSqlBuilder.parse(sql)
|
||||
* // map the sql result columns to bean properties
|
||||
* .columnMapping("order_id", "order.id")
|
||||
* .columnMapping("o.status", "order.status")
|
||||
* .columnMapping("c.id", "order.customer.id")
|
||||
* .columnMapping("c.name", "order.customer.name")
|
||||
* // we don't need to map this one due to the sql column alias
|
||||
* // .columnMapping("sum(d.order_qty*d.unit_price)", "totalAmount")
|
||||
* .create();
|
||||
*
|
||||
* List<OrderAggregate> list = Ebean.find(OrderAggregate.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .where().gt("order.id", 0)
|
||||
* .having().gt("totalAmount", 20)
|
||||
* .findList();
|
||||
*
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Example 2:</h3>
|
||||
* <p>
|
||||
* The following example uses a FetchConfig().query() so that after the initial
|
||||
* RawSql query is executed Ebean executes a secondary query to fetch the
|
||||
* associated order status, orderDate along with the customer name.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = " select order_id, 'ignoreMe', sum(d.order_qty*d.unit_price) as totalAmount "
|
||||
* + " from o_order_detail d"
|
||||
* + " group by order_id ";
|
||||
*
|
||||
* RawSql rawSql = RawSqlBuilder.parse(sql)
|
||||
* .columnMapping("order_id", "order.id")
|
||||
* .columnMappingIgnore("'ignoreMe'")
|
||||
* .create();
|
||||
*
|
||||
* List<OrderAggregate> orders = Ebean.find(OrderAggregate.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .fetch("order", "status,orderDate", new FetchConfig().query())
|
||||
* .fetch("order.customer", "name")
|
||||
* .where().gt("order.id", 0)
|
||||
* .having().gt("totalAmount", 20)
|
||||
* .order().desc("totalAmount")
|
||||
* .setMaxRows(10)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Example 3: tableAliasMapping</h3>
|
||||
* <p>
|
||||
* Instead of mapping each column you can map each table alias to a path using tableAliasMapping().
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* String rs = "select o.id, o.status, c.id, c.name, "+
|
||||
* " d.id, d.order_qty, p.id, p.name " +
|
||||
* "from o_order o join o_customer c on c.id = o.kcustomer_id " +
|
||||
* "join o_order_detail d on d.order_id = o.id " +
|
||||
* "join o_product p on p.id = d.product_id " +
|
||||
* "where o.id <= :maxOrderId and p.id = :productId "+
|
||||
* "order by o.id, d.id asc";
|
||||
*
|
||||
* RawSql rawSql = RawSqlBuilder.parse(rs)
|
||||
* .tableAliasMapping("c", "customer")
|
||||
* .tableAliasMapping("d", "details")
|
||||
* .tableAliasMapping("p", "details.product")
|
||||
* .create();
|
||||
*
|
||||
* List<Order> ordersFromRaw = Ebean.find(Order.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .setParameter("maxOrderId", 2)
|
||||
* .setParameter("productId", 1)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <p>
|
||||
* Note that lazy loading also works with object graphs built with RawSql.
|
||||
* </p>
|
||||
*/
|
||||
public interface RawSql {
|
||||
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Builds RawSql instances from a SQL string and column mappings.
|
||||
* <p>
|
||||
* Note that RawSql can also be defined in ebean-orm.xml files and be used as a
|
||||
* named query.
|
||||
* </p>
|
||||
*
|
||||
* @see RawSql
|
||||
*/
|
||||
public interface RawSqlBuilder {
|
||||
|
||||
/**
|
||||
* Create and return a RawSql object based on the resultSet and list of properties the columns in
|
||||
* the resultSet map to.
|
||||
* <p>
|
||||
* The properties listed in the propertyNames must be in the same order as the columns in the
|
||||
* resultSet.
|
||||
*/
|
||||
static RawSql resultSet(ResultSet resultSet, String... propertyNames) {
|
||||
return XServiceProvider.rawSql().resultSet(resultSet, propertyNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a SqlRow based on the resultSet with dbTrueValue and binaryOptimizedUUID options.
|
||||
*/
|
||||
static SqlRow sqlRow(ResultSet resultSet, final String dbTrueValue, boolean binaryOptimizedUUID) throws SQLException {
|
||||
return XServiceProvider.rawSql().sqlRow(resultSet, dbTrueValue, binaryOptimizedUUID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an unparsed RawSqlBuilder. Unlike a parsed one this query can not be
|
||||
* modified - so no additional WHERE or HAVING expressions can be added to
|
||||
* this query.
|
||||
*/
|
||||
static RawSqlBuilder unparsed(String sql) {
|
||||
return XServiceProvider.rawSql().unparsed(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a RawSqlBuilder parsing the sql.
|
||||
* <p>
|
||||
* The sql statement will be parsed so that Ebean can determine where it can
|
||||
* insert additional WHERE or HAVING expressions.
|
||||
* </p>
|
||||
* <p>
|
||||
* Additionally the selected columns are parsed to determine the column
|
||||
* ordering. This also means additional checks can be made with the column
|
||||
* mapping - specifically we can check that all columns are mapped and that
|
||||
* correct column names are entered into the mapping.
|
||||
* </p>
|
||||
*/
|
||||
static RawSqlBuilder parse(String sql) {
|
||||
return XServiceProvider.rawSql().parsed(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mapping of a DB Column to a bean property.
|
||||
* <p>
|
||||
* For Unparsed SQL the columnMapping MUST be defined in the same order that
|
||||
* the columns appear in the SQL statement.
|
||||
* </p>
|
||||
*
|
||||
* @param dbColumn the DB column that we are mapping to a bean property
|
||||
* @param propertyName the bean property that we are mapping the DB column to.
|
||||
*/
|
||||
RawSqlBuilder columnMapping(String dbColumn, String propertyName);
|
||||
|
||||
/**
|
||||
* Ignore this DB column. It is not mapped to any bean property.
|
||||
*/
|
||||
RawSqlBuilder columnMappingIgnore(String dbColumn);
|
||||
|
||||
/**
|
||||
* Modify any column mappings with the given table alias to have the path prefix.
|
||||
* <p>
|
||||
* For example modify all mappings with table alias "c" to have the path prefix "customer".
|
||||
* </p>
|
||||
* <p>
|
||||
* For the "Root type" you don't need to specify a tableAliasMapping.
|
||||
* </p>
|
||||
*/
|
||||
RawSqlBuilder tableAliasMapping(String tableAlias, String path);
|
||||
|
||||
/**
|
||||
* Create the immutable RawSql object. Do this after all the column mapping
|
||||
* has been defined.
|
||||
*/
|
||||
RawSql create();
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Used with SqlQuery to process potentially large queries reading directly from the JDBC ResultSet.
|
||||
* <p>
|
||||
* This provides a low level option that reads directly from the JDBC ResultSet.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = "select id, name, status from o_customer order by name desc";
|
||||
*
|
||||
* Ebean.createSqlQuery(sql)
|
||||
* .findEachRow((resultSet, rowNum) -> {
|
||||
*
|
||||
* // read directly from ResultSet
|
||||
*
|
||||
* long id = resultSet.getLong(1);
|
||||
* String name = resultSet.getString(2);
|
||||
*
|
||||
* // do something interesting with the data
|
||||
*
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RowConsumer {
|
||||
|
||||
/**
|
||||
* Read the data from the ResultSet and process it.
|
||||
*
|
||||
* @param resultSet The JDBC ResultSet positioned to the current row
|
||||
* @param rowNum The number of the current row being mapped.
|
||||
*/
|
||||
void accept(ResultSet resultSet, int rowNum) throws SQLException;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Used with SqlQuery to map raw JDBC ResultSet to objects.
|
||||
* <p>
|
||||
* This provides a low level mapping option with direct use of JDBC ResultSet
|
||||
* with the option of having logic in the mapping. For example, only map some
|
||||
* columns depending on the values read from other columns.
|
||||
* </p>
|
||||
* <p>
|
||||
* For straight mapping into beans then DtoQuery would be the first choice as
|
||||
* it can automatically map the ResultSet into beans.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* //
|
||||
* // A mapper from ResultSet into our CustomerDto bean
|
||||
* //
|
||||
* class CustomerMapper implements RowMapper<CustomerDto> {
|
||||
*
|
||||
* @Override
|
||||
* public CustomerDto map(ResultSet rset, int rowNum) throws SQLException {
|
||||
*
|
||||
* long id = rset.getLong(1);
|
||||
* String name = rset.getString(2);
|
||||
* String status = rset.getString(3);
|
||||
*
|
||||
* return new CustomerDto(id, name, status);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*
|
||||
* //
|
||||
* // Then use the mapper
|
||||
* //
|
||||
*
|
||||
* String sql = "select id, name, status from o_customer where name = ?";
|
||||
*
|
||||
* CustomerDto rob = Ebean.createSqlQuery(sql)
|
||||
* .setParameter(1, "Rob")
|
||||
* .findOne(CUSTOMER_MAPPER);
|
||||
*
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T> The type the row data is mapped into.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RowMapper<T> {
|
||||
|
||||
/**
|
||||
* Read the data from the ResultSet and map to the return type.
|
||||
*
|
||||
* @param resultSet The JDBC ResultSet positioned to the current row
|
||||
* @param rowNum The number of the current row being mapped.
|
||||
*/
|
||||
T map(ResultSet resultSet, int rowNum) throws SQLException;
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Query object for performing native SQL queries that return SqlRow's.
|
||||
* <p>
|
||||
* Firstly note that you can use your own sql queries with <em>entity beans</em>
|
||||
* by using the SqlSelect annotation. This should be your first approach when
|
||||
* wanting to use your own SQL queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* If ORM Mapping is too tight and constraining for your problem then SqlQuery
|
||||
* could be a good approach.
|
||||
* </p>
|
||||
* <p>
|
||||
* The returned SqlRow objects are similar to a LinkedHashMap with some type
|
||||
* conversion support added.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // its typically a good idea to use a named query
|
||||
* // and put the sql in the orm.xml instead of in your code
|
||||
*
|
||||
* String sql = "select id, name from customer where name like :name and status_code = :status";
|
||||
*
|
||||
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
|
||||
* sqlQuery.setParameter("name", "Acme%");
|
||||
* sqlQuery.setParameter("status", "ACTIVE");
|
||||
*
|
||||
* // execute the query returning a List of MapBean objects
|
||||
* List<SqlRow> list = sqlQuery.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public interface SqlQuery extends Serializable {
|
||||
|
||||
/**
|
||||
* Execute the query returning a list.
|
||||
*/
|
||||
@Nonnull
|
||||
List<SqlRow> findList();
|
||||
|
||||
/**
|
||||
* Execute the SqlQuery iterating a row at a time.
|
||||
* <p>
|
||||
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
|
||||
* </p>
|
||||
*/
|
||||
void findEach(Consumer<SqlRow> consumer);
|
||||
|
||||
/**
|
||||
* Execute the SqlQuery iterating a row at a time with the ability to stop consuming part way through.
|
||||
* <p>
|
||||
* Returning false after processing a row stops the iteration through the query results.
|
||||
* </p>
|
||||
* <p>
|
||||
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
|
||||
* </p>
|
||||
*/
|
||||
void findEachWhile(Predicate<SqlRow> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query returning a single row or null.
|
||||
* <p>
|
||||
* If this query finds 2 or more rows then it will throw a
|
||||
* PersistenceException.
|
||||
* </p>
|
||||
*/
|
||||
@Nullable
|
||||
SqlRow findOne();
|
||||
|
||||
/**
|
||||
* Execute the query returning a single result using the mapper.
|
||||
*
|
||||
* @param mapper Used to map each ResultSet row into the result object.
|
||||
*/
|
||||
<T> T findOne(RowMapper<T> mapper);
|
||||
|
||||
/**
|
||||
* Execute the query returning a list using the mapper.
|
||||
*
|
||||
* @param mapper Used to map each ResultSet row into the result object.
|
||||
*/
|
||||
<T> List<T> findList(RowMapper<T> mapper);
|
||||
|
||||
/**
|
||||
* Execute the query reading each row from ResultSet using the RowConsumer.
|
||||
* <p>
|
||||
* This provides a low level option that reads directly from the JDBC ResultSet
|
||||
* and is good for processing very large results where (unlike findList) we don't
|
||||
* hold all the results in memory but instead can process row by row.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = "select id, name, status from customer order by name desc";
|
||||
*
|
||||
* Ebean.createSqlQuery(sql)
|
||||
* .findEachRow((resultSet, rowNum) -> {
|
||||
*
|
||||
* // read directly from ResultSet
|
||||
*
|
||||
* long id = resultSet.getLong(1);
|
||||
* String name = resultSet.getString(2);
|
||||
*
|
||||
* // do something interesting with the data
|
||||
*
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param consumer Used to read and process each ResultSet row.
|
||||
*/
|
||||
void findEachRow(RowConsumer consumer);
|
||||
|
||||
/**
|
||||
* Execute the query returning an optional row.
|
||||
*/
|
||||
@Nonnull
|
||||
Optional<SqlRow> findOneOrEmpty();
|
||||
|
||||
/**
|
||||
* Execute the query returning a single scalar attribute.
|
||||
* <pre>@{code
|
||||
*
|
||||
* String sql = "select max(unit_price) from o_order_detail where order_qty > ?";
|
||||
*
|
||||
* BigDecimal maxPrice = Ebean.createSqlQuery(sql)
|
||||
* .setParameter(1, 2)
|
||||
* .findSingleAttribute(BigDecimal.class);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* The attributeType can be any scalar type that Ebean supports (includes javax time types, Joda types etc).
|
||||
* </p>
|
||||
*
|
||||
* @param attributeType The type of the returned value
|
||||
*/
|
||||
<T> T findSingleAttribute(Class<T> attributeType);
|
||||
|
||||
/**
|
||||
* Execute the query returning a single BigDecimal value.
|
||||
* <p>
|
||||
* This is an alias for <code>findSingleAttribute(BigDecimal.class)</code>
|
||||
* </p>
|
||||
*/
|
||||
BigDecimal findSingleDecimal();
|
||||
|
||||
/**
|
||||
* Execute the query returning a single Long value.
|
||||
* <p>
|
||||
* This is an alias for <code>findSingleAttribute(Long.class)</code>
|
||||
* </p>
|
||||
*/
|
||||
Long findSingleLong();
|
||||
|
||||
/**
|
||||
* Execute the query returning a list of scalar attribute values.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql =
|
||||
* " select (unit_price * order_qty) " +
|
||||
* " from o_order_detail " +
|
||||
* " where unit_price > ? " +
|
||||
* " order by (unit_price * order_qty) desc";
|
||||
*
|
||||
* //
|
||||
* List<BigDecimal> lineAmounts = Ebean.createSqlQuery(sql)
|
||||
* .setParameter(1, 3)
|
||||
* .findSingleAttributeList(BigDecimal.class);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* The attributeType can be any scalar type that Ebean supports (includes javax time types, Joda types etc).
|
||||
* </p>
|
||||
*
|
||||
* @param attributeType The type of the returned value
|
||||
*/
|
||||
<T> List<T> findSingleAttributeList(Class<T> attributeType);
|
||||
|
||||
/**
|
||||
* The same as bind for named parameters.
|
||||
*/
|
||||
SqlQuery setParameter(String name, Object value);
|
||||
|
||||
/**
|
||||
* The same as bind for positioned parameters.
|
||||
*/
|
||||
SqlQuery setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set the index of the first row of the results to return.
|
||||
*/
|
||||
SqlQuery setFirstRow(int firstRow);
|
||||
|
||||
/**
|
||||
* Set the maximum number of query results to return.
|
||||
*/
|
||||
SqlQuery setMaxRows(int maxRows);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
SqlQuery setTimeout(int secs);
|
||||
|
||||
/**
|
||||
* Set a label that can be put on performance metrics that are collected.
|
||||
*/
|
||||
SqlQuery setLabel(String label);
|
||||
|
||||
/**
|
||||
* 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>
|
||||
*/
|
||||
SqlQuery setBufferFetchSizeHint(int bufferFetchSizeHint);
|
||||
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Date;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Used to return raw SQL query results.
|
||||
* <p>
|
||||
* Refer to {@link SqlQuery} for examples.
|
||||
* </p>
|
||||
* <p>
|
||||
* There are convenience methods such as getInteger(), getBigDecimal() etc. The
|
||||
* reason for these methods is that the values put into this map often come
|
||||
* straight from the JDBC resultSet. Depending on the JDBC driver it may put a
|
||||
* different type into a given property. For example an Integer, BigDecimal,
|
||||
* Double could all be put into a property depending on the JDBC driver used.
|
||||
* These convenience methods automatically convert the value as required
|
||||
* returning the type you expect.
|
||||
* </p>
|
||||
*/
|
||||
public interface SqlRow extends Serializable, Map<String, Object> {
|
||||
|
||||
/**
|
||||
* Return the property names (String).
|
||||
* <p>
|
||||
* Internally this uses LinkedHashMap and so the order of the property names
|
||||
* should be predictable and ordered by the use of LinkedHashMap.
|
||||
* </p>
|
||||
*/
|
||||
Iterator<String> keys();
|
||||
|
||||
/**
|
||||
* Remove a property from the map. Returns the value of the removed property.
|
||||
*/
|
||||
@Override
|
||||
Object remove(Object name);
|
||||
|
||||
/**
|
||||
* Return a property value by its name.
|
||||
*/
|
||||
@Override
|
||||
Object get(Object name);
|
||||
|
||||
/**
|
||||
* Set a value to a property.
|
||||
*/
|
||||
@Override
|
||||
Object put(String name, Object value);
|
||||
|
||||
/**
|
||||
* Exactly the same as the put method.
|
||||
* <p>
|
||||
* I added this method because it seems more bean like to have get and set
|
||||
* methods.
|
||||
* </p>
|
||||
*/
|
||||
Object set(String name, Object value);
|
||||
|
||||
/**
|
||||
* Return a property as a Boolean.
|
||||
*/
|
||||
Boolean getBoolean(String name);
|
||||
|
||||
/**
|
||||
* Return a property as a UUID.
|
||||
*/
|
||||
UUID getUUID(String name);
|
||||
|
||||
/**
|
||||
* Return a property as an Integer.
|
||||
*/
|
||||
Integer getInteger(String name);
|
||||
|
||||
/**
|
||||
* Return a property value as a BigDecimal.
|
||||
*/
|
||||
BigDecimal getBigDecimal(String name);
|
||||
|
||||
/**
|
||||
* Return a property value as a Long.
|
||||
*/
|
||||
Long getLong(String name);
|
||||
|
||||
/**
|
||||
* Return the property value as a Double.
|
||||
*/
|
||||
Double getDouble(String name);
|
||||
|
||||
/**
|
||||
* Return the property value as a Float.
|
||||
*/
|
||||
Float getFloat(String name);
|
||||
|
||||
/**
|
||||
* Return a property as a String.
|
||||
*/
|
||||
String getString(String name);
|
||||
|
||||
/**
|
||||
* Return the property as a java.util.Date.
|
||||
*/
|
||||
java.util.Date getUtilDate(String name);
|
||||
|
||||
/**
|
||||
* Return the property as a sql date.
|
||||
*/
|
||||
Date getDate(String name);
|
||||
|
||||
/**
|
||||
* Return the property as a sql timestamp.
|
||||
*/
|
||||
Timestamp getTimestamp(String name);
|
||||
|
||||
/**
|
||||
* String description of the underlying map.
|
||||
*/
|
||||
@Override
|
||||
String toString();
|
||||
|
||||
/**
|
||||
* Clear the map.
|
||||
*/
|
||||
@Override
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Returns true if the map contains the property.
|
||||
*/
|
||||
@Override
|
||||
boolean containsKey(Object key);
|
||||
|
||||
/**
|
||||
* Returns true if the map contains the value.
|
||||
*/
|
||||
@Override
|
||||
boolean containsValue(Object value);
|
||||
|
||||
/**
|
||||
* Returns the entrySet of the map.
|
||||
*/
|
||||
@Override
|
||||
Set<Map.Entry<String, Object>> entrySet();
|
||||
|
||||
/**
|
||||
* Returns true if the map is empty.
|
||||
*/
|
||||
@Override
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Returns the key set of the map.
|
||||
*/
|
||||
@Override
|
||||
Set<String> keySet();
|
||||
|
||||
/**
|
||||
* Put all the values from t into this map.
|
||||
*/
|
||||
@Override
|
||||
void putAll(Map<? extends String, ?> t);
|
||||
|
||||
/**
|
||||
* Return the size of the map.
|
||||
*/
|
||||
@Override
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Return the values from this map.
|
||||
*/
|
||||
@Override
|
||||
Collection<Object> values();
|
||||
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* A SqlUpdate for executing insert update or delete statements.
|
||||
* <p>
|
||||
* Provides a simple way to execute raw SQL insert update or delete statements
|
||||
* without having to resort to JDBC.
|
||||
* </p>
|
||||
* <p>
|
||||
* Supports the use of positioned or named parameters and can automatically
|
||||
* notify Ebean of the table modified so that Ebean can maintain its cache.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that {@link #setAutoTableMod(boolean)} and
|
||||
* Ebean#externalModification(String, boolean, boolean, boolean)} can be to
|
||||
* notify Ebean of external changes and enable Ebean to maintain it's "L2"
|
||||
* server cache.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // example that uses 'named' parameters
|
||||
*
|
||||
* String s = "UPDATE f_topic set post_count = :count where id = :id";
|
||||
*
|
||||
* SqlUpdate update = Ebean.createSqlUpdate(s);
|
||||
* update.setParameter("id", 1);
|
||||
* update.setParameter("count", 50);
|
||||
*
|
||||
* int modifiedCount = update.execute();
|
||||
*
|
||||
* String msg = "There were " + modifiedCount + " rows updated";
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Example: Using setNextParameter()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = "insert into audit_log (id, description, modified_description) values (?,?,?)";
|
||||
* SqlUpdate insert = Ebean.createSqlUpdate(sql);
|
||||
*
|
||||
* try (Transaction txn = Ebean.beginTransaction()) {
|
||||
* txn.setBatchMode(true);
|
||||
*
|
||||
* insert.setNextParameter(10000);
|
||||
* insert.setNextParameter("hello");
|
||||
* insert.setNextParameter("rob");
|
||||
* insert.execute();
|
||||
*
|
||||
* insert.setNextParameter(10001);
|
||||
* insert.setNextParameter("goodbye");
|
||||
* insert.setNextParameter("rob");
|
||||
* insert.execute();
|
||||
*
|
||||
* insert.setNextParameter(10002);
|
||||
* insert.setNextParameter("chow");
|
||||
* insert.setNextParameter("bob");
|
||||
* insert.execute();
|
||||
*
|
||||
* txn.commit();
|
||||
* }
|
||||
* }</pre>
|
||||
* <p>
|
||||
* An alternative to the batch mode on the transaction is to use addBatch() and executeBatch() like:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* try (Transaction txn = Ebean.beginTransaction()) {
|
||||
*
|
||||
* insert.setNextParameter(10000);
|
||||
* insert.setNextParameter("hello");
|
||||
* insert.setNextParameter("rob");
|
||||
* insert.addBatch();
|
||||
*
|
||||
* insert.setNextParameter(10001);
|
||||
* insert.setNextParameter("goodbye");
|
||||
* insert.setNextParameter("rob");
|
||||
* insert.addBatch();
|
||||
*
|
||||
* insert.setNextParameter(10002);
|
||||
* insert.setNextParameter("chow");
|
||||
* insert.setNextParameter("bob");
|
||||
* insert.addBatch();
|
||||
*
|
||||
* int[] rows = insert.executeBatch();
|
||||
*
|
||||
* txn.commit();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see Update
|
||||
* @see SqlQuery
|
||||
* @see CallableSql
|
||||
*/
|
||||
public interface SqlUpdate {
|
||||
|
||||
/**
|
||||
* Execute the update returning the number of rows modified.
|
||||
* <p>
|
||||
* After you have executed the SqlUpdate you can bind new variables using
|
||||
* {@link #setParameter(String, Object)} etc and then execute the SqlUpdate
|
||||
* again.
|
||||
* </p>
|
||||
* <p>
|
||||
* For JDBC batch processing refer to
|
||||
* {@link Transaction#setBatchMode(boolean)} and
|
||||
* {@link Transaction#setBatchSize(int)}.
|
||||
* </p>
|
||||
*
|
||||
* @see Ebean#execute(SqlUpdate)
|
||||
*/
|
||||
int execute();
|
||||
|
||||
/**
|
||||
* Execute when addBatch() has been used to batch multiple bind executions.
|
||||
*
|
||||
* @return The row counts for each of the batched statements.
|
||||
*/
|
||||
int[] executeBatch();
|
||||
|
||||
/**
|
||||
* Add the statement to batch processing to then later execute via executeBatch().
|
||||
*/
|
||||
void addBatch();
|
||||
|
||||
/**
|
||||
* Return the generated key value.
|
||||
*/
|
||||
Object getGeneratedKey();
|
||||
|
||||
/**
|
||||
* Execute and return the generated key. This is effectively a short cut for:
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* sqlUpdate.execute();
|
||||
* Object key = sqlUpdate.getGeneratedKey();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @return The generated key value
|
||||
*/
|
||||
Object executeGetKey();
|
||||
|
||||
/**
|
||||
* Return true if eBean should automatically deduce the table modification
|
||||
* information and process it.
|
||||
* <p>
|
||||
* If this is true then cache invalidation and text index management are aware
|
||||
* of the modification.
|
||||
* </p>
|
||||
*/
|
||||
boolean isAutoTableMod();
|
||||
|
||||
/**
|
||||
* Set this to false if you don't want eBean to automatically deduce the table
|
||||
* modification information and process it.
|
||||
* <p>
|
||||
* Set this to false if you don't want any cache invalidation or text index
|
||||
* management to occur. You may do this when say you update only one column
|
||||
* and you know that it is not important for cached objects or text indexes.
|
||||
* </p>
|
||||
*/
|
||||
SqlUpdate setAutoTableMod(boolean isAutoTableMod);
|
||||
|
||||
/**
|
||||
* Return the label that can be seen in the transaction logs.
|
||||
*/
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* Set a descriptive text that can be put into the transaction log.
|
||||
* <p>
|
||||
* Useful when identifying the statement in the transaction log.
|
||||
* </p>
|
||||
*/
|
||||
SqlUpdate setLabel(String label);
|
||||
|
||||
/**
|
||||
* Set to true when we want to use getGeneratedKeys with this statement.
|
||||
*/
|
||||
SqlUpdate setGetGeneratedKeys(boolean getGeneratedKeys);
|
||||
|
||||
/**
|
||||
* Return the sql statement.
|
||||
*/
|
||||
String getSql();
|
||||
|
||||
/**
|
||||
* Return the generated sql that has named parameters converted to positioned parameters.
|
||||
*/
|
||||
String getGeneratedSql();
|
||||
|
||||
/**
|
||||
* Return the timeout used to execute this statement.
|
||||
*/
|
||||
int getTimeout();
|
||||
|
||||
/**
|
||||
* Set the timeout in seconds. Zero implies no limit.
|
||||
* <p>
|
||||
* This will set the query timeout on the underlying PreparedStatement. If the
|
||||
* timeout expires a SQLException will be throw and wrapped in a
|
||||
* PersistenceException.
|
||||
* </p>
|
||||
*/
|
||||
SqlUpdate setTimeout(int secs);
|
||||
|
||||
/**
|
||||
* Set the next positioned parameter.
|
||||
*
|
||||
* @param value The value to bind
|
||||
*/
|
||||
SqlUpdate setNextParameter(Object value);
|
||||
|
||||
/**
|
||||
* Set a parameter via its index position.
|
||||
*/
|
||||
SqlUpdate setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set a null parameter via its index position.
|
||||
*/
|
||||
SqlUpdate setNull(int position, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set a null valued parameter using its index position.
|
||||
*/
|
||||
SqlUpdate setNullParameter(int position, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set a named parameter value.
|
||||
*/
|
||||
SqlUpdate setParameter(String name, Object param);
|
||||
|
||||
/**
|
||||
* Set a named parameter that has a null value. Exactly the same as
|
||||
* {@link #setNullParameter(String, int)}.
|
||||
*/
|
||||
SqlUpdate setNull(String name, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set a named parameter that has a null value.
|
||||
*/
|
||||
SqlUpdate setNullParameter(String name, int jdbcType);
|
||||
|
||||
}
|
||||
@@ -1,556 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.config.DocStoreConfig;
|
||||
import io.ebean.config.ServerConfig;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* The Transaction object. Typically representing a JDBC or JTA transaction.
|
||||
*/
|
||||
public interface Transaction extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* Return the current transaction (of the default server) or null if there is
|
||||
* no current transaction in scope.
|
||||
* <p>
|
||||
* This is the same as <code>Ebean.currentTransaction()</code>
|
||||
* </p>
|
||||
* <p>
|
||||
* This returns the current transaction for the 'default server'. If you are using
|
||||
* multiple EbeanServer's then use {@link EbeanServer#currentTransaction()}.
|
||||
* </p>
|
||||
*
|
||||
* @see Ebean#currentTransaction()
|
||||
* @see EbeanServer#currentTransaction()
|
||||
*/
|
||||
static Transaction current() {
|
||||
return Ebean.currentTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read Committed transaction isolation. Same as
|
||||
* java.sql.Connection.TRANSACTION_READ_COMMITTED.
|
||||
*/
|
||||
int READ_COMMITTED = java.sql.Connection.TRANSACTION_READ_COMMITTED;
|
||||
|
||||
/**
|
||||
* Read Uncommitted transaction isolation. Same as
|
||||
* java.sql.Connection.TRANSACTION_READ_UNCOMMITTED.
|
||||
*/
|
||||
int READ_UNCOMMITTED = java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
|
||||
|
||||
/**
|
||||
* Repeatable read transaction isolation. Same as
|
||||
* java.sql.Connection.TRANSACTION_REPEATABLE_READ.
|
||||
*/
|
||||
int REPEATABLE_READ = java.sql.Connection.TRANSACTION_REPEATABLE_READ;
|
||||
|
||||
/**
|
||||
* Serializable transaction isolation. Same as
|
||||
* java.sql.Connection.TRANSACTION_SERIALIZABLE.
|
||||
*/
|
||||
int SERIALIZABLE = java.sql.Connection.TRANSACTION_SERIALIZABLE;
|
||||
|
||||
/**
|
||||
* Register a TransactionCallback with this transaction.
|
||||
*/
|
||||
void register(TransactionCallback callback);
|
||||
|
||||
/**
|
||||
* Set a label on the transaction.
|
||||
* <p>
|
||||
* This label is used to group transaction execution times for performance metrics reporting.
|
||||
* </p>
|
||||
*/
|
||||
void setLabel(String label);
|
||||
|
||||
/**
|
||||
* Return true if this transaction is read only.
|
||||
*/
|
||||
boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Set whether this transaction should be readOnly.
|
||||
*/
|
||||
void setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Commits the transaction at this point with the expectation that another
|
||||
* commit (or rollback or end) will occur later to complete the transaction.
|
||||
* <p>
|
||||
* This is similar to commit() but leaves the transaction "Active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <ul>
|
||||
* <li>Flush the JDBC batch buffer</li>
|
||||
* <li>Call commit on the underlying JDBC connection</li>
|
||||
* <li>Trigger any registered TransactionCallbacks</li>
|
||||
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
|
||||
* </ul>
|
||||
*/
|
||||
void commitAndContinue();
|
||||
|
||||
/**
|
||||
* Commit the transaction.
|
||||
* <p>
|
||||
* This performs commit and completes the transaction closing underlying resources and
|
||||
* marking the transaction as "In active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <ul>
|
||||
* <li>Flush the JDBC batch buffer</li>
|
||||
* <li>Call commit on the underlying JDBC connection</li>
|
||||
* <li>Trigger any registered TransactionCallbacks</li>
|
||||
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
|
||||
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
|
||||
* <li>Mark the transaction as "Inactive"</li>
|
||||
* </ul>
|
||||
*/
|
||||
void commit();
|
||||
|
||||
/**
|
||||
* Rollback the transaction.
|
||||
* <p>
|
||||
* This performs rollback, closes underlying resources and marks the transaction as "In active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <ul>
|
||||
* <li>Call rollback on the underlying JDBC connection</li>
|
||||
* <li>Trigger any registered TransactionCallbacks</li>
|
||||
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
|
||||
* <li>Mark the transaction as "Inactive"</li>
|
||||
* </ul>
|
||||
*/
|
||||
void rollback() throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Rollback the transaction specifying a throwable that caused the rollback to
|
||||
* occur.
|
||||
* <p>
|
||||
* If you are using transaction logging this will log the throwable in the
|
||||
* transaction logs.
|
||||
* </p>
|
||||
*/
|
||||
void rollback(Throwable e) throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Set when we want nested transactions to use Savepoint's.
|
||||
* <p>
|
||||
* This means that for a nested transaction:
|
||||
* <ul>
|
||||
* <li>begin transaction maps to creating a savepoint</li>
|
||||
* <li>commit transaction maps to releasing a savepoint</li>
|
||||
* <li>rollback transaction maps to rollback a savepoint</li>
|
||||
* </ul>
|
||||
*/
|
||||
void setNestedUseSavepoint();
|
||||
|
||||
/**
|
||||
* Mark the transaction for rollback only.
|
||||
*/
|
||||
void setRollbackOnly();
|
||||
|
||||
/**
|
||||
* Return true if the transaction is marked as rollback only.
|
||||
*/
|
||||
boolean isRollbackOnly();
|
||||
|
||||
/**
|
||||
* If the transaction is active then perform rollback. Otherwise do nothing.
|
||||
*/
|
||||
void end();
|
||||
|
||||
/**
|
||||
* Synonym for end() to support AutoClosable.
|
||||
*/
|
||||
@Override
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Return true if the transaction is active.
|
||||
*/
|
||||
boolean isActive();
|
||||
|
||||
/**
|
||||
* Set the behavior for document store updates on this transaction.
|
||||
* <p>
|
||||
* For example, set the mode to DocStoreEvent.IGNORE for this transaction and
|
||||
* then any changes via this transaction are not sent to the doc store. This
|
||||
* would be used when doing large bulk inserts into the database and we want
|
||||
* to control how that is sent to the document store.
|
||||
* </p>
|
||||
*/
|
||||
void setDocStoreMode(DocStoreMode mode);
|
||||
|
||||
/**
|
||||
* Set the batch size to use for sending messages to the document store.
|
||||
* <p>
|
||||
* You might set this if you know the changes in this transaction result in especially large or
|
||||
* especially small payloads and want to adjust the batch size to match.
|
||||
* </p>
|
||||
* <p>
|
||||
* Setting this overrides the default of {@link DocStoreConfig#getBulkBatchSize()}
|
||||
* </p>
|
||||
*/
|
||||
void setDocStoreBatchSize(int batchSize);
|
||||
|
||||
/**
|
||||
* Explicitly turn off or on the cascading nature of save() and delete(). This
|
||||
* gives the developer exact control over what beans are saved and deleted
|
||||
* rather than Ebean cascading detecting 'dirty/modified' beans etc.
|
||||
* <p>
|
||||
* This is useful if you can getting back entity beans from a layer of code
|
||||
* (potentially remote) and you prefer to have exact control.
|
||||
* </p>
|
||||
* <p>
|
||||
* This may also be useful if you are using jdbc batching with jdbc drivers
|
||||
* that do not support getGeneratedKeys.
|
||||
* </p>
|
||||
*/
|
||||
void setPersistCascade(boolean persistCascade);
|
||||
|
||||
/**
|
||||
* Set to true when you want all loaded properties to be included in the update
|
||||
* (rather than just the changed properties).
|
||||
* <p>
|
||||
* You might set this when using JDBC batch in order to get multiple updates
|
||||
* with slightly different sets of changed properties into the same statement
|
||||
* and hence better JDBC batch performance.
|
||||
* </p>
|
||||
*/
|
||||
void setUpdateAllLoadedProperties(boolean updateAllLoadedProperties);
|
||||
|
||||
/**
|
||||
* Set if the L2 cache should be skipped for "find by id" and "find by natural key" queries.
|
||||
* <p>
|
||||
* By default {@link ServerConfig#isSkipCacheAfterWrite()} is true and that means that for
|
||||
* "find by id" and "find by natural key" queries which normally hit L2 bean cache automatically
|
||||
* - will not do so after a persist/write on the transaction.
|
||||
* </p>
|
||||
* <p>
|
||||
* This method provides explicit control over whether "find by id" and "find by natural key"
|
||||
* will skip the L2 bean cache or not (regardless of whether the transaction is considered "read only").
|
||||
* </p>
|
||||
* <p>
|
||||
* Refer to {@link ServerConfig#setSkipCacheAfterWrite(boolean)} for configuring the default behavior
|
||||
* for using the L2 bean cache in transactions spanning multiple query/persist requests.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // assume Customer has L2 bean caching enabled ...
|
||||
*
|
||||
* Transaction transaction = Ebean.beginTransaction();
|
||||
* try {
|
||||
*
|
||||
* // this uses L2 bean cache as the transaction
|
||||
* // ... is considered "query only" at this point
|
||||
* Customer.find.byId(42);
|
||||
*
|
||||
* // transaction no longer "query only" once
|
||||
* // ... a bean has been saved etc
|
||||
* Ebean.save(someBean);
|
||||
*
|
||||
* // will NOT use L2 bean cache as the transaction
|
||||
* // ... is no longer considered "query only"
|
||||
* Customer.find.byId(55);
|
||||
*
|
||||
*
|
||||
*
|
||||
* // explicit control - please use L2 bean cache
|
||||
*
|
||||
* transaction.setSkipCache(false);
|
||||
* Customer.find.byId(77); // hit the l2 bean cache
|
||||
*
|
||||
*
|
||||
* // explicit control - please don't use L2 bean cache
|
||||
*
|
||||
* transaction.setSkipCache(true);
|
||||
* Customer.find.byId(99); // skips l2 bean cache
|
||||
*
|
||||
*
|
||||
* } finally {
|
||||
* transaction.end();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see ServerConfig#isSkipCacheAfterWrite()
|
||||
*/
|
||||
void setSkipCache(boolean skipCache);
|
||||
|
||||
/**
|
||||
* Return true if the L2 cache should be skipped. More accurately if true then find by id
|
||||
* and find by natural key queries should NOT automatically use the L2 bean cache.
|
||||
*/
|
||||
boolean isSkipCache();
|
||||
|
||||
/**
|
||||
* Turn on or off statement batching. Statement batching can be transparent
|
||||
* for drivers and databases that support getGeneratedKeys. Otherwise you may
|
||||
* wish to specifically control when batching is used via this method.
|
||||
* <p>
|
||||
* Refer to <code>java.sql.PreparedStatement.addBatch();</code>
|
||||
* <p>
|
||||
* Note that you may also wish to use the setPersistCascade method to stop
|
||||
* save and delete cascade behaviour. You may do this to have full control
|
||||
* over the order of execution rather than the normal cascading fashion.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that the <em>execution order</em> in batch mode may be different from
|
||||
* non batch mode execution order. Also note that <em>insert behaviour</em>
|
||||
* may be different depending on the JDBC driver and its support for
|
||||
* getGeneratedKeys. That is, for JDBC drivers that do not support
|
||||
* getGeneratedKeys you may not get back the generated IDs (used for inserting
|
||||
* associated detail beans etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* Calls to save(), delete(), insert() and execute() all support batch
|
||||
* processing. This includes normal beans, MapBean, CallableSql and UpdateSql.
|
||||
* </p>
|
||||
* <p>
|
||||
* The flushing of the batched statements is automatic but you can call
|
||||
* batchFlush when you like. Note that flushing occurs when a query is
|
||||
* executed or when you mix UpdateSql and CallableSql with save and delete of
|
||||
* beans.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example: batch processing executing every 3 rows
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String data = "This is a simple test of the batch processing"
|
||||
* + " mode and the transaction execute batch method";
|
||||
*
|
||||
* String[] da = data.split(" ");
|
||||
*
|
||||
* String sql = "{call sp_t3(?,?)}";
|
||||
*
|
||||
* CallableSql cs = new CallableSql(sql);
|
||||
* cs.registerOut(2, Types.INTEGER);
|
||||
*
|
||||
* // (optional) inform eBean this stored procedure
|
||||
* // inserts into a table called sp_test
|
||||
* cs.addModification("sp_test", true, false, false);
|
||||
*
|
||||
* Transaction txn = ebeanServer.beginTransaction();
|
||||
* txn.setBatchMode(true);
|
||||
* txn.setBatchSize(3);
|
||||
* try {
|
||||
* for (int i = 0; i < da.length;) {
|
||||
* cs.setParameter(1, da[i]);
|
||||
* ebeanServer.execute(cs);
|
||||
* }
|
||||
*
|
||||
* // NB: commit implicitly flushes
|
||||
* txn.commit();
|
||||
*
|
||||
* } finally {
|
||||
* txn.end();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
void setBatchMode(boolean useBatch);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to {@link #setBatchMode(boolean)}.
|
||||
* <p>
|
||||
* Set the JDBC batch mode to use for this transaction.
|
||||
* </p>
|
||||
* <p>
|
||||
* If this is NONE then JDBC batch can still be used for each request - save(), insert(), update() or delete()
|
||||
* and this would be useful if the request cascades to detail beans.
|
||||
* </p>
|
||||
*
|
||||
* @param persistBatchMode the batch mode to use for this transaction
|
||||
* @see io.ebean.config.ServerConfig#setPersistBatch(PersistBatch)
|
||||
*/
|
||||
@Deprecated
|
||||
void setBatch(PersistBatch persistBatchMode);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to {@link #isBatchMode()}.
|
||||
* Return the batch mode at the transaction level.
|
||||
*/
|
||||
@Deprecated
|
||||
PersistBatch getBatch();
|
||||
|
||||
/**
|
||||
* Return the batch mode at the transaction level.
|
||||
*/
|
||||
boolean isBatchMode();
|
||||
|
||||
/**
|
||||
* Set the JDBC batch mode to use for a save() or delete() when cascading to children.
|
||||
* <p>
|
||||
* This only takes effect when batch mode on the transaction has not already meant that
|
||||
* JDBC batch mode is being used.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is useful when the single save() or delete() cascades. For example, inserting a 'master' cascades
|
||||
* and inserts a collection of 'detail' beans. The detail beans can be inserted using JDBC batch.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is effectively already turned on for all platforms apart from older Sql Server.
|
||||
* </p>
|
||||
*
|
||||
* @param batchMode the batch mode to use per save(), insert(), update() or delete()
|
||||
* @see io.ebean.config.ServerConfig#setPersistBatchOnCascade(PersistBatch)
|
||||
*/
|
||||
void setBatchOnCascade(boolean batchMode);
|
||||
|
||||
/**
|
||||
* Set the batch mode when cascading.
|
||||
* <p>
|
||||
* Deprecated in favour of {@link #setBatchOnCascade(boolean)}
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
void setBatchOnCascade(PersistBatch batchOnCascadeMode);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to {@link #isBatchMode()}.
|
||||
* Return the batch mode at the request level (for each save(), insert(), update() or delete()).
|
||||
*/
|
||||
@Deprecated
|
||||
PersistBatch getBatchOnCascade();
|
||||
|
||||
/**
|
||||
* Return the batch mode at the request level.
|
||||
*/
|
||||
boolean isBatchOnCascade();
|
||||
|
||||
/**
|
||||
* Specify the number of statements before a batch is flushed automatically.
|
||||
*/
|
||||
void setBatchSize(int batchSize);
|
||||
|
||||
/**
|
||||
* Return the current batch size.
|
||||
*/
|
||||
int getBatchSize();
|
||||
|
||||
/**
|
||||
* Specify if you want batched inserts to use getGeneratedKeys.
|
||||
* <p>
|
||||
* By default batched inserts will try to use getGeneratedKeys if it is
|
||||
* supported by the underlying jdbc driver and database.
|
||||
* </p>
|
||||
* <p>
|
||||
* You may want to turn getGeneratedKeys off when you are inserting a large
|
||||
* number of objects and you don't care about getting back the ids.
|
||||
* </p>
|
||||
*/
|
||||
void setBatchGetGeneratedKeys(boolean getGeneratedKeys);
|
||||
|
||||
/**
|
||||
* By default when mixing UpdateSql (or CallableSql) with Beans the batch is
|
||||
* automatically flushed when you change (between persisting beans and
|
||||
* executing UpdateSql or CallableSql).
|
||||
* <p>
|
||||
* If you want to execute both WITHOUT having the batch automatically flush
|
||||
* you need to call this with batchFlushOnMixed = false.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that UpdateSql and CallableSql are ALWAYS executed first (before the
|
||||
* beans are executed). This is because the UpdateSql and CallableSql have
|
||||
* already been bound to their PreparedStatements. The beans on the other hand
|
||||
* have a 2 step process (delayed binding).
|
||||
* </p>
|
||||
*/
|
||||
void setBatchFlushOnMixed(boolean batchFlushOnMixed);
|
||||
|
||||
/**
|
||||
* By default executing a query will automatically flush any batched
|
||||
* statements (persisted beans, executed UpdateSql etc).
|
||||
* <p>
|
||||
* Calling this method with batchFlushOnQuery = false means that you can
|
||||
* execute a query and the batch will not be automatically flushed.
|
||||
* </p>
|
||||
*/
|
||||
void setBatchFlushOnQuery(boolean batchFlushOnQuery);
|
||||
|
||||
/**
|
||||
* Return true if the batch (of persisted beans or executed UpdateSql etc)
|
||||
* should be flushed prior to executing a query.
|
||||
* <p>
|
||||
* The default is for this to be true.
|
||||
* </p>
|
||||
*/
|
||||
boolean isBatchFlushOnQuery();
|
||||
|
||||
/**
|
||||
* The batch will be flushing automatically but you can use this to explicitly
|
||||
* flush the batch if you like.
|
||||
* <p>
|
||||
* Flushing occurs automatically when:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>the batch size is reached</li>
|
||||
* <li>A query is executed on the same transaction</li>
|
||||
* <li>UpdateSql or CallableSql are mixed with bean save and delete</li>
|
||||
* <li>Transaction commit occurs</li>
|
||||
* <li>A getter method is called on a batched bean</li>
|
||||
* </ul>
|
||||
*/
|
||||
void flush() throws PersistenceException;
|
||||
|
||||
/**
|
||||
* This is a synonym for flush() and will be deprecated.
|
||||
* <p>
|
||||
* flush() is preferred as it matches the JPA flush() method.
|
||||
* </p>
|
||||
*/
|
||||
void flushBatch() throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Return the underlying Connection object.
|
||||
* <p>
|
||||
* Useful where a Developer wishes to use the JDBC API directly. Note that the
|
||||
* commit() rollback() and end() methods on the Transaction should still be
|
||||
* used. Calling these methods on the Connection would be a big no no unless
|
||||
* you know what you are doing.
|
||||
* </p>
|
||||
* <p>
|
||||
* Examples of when a developer may wish to use the connection directly are:
|
||||
* Savepoints, advanced CLOB BLOB use and advanced stored procedure calls.
|
||||
* </p>
|
||||
*/
|
||||
Connection getConnection();
|
||||
|
||||
/**
|
||||
* Add table modification information to the TransactionEvent.
|
||||
* <p>
|
||||
* Use this in conjunction with getConnection() and raw JDBC.
|
||||
* </p>
|
||||
* <p>
|
||||
* This effectively informs Ebean of the data that has been changed by the
|
||||
* transaction and this information is normally automatically handled by Ebean
|
||||
* when you save entity beans or use UpdateSql etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you use raw JDBC then you can use this method to inform Ebean for the
|
||||
* tables that have been modified. Ebean uses this information to keep its
|
||||
* caches in synch and maintain text indexes.
|
||||
* </p>
|
||||
*/
|
||||
void addModification(String tableName, boolean inserts, boolean updates, boolean deletes);
|
||||
|
||||
/**
|
||||
* Add an arbitrary user object to the transaction. The objects added have no
|
||||
* impact on any internals of ebean and are solely meant as a convenient
|
||||
* method push user information (although somewhat replaced by TransactionCallback).
|
||||
*/
|
||||
void putUserObject(String name, Object value);
|
||||
|
||||
/**
|
||||
* Get an object added with {@link #putUserObject(String, Object)}.
|
||||
*/
|
||||
Object getUserObject(String name);
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Provides a callback that can be registered with a Transaction.
|
||||
* <p/>
|
||||
* The callback methods are called just prior to and after the transaction performs a commit or rollback.
|
||||
* <p/>
|
||||
* A typical use of TransactionCallback would be to clean up non-transactional resources like files. For example,
|
||||
* when processing files on postCommit/postRollback clean up the associated files. As another example when
|
||||
* on postCommit of a delete remove associated resources from the file system or remote service.
|
||||
*/
|
||||
public interface TransactionCallback {
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction commit.
|
||||
*/
|
||||
void preCommit();
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction commit.
|
||||
*/
|
||||
void postCommit();
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction rollback.
|
||||
*/
|
||||
void preRollback();
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction rollback.
|
||||
*/
|
||||
void postRollback();
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Adapter that can be extended for easier implementation of TransactionCallback.
|
||||
* <p/>
|
||||
* Provides 'no operation' implementation for each of the TransactionCallback methods. It is expected that this
|
||||
* class is extended and override the methods you need to.
|
||||
*/
|
||||
public abstract class TransactionCallbackAdapter implements TransactionCallback {
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction commit.
|
||||
*/
|
||||
@Override
|
||||
public void preCommit() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction commit.
|
||||
*/
|
||||
@Override
|
||||
public void postCommit() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction rollback.
|
||||
*/
|
||||
@Override
|
||||
public void preRollback() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction rollback.
|
||||
*/
|
||||
@Override
|
||||
public void postRollback() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
}
|
||||
@@ -1,435 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.annotation.TxType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Holds the definition of how a transactional method should run.
|
||||
* <p>
|
||||
* This information matches the features of the Transactional annotation. You
|
||||
* can use it directly with Runnable or Callable via
|
||||
* {@link Ebean#execute(TxScope, Runnable)} or
|
||||
* {@link Ebean#executeCall(TxScope, Callable)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This object is used internally with the enhancement of a method with
|
||||
* Transactional annotation.
|
||||
* </p>
|
||||
*
|
||||
* @see Ebean#execute(TxScope, Runnable)
|
||||
* @see Ebean#executeCall(TxScope, Callable)
|
||||
*/
|
||||
public final class TxScope {
|
||||
|
||||
private int profileId;
|
||||
|
||||
private TxType type;
|
||||
|
||||
private String serverName;
|
||||
|
||||
private TxIsolation isolation;
|
||||
|
||||
private PersistBatch batch;
|
||||
|
||||
private PersistBatch batchOnCascade;
|
||||
|
||||
private int batchSize;
|
||||
|
||||
private boolean skipGeneratedKeys;
|
||||
|
||||
private boolean readOnly;
|
||||
|
||||
/**
|
||||
* Set this to false if the JDBC batch should not be automatically be flushed when a query is executed.
|
||||
*/
|
||||
private boolean flushOnQuery = true;
|
||||
|
||||
private boolean skipCache;
|
||||
|
||||
private String label;
|
||||
|
||||
private ArrayList<Class<? extends Throwable>> rollbackFor;
|
||||
|
||||
private ArrayList<Class<? extends Throwable>> noRollbackFor;
|
||||
|
||||
private ProfileLocation profileLocation;
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with REQUIRES.
|
||||
*/
|
||||
public static TxScope required() {
|
||||
return new TxScope(TxType.REQUIRED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with REQUIRES_NEW.
|
||||
*/
|
||||
public static TxScope requiresNew() {
|
||||
return new TxScope(TxType.REQUIRES_NEW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with MANDATORY.
|
||||
*/
|
||||
public static TxScope mandatory() {
|
||||
return new TxScope(TxType.MANDATORY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with SUPPORTS.
|
||||
*/
|
||||
public static TxScope supports() {
|
||||
return new TxScope(TxType.SUPPORTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with NOT_SUPPORTED.
|
||||
*/
|
||||
public static TxScope notSupported() {
|
||||
return new TxScope(TxType.NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with NEVER.
|
||||
*/
|
||||
public static TxScope never() {
|
||||
return new TxScope(TxType.NEVER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a REQUIRED transaction scope.
|
||||
*/
|
||||
public TxScope() {
|
||||
this.type = TxType.REQUIRED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with a given transaction scope type.
|
||||
*/
|
||||
public TxScope(TxType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes this TxScope instance.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TxScope[" + type + "] readOnly[" + readOnly + "] isolation[" + isolation
|
||||
+ "] serverName[" + serverName + "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if PersistBatch has been set.
|
||||
*/
|
||||
public boolean isBatchSet() {
|
||||
return batch != null && batch != PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if batch on cascade has been set.
|
||||
*/
|
||||
public boolean isBatchOnCascadeSet() {
|
||||
return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if batch size has been set.
|
||||
*/
|
||||
public boolean isBatchSizeSet() {
|
||||
return batchSize > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for batchSize being set without batch mode and use this to imply PersistBatch.ALL.
|
||||
*/
|
||||
public void checkBatchMode() {
|
||||
if (batchSize > 0 && notSet(batch) && notSet(batchOnCascade)) {
|
||||
// Use setting the batchSize as implying PersistBatch.ALL for @Transactional
|
||||
batch = PersistBatch.ALL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the mode is considered not set.
|
||||
*/
|
||||
private boolean notSet(PersistBatch batchMode) {
|
||||
return batchMode == null || batchMode == PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction type.
|
||||
*/
|
||||
public TxType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transaction type.
|
||||
*/
|
||||
public TxScope setType(TxType type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction profile id.
|
||||
*/
|
||||
public int getProfileId() {
|
||||
return profileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transaction profile id.
|
||||
*/
|
||||
public TxScope setProfileId(int profileId) {
|
||||
this.profileId = profileId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the profile location.
|
||||
*/
|
||||
public ProfileLocation getProfileLocation() {
|
||||
return profileLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the profile location.
|
||||
*/
|
||||
public TxScope setProfileLocation(ProfileLocation profileLocation) {
|
||||
this.profileLocation = profileLocation;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the L2 cache should be skipped for this transaction.
|
||||
*/
|
||||
public boolean isSkipCache() {
|
||||
return skipCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the transaction should skip L2 cache access.
|
||||
*/
|
||||
public TxScope setSkipCache(boolean skipCache) {
|
||||
this.skipCache = skipCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the label for the transaction.
|
||||
*/
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a label for the transaction.
|
||||
*/
|
||||
public TxScope setLabel(String label) {
|
||||
this.label = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch mode.
|
||||
*/
|
||||
public PersistBatch getBatch() {
|
||||
return batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the batch mode to use.
|
||||
*/
|
||||
public TxScope setBatch(PersistBatch batch) {
|
||||
this.batch = batch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch on cascade mode.
|
||||
*/
|
||||
public PersistBatch getBatchOnCascade() {
|
||||
return batchOnCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the batch on cascade mode.
|
||||
*/
|
||||
public TxScope setBatchOnCascade(PersistBatch batchOnCascade) {
|
||||
this.batchOnCascade = batchOnCascade;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size. 0 means use the default value.
|
||||
*/
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the batch size to use.
|
||||
*/
|
||||
public TxScope setBatchSize(int batchSize) {
|
||||
this.batchSize = batchSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the transaction should skip reading generated keys for inserts.
|
||||
*/
|
||||
public TxScope setSkipGeneratedKeys() {
|
||||
this.skipGeneratedKeys = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if getGeneratedKeys should be skipped for this transaction.
|
||||
*/
|
||||
public boolean isSkipGeneratedKeys() {
|
||||
return skipGeneratedKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the transaction should be treated as read only.
|
||||
*/
|
||||
public boolean isReadonly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the transaction should be treated as read only.
|
||||
*/
|
||||
public TxScope setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false if the JDBC batch buffer should not be flushed automatically when a query is executed.
|
||||
*/
|
||||
public boolean isFlushOnQuery() {
|
||||
return flushOnQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set flushOnQuery to be false to stop automatically flushing the JDBC batch buffer when a query is executed.
|
||||
*/
|
||||
public TxScope setFlushOnQuery(boolean flushOnQuery) {
|
||||
this.flushOnQuery = flushOnQuery;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the isolation level.
|
||||
*/
|
||||
public int getIsolationLevel() {
|
||||
return isolation != null ? isolation.getLevel() : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Isolation level this transaction should run with.
|
||||
*/
|
||||
public TxIsolation getIsolation() {
|
||||
return isolation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transaction isolation level this transaction should run with.
|
||||
*/
|
||||
public TxScope setIsolation(TxIsolation isolation) {
|
||||
this.isolation = isolation;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the serverName for this transaction. If this is null then the
|
||||
* default server (default DataSource) will be used.
|
||||
*/
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the serverName (DataSource name) for which this transaction will be. If
|
||||
* the serverName is not specified (left null) then the default server will be
|
||||
* used.
|
||||
*/
|
||||
public TxScope setServerName(String serverName) {
|
||||
this.serverName = serverName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the throwable's that should cause a rollback.
|
||||
*/
|
||||
public ArrayList<Class<? extends Throwable>> getRollbackFor() {
|
||||
return rollbackFor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Throwable that should explicitly cause a rollback.
|
||||
*/
|
||||
public TxScope setRollbackFor(Class<? extends Throwable> rollbackThrowable) {
|
||||
if (rollbackFor == null) {
|
||||
rollbackFor = new ArrayList<>(2);
|
||||
}
|
||||
rollbackFor.add(rollbackThrowable);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set multiple throwable's that will cause a rollback.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public TxScope setRollbackFor(Class<?>[] rollbackThrowables) {
|
||||
if (rollbackFor == null) {
|
||||
rollbackFor = new ArrayList<>(rollbackThrowables.length);
|
||||
}
|
||||
for (Class<?> rollbackThrowable : rollbackThrowables) {
|
||||
rollbackFor.add((Class<? extends Throwable>) rollbackThrowable);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the throwable's that should NOT cause a rollback.
|
||||
*/
|
||||
public ArrayList<Class<? extends Throwable>> getNoRollbackFor() {
|
||||
return noRollbackFor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Throwable to a list that will NOT cause a rollback. You are able to
|
||||
* call this method multiple times with different throwable's and they will
|
||||
* added to a list.
|
||||
*/
|
||||
public TxScope setNoRollbackFor(Class<? extends Throwable> noRollback) {
|
||||
if (noRollbackFor == null) {
|
||||
noRollbackFor = new ArrayList<>(2);
|
||||
}
|
||||
this.noRollbackFor.add(noRollback);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set multiple throwable's that will NOT cause a rollback.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public TxScope setNoRollbackFor(Class<?>[] noRollbacks) {
|
||||
if (noRollbackFor == null) {
|
||||
noRollbackFor = new ArrayList<>(noRollbacks.length);
|
||||
}
|
||||
for (Class<?> noRollback : noRollbacks) {
|
||||
noRollbackFor.add((Class<? extends Throwable>) noRollback);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* An Insert Update or Delete statement.
|
||||
* <p>
|
||||
* Generally a named update will be defined on the entity bean. This will take
|
||||
* the form of either an actual sql insert update delete statement or a similar
|
||||
* statement with bean name and property names in place of database table and
|
||||
* column names. The statement will likely include named parameters.
|
||||
* </p>
|
||||
* <p>
|
||||
* The following is an example of named updates on an entity bean.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* ...
|
||||
* @NamedUpdates(value = {
|
||||
* @NamedUpdate(
|
||||
* name = "setTitle",
|
||||
* notifyCache = false,
|
||||
* update = "update topic set title = :title, postCount = :count where id = :id"),
|
||||
* @NamedUpdate(
|
||||
* name = "setPostCount",
|
||||
* notifyCache = false,
|
||||
* update = "update f_topic set post_count = :postCount where id = :id"),
|
||||
* @NamedUpdate(
|
||||
* name = "incrementPostCount",
|
||||
* notifyCache = false,
|
||||
* update = "update Topic set postCount = postCount + 1 where id = :id")
|
||||
* //update = "update f_topic set post_count = post_count + 1 where id = :id")
|
||||
* })
|
||||
* @Entity
|
||||
* @Table(name = "f_topic")
|
||||
* public class Topic {
|
||||
* ...
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* The following show code that would use a named update on the Topic entity
|
||||
* bean.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Update<Topic> update = Ebean.createUpdate(Topic.class, "incrementPostCount");
|
||||
* update.setParameter("id", 1);
|
||||
* int rows = update.execute();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T> the type of entity beans inserted updated or deleted
|
||||
*/
|
||||
public interface Update<T> {
|
||||
|
||||
/**
|
||||
* Return the name if it is a named update.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Set this to false if you do not want the cache to invalidate related
|
||||
* objects.
|
||||
* <p>
|
||||
* If you don't set this Ebean will automatically invalidate the appropriate
|
||||
* parts of the "L2" server cache.
|
||||
* </p>
|
||||
*/
|
||||
Update<T> setNotifyCache(boolean notifyCache);
|
||||
|
||||
/**
|
||||
* Set a timeout for statement execution.
|
||||
* <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 timeout in seconds. Zero implies unlimited.
|
||||
*/
|
||||
Update<T> setTimeout(int secs);
|
||||
|
||||
/**
|
||||
* Execute the statement returning the number of rows modified.
|
||||
*/
|
||||
int execute();
|
||||
|
||||
/**
|
||||
* Set an ordered bind parameter.
|
||||
* <p>
|
||||
* position starts at value 1 (not 0) to be consistent with PreparedStatement.
|
||||
* </p>
|
||||
* <p>
|
||||
* Set a value for each ? you have in the sql.
|
||||
* </p>
|
||||
*
|
||||
* @param position the index position of the parameter starting with 1.
|
||||
* @param value the parameter value to bind.
|
||||
*/
|
||||
Update<T> set(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set and ordered bind parameter (same as bind).
|
||||
*
|
||||
* @param position the index position of the parameter starting with 1.
|
||||
* @param value the parameter value to bind.
|
||||
*/
|
||||
Update<T> setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set an ordered parameter that is null. The JDBC type of the null must be
|
||||
* specified.
|
||||
* <p>
|
||||
* position starts at value 1 (not 0) to be consistent with PreparedStatement.
|
||||
* </p>
|
||||
*/
|
||||
Update<T> setNull(int position, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set an ordered parameter that is null (same as bind).
|
||||
*/
|
||||
Update<T> setNullParameter(int position, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set a named parameter. Named parameters have a colon to prefix the name.
|
||||
* <p>
|
||||
* A more succinct version of setParameter() to be consistent with Query.
|
||||
* </p>
|
||||
*
|
||||
* @param name the parameter name.
|
||||
* @param value the parameter value.
|
||||
*/
|
||||
Update<T> set(String name, Object value);
|
||||
|
||||
/**
|
||||
* Bind a named parameter (same as bind).
|
||||
*/
|
||||
Update<T> setParameter(String name, Object param);
|
||||
|
||||
/**
|
||||
* Set a named parameter that is null. The JDBC type of the null must be
|
||||
* specified.
|
||||
* <p>
|
||||
* A more succinct version of setNullParameter().
|
||||
* </p>
|
||||
*
|
||||
* @param name the parameter name.
|
||||
* @param jdbcType the type of the property being bound.
|
||||
*/
|
||||
Update<T> setNull(String name, int jdbcType);
|
||||
|
||||
/**
|
||||
* Bind a named parameter that is null (same as bind).
|
||||
*/
|
||||
Update<T> setNullParameter(String name, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set a label meaning performance metrics will be collected for the execution of this update.
|
||||
*/
|
||||
Update<T> setLabel(String label);
|
||||
|
||||
/**
|
||||
* Return the sql that is actually executed.
|
||||
*/
|
||||
String getGeneratedSql();
|
||||
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* An update query typically intended to perform a bulk update of many rows that match the query.
|
||||
* <p>
|
||||
* Also note that you can also just use a raw SQL update via {@link SqlUpdate} which is pretty light and simple.
|
||||
* This UpdateQuery is more for the cases where we want to build the where expression of the update using the
|
||||
* {@link ExpressionList} "Criteria API" that is used with a normal ORM query.
|
||||
* </p>
|
||||
* <p>
|
||||
* <h4>Example: Simple update</h4>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
* <pre>{@code sql
|
||||
*
|
||||
* update o_customer set status=?, updtime=? where id > ?
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Note that if the where() clause contains a join then the SQL update changes to use a
|
||||
* <code> WHERE ID IN () </code> form.
|
||||
* </p>
|
||||
* <p>
|
||||
* <h4>Example: Update with a JOIN</h4>
|
||||
* <p>
|
||||
* In this example the expression <code>.eq("billingAddress.country", nz)</code> requires a join
|
||||
* to the address table.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
* .eq("status", Customer.Status.NEW)
|
||||
* .eq("billingAddress.country", nz)
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <pre>{@code sql
|
||||
*
|
||||
* update o_customer set status=?, updtime=?
|
||||
* where id in (
|
||||
* select t0.id c0
|
||||
* from o_customer t0
|
||||
* left join o_address t1 on t1.id = t0.billing_address_id
|
||||
* where t0.status = ?
|
||||
* and t1.country_code = ?
|
||||
* and t0.id > ? )
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T> The type of entity bean being updated
|
||||
* @see SqlUpdate
|
||||
*/
|
||||
public interface UpdateQuery<T> {
|
||||
|
||||
/**
|
||||
* Set the value of a property.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param property The bean property to be set
|
||||
* @param value The value to set the property to
|
||||
*/
|
||||
UpdateQuery<T> set(String property, Object value);
|
||||
|
||||
/**
|
||||
* Set the property to be null.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .setNull("notes")
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param property The property to be set to null.
|
||||
*/
|
||||
UpdateQuery<T> setNull(String property);
|
||||
|
||||
/**
|
||||
* Set using a property expression that does not need any bind values.
|
||||
* <p>
|
||||
* The property expression typically contains database functions.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .setRaw("status = coalesce(status, 'A')")
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyExpression A property expression
|
||||
*/
|
||||
UpdateQuery<T> setRaw(String propertyExpression);
|
||||
|
||||
/**
|
||||
* Set using a property expression that can contain <code>?</code> bind value placeholders.
|
||||
* <p>
|
||||
* For each <code>?</code> in the property expression there should be a matching bind value supplied.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* .setRaw("status = coalesce(status, ?)", Customer.Status.ACTIVE)
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
* .update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyExpression A raw property expression
|
||||
* @param values The values to bind with the property expression
|
||||
*/
|
||||
UpdateQuery<T> setRaw(String propertyExpression, Object... values);
|
||||
|
||||
/**
|
||||
* Set the profile location of this update query. This is used to relate query execution metrics
|
||||
* back to a location like a specific line of code.
|
||||
*/
|
||||
UpdateQuery<T> setProfileLocation(ProfileLocation profileLocation);
|
||||
|
||||
/**
|
||||
* Return the query expression list to add predicates to.
|
||||
*/
|
||||
ExpressionList<T> where();
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Holds two values as the result of a difference comparison.
|
||||
*/
|
||||
public class ValuePair {
|
||||
|
||||
protected Object newValue;
|
||||
|
||||
protected Object oldValue;
|
||||
|
||||
/**
|
||||
* Default constructor for JSON tools.
|
||||
*/
|
||||
public ValuePair() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with the pair of new and old values.
|
||||
*/
|
||||
public ValuePair(Object newValue, Object oldValue) {
|
||||
this.newValue = newValue;
|
||||
this.oldValue = oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the new value.
|
||||
*/
|
||||
public Object getNewValue() {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the old value.
|
||||
*/
|
||||
public Object getOldValue() {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the new value.
|
||||
*/
|
||||
public void setNewValue(Object newValue) {
|
||||
this.newValue = newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the old value.
|
||||
*/
|
||||
public void setOldValue(Object oldValue) {
|
||||
this.oldValue = oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return newValue + "," + oldValue;
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Wraps a version of a @History bean.
|
||||
*/
|
||||
public class Version<T> {
|
||||
|
||||
/**
|
||||
* The version of the bean.
|
||||
*/
|
||||
protected T bean;
|
||||
|
||||
/**
|
||||
* The effective start date time of this version.
|
||||
*/
|
||||
protected Timestamp start;
|
||||
|
||||
/**
|
||||
* The effective end date time of this version.
|
||||
*/
|
||||
protected Timestamp end;
|
||||
|
||||
/**
|
||||
* The map of changed properties.
|
||||
*/
|
||||
protected Map<String, ValuePair> diff;
|
||||
|
||||
/**
|
||||
* Construct with bean and an effective date time range.
|
||||
*/
|
||||
public Version(T bean, Timestamp start, Timestamp end) {
|
||||
this.bean = bean;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor - useful for JSON tools such as Jackson.
|
||||
*/
|
||||
public Version() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean instance for this version.
|
||||
*/
|
||||
public T getBean() {
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean instance for this version.
|
||||
*/
|
||||
public void setBean(T bean) {
|
||||
this.bean = bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the effective start date time of this version.
|
||||
*/
|
||||
public Timestamp getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the effective start date time of this version.
|
||||
*/
|
||||
public void setStart(Timestamp start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the effective end date time of this version.
|
||||
*/
|
||||
public Timestamp getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the effective end date time of this version.
|
||||
*/
|
||||
public void setEnd(Timestamp end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the map of differences from this bean to the prior version.
|
||||
*/
|
||||
public void setDiff(Map<String, ValuePair> diff) {
|
||||
this.diff = diff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the map of differences from this bean to the prior version.
|
||||
*/
|
||||
public Map<String, ValuePair> getDiff() {
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.service.SpiProfileLocationFactory;
|
||||
import io.ebean.service.SpiRawSqlService;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* Lookup internal services.
|
||||
*/
|
||||
class XServiceProvider {
|
||||
|
||||
private static SpiRawSqlService rawSqlService = initRawSql();
|
||||
|
||||
private static SpiProfileLocationFactory profileLocationFactory = initProfileLocation();
|
||||
|
||||
private static SpiRawSqlService initRawSql() {
|
||||
|
||||
Iterator<SpiRawSqlService> loader = ServiceLoader.load(SpiRawSqlService.class).iterator();
|
||||
if (loader.hasNext()) {
|
||||
return loader.next();
|
||||
}
|
||||
throw new IllegalStateException("No service implementation found for SpiRawSqlService?");
|
||||
}
|
||||
|
||||
private static SpiProfileLocationFactory initProfileLocation() {
|
||||
|
||||
Iterator<SpiProfileLocationFactory> loader = ServiceLoader.load(SpiProfileLocationFactory.class).iterator();
|
||||
if (loader.hasNext()) {
|
||||
return loader.next();
|
||||
}
|
||||
throw new IllegalStateException("No service implementation found for SpiProfileLocationFactory?");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the RawSqlService implementation.
|
||||
*/
|
||||
static SpiRawSqlService rawSql() {
|
||||
return rawSqlService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the RawSqlService implementation.
|
||||
*/
|
||||
static SpiProfileLocationFactory profileLocationFactory() {
|
||||
return profileLocationFactory;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import io.ebean.ExpressionList;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Lazy loading capable Maps, Lists and Sets.
|
||||
* <p>
|
||||
* This also includes the ability to listen for additions and removals to or
|
||||
* from the Map Set or List. The purpose of gathering the additions and removals
|
||||
* is to support persisting ManyToMany objects. The additions and removals
|
||||
* become inserts and deletes from the intersection table.
|
||||
* </p>
|
||||
* <p>
|
||||
* Technically this is <em>NOT</em> an extension of
|
||||
* <em>java.util.Collection</em>. The reason being that java.util.Map is not a
|
||||
* Collection. I realise this makes this name confusing so I apologise for that.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanCollection<E> extends Serializable {
|
||||
|
||||
enum ModifyListenMode {
|
||||
/**
|
||||
* The common mode
|
||||
*/
|
||||
NONE,
|
||||
/**
|
||||
* Mode used for PrivateOwned
|
||||
*/
|
||||
REMOVALS,
|
||||
/**
|
||||
* Mode used for ManyToMany relationships
|
||||
*/
|
||||
ALL
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the disableLazyLoad state.
|
||||
*/
|
||||
void setDisableLazyLoad(boolean disableLazyLoad);
|
||||
|
||||
/**
|
||||
* Load bean from another collection.
|
||||
*/
|
||||
void loadFrom(BeanCollection<?> other);
|
||||
|
||||
/**
|
||||
* Add a bean to the list/set with modifyListen notification.
|
||||
*/
|
||||
void addBean(E bean);
|
||||
|
||||
/**
|
||||
* Remove a bean to the list/set with modifyListen notification.
|
||||
*/
|
||||
void removeBean(E bean);
|
||||
|
||||
/**
|
||||
* Reset the collection back to an empty state ready for reloading.
|
||||
* <p>
|
||||
* This is done as part of bean refresh.
|
||||
*/
|
||||
void reset(EntityBean ownerBean, String propertyName);
|
||||
|
||||
/**
|
||||
* Return true if the collection is uninitialised or is empty without any held modifications.
|
||||
* <p>
|
||||
* Returning true means can safely skip cascade save for this bean collection.
|
||||
* </p>
|
||||
*/
|
||||
boolean isSkipSave();
|
||||
|
||||
/**
|
||||
* Return true if the collection holds modifications.
|
||||
*/
|
||||
boolean holdsModifications();
|
||||
|
||||
/**
|
||||
* Return the bean that owns this collection.
|
||||
*/
|
||||
EntityBean getOwnerBean();
|
||||
|
||||
/**
|
||||
* Return the bean property name this collection represents.
|
||||
*/
|
||||
String getPropertyName();
|
||||
|
||||
/**
|
||||
* Check after the lazy load that the underlying collection is not null
|
||||
* (handle case where join to many not outer).
|
||||
* <p>
|
||||
* That is, if the collection was not loaded due to filterMany predicates etc
|
||||
* then make sure the collection is set to empty.
|
||||
* </p>
|
||||
*/
|
||||
boolean checkEmptyLazyLoad();
|
||||
|
||||
/**
|
||||
* Return the filter (if any) that was used in building this collection.
|
||||
* <p>
|
||||
* This is so that the filter can be applied on refresh.
|
||||
* </p>
|
||||
*/
|
||||
ExpressionList<?> getFilterMany();
|
||||
|
||||
/**
|
||||
* Set the filter that was used in building this collection.
|
||||
*/
|
||||
void setFilterMany(ExpressionList<?> filterMany);
|
||||
|
||||
/**
|
||||
* Return true if the collection has been registered with the batch loading context.
|
||||
*/
|
||||
boolean isRegisteredWithLoadContext();
|
||||
|
||||
/**
|
||||
* Set the loader that will be used to lazy/query load this collection.
|
||||
* <p>
|
||||
* This is effectively the batch loading context this collection is registered with.
|
||||
* </p>
|
||||
*/
|
||||
void setLoader(BeanCollectionLoader beanLoader);
|
||||
|
||||
/**
|
||||
* Set to true if you want the BeanCollection to be treated as read only. This
|
||||
* means no elements can be added or removed etc.
|
||||
*/
|
||||
void setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Return true if the collection should be treated as readOnly and no elements
|
||||
* can be added or removed etc.
|
||||
*/
|
||||
boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Add the bean to the collection.
|
||||
* <p>
|
||||
* This is disallowed for BeanMap.
|
||||
* </p>
|
||||
*/
|
||||
void internalAdd(Object bean);
|
||||
|
||||
/**
|
||||
* Add the bean with a check to see if it is already contained.
|
||||
*/
|
||||
void internalAddWithCheck(Object bean);
|
||||
|
||||
/**
|
||||
* Return the number of elements in the List Set or Map.
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Return true if the List Set or Map is empty.
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Returns the underlying collection of beans from the Set, Map or List.
|
||||
*/
|
||||
Collection<E> getActualDetails();
|
||||
|
||||
/**
|
||||
* Returns the underlying entries so for Maps this is a collection of
|
||||
* Map.Entry.
|
||||
* <p>
|
||||
* For maps this returns the entrySet as we need the keys of the map.
|
||||
* </p>
|
||||
*/
|
||||
Collection<?> getActualEntries();
|
||||
|
||||
/**
|
||||
* return true if there are real rows held. Return false is this is using
|
||||
* Deferred fetch to lazy load the rows and the rows have not yet been
|
||||
* fetched.
|
||||
*/
|
||||
boolean isPopulated();
|
||||
|
||||
/**
|
||||
* Return true if this is a reference (lazy loading) bean collection. This is
|
||||
* the same as !isPopulated();
|
||||
*/
|
||||
boolean isReference();
|
||||
|
||||
/**
|
||||
* Set modify listening on or off. This is used to keep track of objects that
|
||||
* have been added to or removed from the list set or map.
|
||||
* <p>
|
||||
* This is required only for ManyToMany collections. The additions and
|
||||
* deletions are used to insert or delete entries from the intersection table.
|
||||
* Otherwise modifyListening is false.
|
||||
* </p>
|
||||
*/
|
||||
void setModifyListening(ModifyListenMode modifyListenMode);
|
||||
|
||||
/**
|
||||
* Return the current modify listening mode. Can be null for on newly created beans.
|
||||
*/
|
||||
ModifyListenMode getModifyListening();
|
||||
|
||||
/**
|
||||
* Add an object to the additions list.
|
||||
* <p>
|
||||
* This will potentially end up as an insert into a intersection table for a
|
||||
* ManyToMany.
|
||||
* </p>
|
||||
*/
|
||||
void modifyAddition(E bean);
|
||||
|
||||
/**
|
||||
* Add an object to the deletions list.
|
||||
* <p>
|
||||
* This will potentially end up as an delete from an intersection table for a
|
||||
* ManyToMany.
|
||||
* </p>
|
||||
*/
|
||||
void modifyRemoval(Object bean);
|
||||
|
||||
/**
|
||||
* Return the list of objects added to the list set or map. These will used to
|
||||
* insert rows into the intersection table of a ManyToMany.
|
||||
*/
|
||||
Set<E> getModifyAdditions();
|
||||
|
||||
/**
|
||||
* Return the list of objects removed from the list set or map. These will
|
||||
* used to delete rows from the intersection table of a ManyToMany.
|
||||
*/
|
||||
Set<E> getModifyRemovals();
|
||||
|
||||
/**
|
||||
* Reset the set of additions and deletions. This is called after the
|
||||
* additions and removals have been processed.
|
||||
*/
|
||||
void modifyReset();
|
||||
|
||||
/**
|
||||
* Has been modified by an addition or removal.
|
||||
*/
|
||||
boolean wasTouched();
|
||||
|
||||
/**
|
||||
* Return a shallow copy of this collection that is modifiable.
|
||||
*/
|
||||
BeanCollection<E> getShallowCopy();
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* Interface to define the addition of a bean to the underlying collection.
|
||||
* <p>
|
||||
* For maps this takes into account the map key. For List and Set this simply
|
||||
* adds the bean to the underlying list or set.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanCollectionAdd {
|
||||
|
||||
/**
|
||||
* Add a loaded bean to the collection.
|
||||
*/
|
||||
void addEntityBean(EntityBean bean);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* Loads a entity bean collection.
|
||||
* <p>
|
||||
* Typically invokes lazy loading for a single or batch of collections.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanCollectionLoader {
|
||||
|
||||
/**
|
||||
* Return the name of the associated EbeanServer.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Invoke the lazy loading for this bean collection.
|
||||
*/
|
||||
void loadMany(BeanCollection<?> collection, boolean onlyIds);
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* Visitor for collecting new/old values for a bean update.
|
||||
*/
|
||||
public interface BeanDiffVisitor {
|
||||
|
||||
/**
|
||||
* Collect a new/old value pair.
|
||||
*/
|
||||
void visit(int position, Object newVal, Object oldVal);
|
||||
|
||||
/**
|
||||
* Start processing an associated bean.
|
||||
*/
|
||||
void visitPush(int position);
|
||||
|
||||
/**
|
||||
* Stop processing an associated bean.
|
||||
*/
|
||||
void visitPop();
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* Loads a entity bean.
|
||||
* <p>
|
||||
* Typically invokes lazy loading for a single or batch of entity beans.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanLoader {
|
||||
|
||||
/**
|
||||
* Return the name of the associated EbeanServer.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Invoke the lazy loading for this bean.
|
||||
*/
|
||||
void loadBean(EntityBeanIntercept ebi);
|
||||
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Represent the call stack (stack trace elements).
|
||||
* <p>
|
||||
* Used with a query to identify a CallStackQuery for AutoTune automatic query
|
||||
* tuning.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is used so that a single query called from different methods can be
|
||||
* tuned for each different call stack.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note the call stack is trimmed to remove the common ebean internal elements.
|
||||
* </p>
|
||||
*/
|
||||
public final class CallStack implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8590644046907438579L;
|
||||
|
||||
private final String zeroHash;
|
||||
private final String pathHash;
|
||||
|
||||
private final StackTraceElement[] callStack;
|
||||
|
||||
private final int hc;
|
||||
|
||||
public CallStack(StackTraceElement[] callStack, int zeroHash, int pathHash) {
|
||||
this.callStack = callStack;
|
||||
this.zeroHash = enc(zeroHash);
|
||||
this.pathHash = enc(pathHash);
|
||||
this.hc = computeHashCode();
|
||||
}
|
||||
|
||||
private int computeHashCode() {
|
||||
int hc = 0;
|
||||
for (StackTraceElement aCallStack : callStack) {
|
||||
hc = 92821 * hc + aCallStack.hashCode();
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof CallStack)) {
|
||||
return false;
|
||||
}
|
||||
CallStack e = (CallStack) obj;
|
||||
return Arrays.equals(callStack, e.callStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first element of the call stack.
|
||||
*/
|
||||
public StackTraceElement getFirstStackTraceElement() {
|
||||
return callStack[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the call stack.
|
||||
*/
|
||||
public StackTraceElement[] getCallStack() {
|
||||
return callStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash for the first stack element.
|
||||
*/
|
||||
public String getZeroHash() {
|
||||
return zeroHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash for the stack elements (excluding first stack element).
|
||||
*/
|
||||
public String getPathHash() {
|
||||
return pathHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return zeroHash + ":" + pathHash + ":" + callStack[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the call stack lines appended with the given newLine string.
|
||||
*/
|
||||
public String description(String newLine) {
|
||||
StringBuilder sb = new StringBuilder(400);
|
||||
for (StackTraceElement aCallStack : callStack) {
|
||||
sb.append(aCallStack.toString()).append(newLine);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getOriginKey(int queryHash) {
|
||||
return enc(queryHash) + "." + zeroHash + "." + pathHash;
|
||||
}
|
||||
|
||||
private static final int radix = 1 << 6;
|
||||
private static final int mask = radix - 1;
|
||||
|
||||
/**
|
||||
* Convert the integer to unsigned base 64.
|
||||
*/
|
||||
public static String enc(int i) {
|
||||
char[] buf = new char[32];
|
||||
int charPos = 32;
|
||||
do {
|
||||
buf[--charPos] = intToBase64[i & mask];
|
||||
i >>>= 6;
|
||||
} while (i != 0);
|
||||
|
||||
return new String(buf, charPos, (32 - charPos));
|
||||
}
|
||||
|
||||
private static final char intToBase64[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
|
||||
};
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* Marker interface for classes enhanced to support Transactional methods.
|
||||
*/
|
||||
public interface EnhancedTransactional {
|
||||
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Bean that is aware of EntityBeanIntercept.
|
||||
* <p>
|
||||
* This interface and implementation of these methods is added to Entity Beans
|
||||
* via instrumentation. These methods have a funny _ebean_ prefix to avoid any
|
||||
* clash with normal methods these beans would have. These methods are not for
|
||||
* general application consumption.
|
||||
* </p>
|
||||
*/
|
||||
public interface EntityBean extends Serializable {
|
||||
|
||||
/**
|
||||
* Return all the property names in defined order.
|
||||
*/
|
||||
String[] _ebean_getPropertyNames();
|
||||
|
||||
/**
|
||||
* Return the property name at the given position.
|
||||
*/
|
||||
String _ebean_getPropertyName(int pos);
|
||||
|
||||
/**
|
||||
* Return the enhancement marker value.
|
||||
* <p>
|
||||
* This is the class name of the enhanced class and used to check that all
|
||||
* entity classes are enhanced (specifically not just a super class).
|
||||
* </p>
|
||||
*/
|
||||
String _ebean_getMarker();
|
||||
|
||||
/**
|
||||
* Create and return a new entity bean instance.
|
||||
*/
|
||||
Object _ebean_newInstance();
|
||||
|
||||
/**
|
||||
* Generated method that sets the loaded state on all the embedded beans on
|
||||
* this entity bean by using EntityBeanIntercept.setEmbeddedLoaded(Object o);
|
||||
*/
|
||||
void _ebean_setEmbeddedLoaded();
|
||||
|
||||
/**
|
||||
* Return true if any embedded beans are new or dirty.
|
||||
*/
|
||||
boolean _ebean_isEmbeddedNewOrDirty();
|
||||
|
||||
/**
|
||||
* Return the intercept for this object.
|
||||
*/
|
||||
EntityBeanIntercept _ebean_getIntercept();
|
||||
|
||||
/**
|
||||
* Similar to _ebean_getIntercept() except it checks to see if the intercept
|
||||
* field is null and will create it if required.
|
||||
* <p>
|
||||
* This is really only required when transientInternalFields=true as an
|
||||
* enhancement option. In this case the intercept field is transient and will
|
||||
* be null after a bean has been deserialised.
|
||||
* </p>
|
||||
* <p>
|
||||
* This transientInternalFields=true option was to support some serialization
|
||||
* frameworks that can't take into account our ebean fields.
|
||||
* </p>
|
||||
*/
|
||||
EntityBeanIntercept _ebean_intercept();
|
||||
|
||||
/**
|
||||
* Set the value of a field of an entity bean of this type.
|
||||
* <p>
|
||||
* Note that using this method bypasses any interception that otherwise occurs
|
||||
* on entity beans. That means lazy loading and oldValues creation.
|
||||
* </p>
|
||||
*/
|
||||
void _ebean_setField(int fieldIndex, Object value);
|
||||
|
||||
/**
|
||||
* Set the field value with interception.
|
||||
*/
|
||||
void _ebean_setFieldIntercept(int fieldIndex, Object value);
|
||||
|
||||
/**
|
||||
* Return the value of a field from an entity bean of this type.
|
||||
* <p>
|
||||
* Note that using this method bypasses any interception that otherwise occurs
|
||||
* on entity beans. That means lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
Object _ebean_getField(int fieldIndex);
|
||||
|
||||
/**
|
||||
* Return the field value with interception.
|
||||
*/
|
||||
Object _ebean_getFieldIntercept(int fieldIndex);
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,127 +0,0 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Collects profile information for a bean (or reference/proxy bean) at a given node.
|
||||
* <p>
|
||||
* The node identifies the location of the bean in the object graph.
|
||||
* </p>
|
||||
* <p>
|
||||
* It has to use a weak reference so as to ensure that it does not stop the
|
||||
* associated bean from being garbage collected.
|
||||
* </p>
|
||||
*/
|
||||
public final class NodeUsageCollector {
|
||||
|
||||
/**
|
||||
* The point in the object graph for a specific query and call stack point.
|
||||
*/
|
||||
private final ObjectGraphNode node;
|
||||
|
||||
/**
|
||||
* Weak to allow garbage collection.
|
||||
*/
|
||||
private final WeakReference<NodeUsageListener> managerRef;
|
||||
|
||||
/**
|
||||
* The properties used at this profile point.
|
||||
*/
|
||||
private final Set<String> used = new LinkedHashSet<>();
|
||||
|
||||
/**
|
||||
* set to true if the bean is modified (setter called)
|
||||
*/
|
||||
private boolean modified;
|
||||
|
||||
/**
|
||||
* The property that cause a reference to lazy load.
|
||||
*/
|
||||
private String loadProperty;
|
||||
|
||||
public NodeUsageCollector(ObjectGraphNode node, WeakReference<NodeUsageListener> managerRef) {
|
||||
this.node = node;
|
||||
// weak to allow garbage collection.
|
||||
this.managerRef = managerRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bean has been modified by a setter method.
|
||||
*/
|
||||
public void setModified() {
|
||||
modified = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the name of a property that has been used.
|
||||
*/
|
||||
public void addUsed(String property) {
|
||||
used.add(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* The property that invoked a lazy load.
|
||||
*/
|
||||
public void setLoadProperty(String loadProperty) {
|
||||
this.loadProperty = loadProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish the usage info to the manager.
|
||||
*/
|
||||
private void publishUsageInfo() {
|
||||
NodeUsageListener manager = managerRef.get();
|
||||
if (manager != null) {
|
||||
manager.collectNodeUsage(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* publish the collected usage information when garbage collection occurs.
|
||||
*/
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
publishUsageInfo();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated node which identifies the location in the object
|
||||
* graph of the bean/reference.
|
||||
*/
|
||||
public ObjectGraphNode getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if no properties where used.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return used.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of used properties.
|
||||
*/
|
||||
public Set<String> getUsed() {
|
||||
return used;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the bean was modified by a setter.
|
||||
*/
|
||||
public boolean isModified() {
|
||||
return modified;
|
||||
}
|
||||
|
||||
public String getLoadProperty() {
|
||||
return loadProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return node + " read:" + used + " modified:" + modified;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* Collects the profile information.
|
||||
*/
|
||||
public interface NodeUsageListener {
|
||||
|
||||
/**
|
||||
* Collect node usage "profiling" information.
|
||||
* <p>
|
||||
* This is the properties that are used for a given bean in the object graph.
|
||||
* This information is used by autoTune to tune queries.
|
||||
* </p>
|
||||
*/
|
||||
void collectNodeUsage(NodeUsageCollector collector);
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Identifies a unique node of an object graph.
|
||||
* <p>
|
||||
* It represents a location relative to the root of an object graph and specific
|
||||
* to a query and call stack hash.
|
||||
* </p>
|
||||
*/
|
||||
public final class ObjectGraphNode implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2087081778650228996L;
|
||||
|
||||
/**
|
||||
* Identifies the origin.
|
||||
*/
|
||||
private final ObjectGraphOrigin originQueryPoint;
|
||||
|
||||
/**
|
||||
* The path relative to the root.
|
||||
*/
|
||||
private final String path;
|
||||
|
||||
/**
|
||||
* Create at a sub level.
|
||||
*/
|
||||
public ObjectGraphNode(ObjectGraphNode parent, String path) {
|
||||
this.originQueryPoint = parent.getOriginQueryPoint();
|
||||
this.path = parent.getChildPath(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an the root level.
|
||||
*/
|
||||
public ObjectGraphNode(ObjectGraphOrigin originQueryPoint, String path) {
|
||||
this.originQueryPoint = originQueryPoint;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the origin query point.
|
||||
*/
|
||||
public ObjectGraphOrigin getOriginQueryPoint() {
|
||||
return originQueryPoint;
|
||||
}
|
||||
|
||||
private String getChildPath(String childPath) {
|
||||
if (path == null) {
|
||||
return childPath;
|
||||
} else if (childPath == null) {
|
||||
return path;
|
||||
} else {
|
||||
return path + "." + childPath;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path relative to the root.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "origin:" + originQueryPoint + " path[" + path + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc = 92821 * originQueryPoint.hashCode();
|
||||
hc = 92821 * hc + (path == null ? 0 : path.hashCode());
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof ObjectGraphNode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectGraphNode e = (ObjectGraphNode) obj;
|
||||
//noinspection StringEquality
|
||||
return ((e.path == path) || (e.path != null && e.path.equals(path)))
|
||||
&& e.originQueryPoint.equals(originQueryPoint);
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Represents a "origin" of an ORM object graph. This combines the call stack
|
||||
* and query plan hash.
|
||||
* <p>
|
||||
* The call stack is included so that the query can have different tuned fetches
|
||||
* for each unique call stack. For example, a query to fetch a customer could be
|
||||
* called by three different methods and each can be treated as a separate
|
||||
* origin point (and autoTune can tune each one separately).
|
||||
* </p>
|
||||
*/
|
||||
public final class ObjectGraphOrigin implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 410937765287968708L;
|
||||
|
||||
private final CallStack callStack;
|
||||
|
||||
private final String beanType;
|
||||
|
||||
private final int queryHash;
|
||||
|
||||
private final String key;
|
||||
|
||||
public ObjectGraphOrigin(int queryHash, CallStack callStack, String beanType) {
|
||||
this.callStack = callStack;
|
||||
this.beanType = beanType;
|
||||
this.queryHash = queryHash;
|
||||
this.key = callStack.getOriginKey(queryHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* The key includes the queryPlan hash and the callStack hash. This becomes
|
||||
* the unique identifier for a query point.
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of bean the query is fetching.
|
||||
*/
|
||||
public String getBeanType() {
|
||||
return beanType;
|
||||
}
|
||||
|
||||
/**
|
||||
* The call stack involved.
|
||||
*/
|
||||
public CallStack getCallStack() {
|
||||
return callStack;
|
||||
}
|
||||
|
||||
public String getFirstStackElement() {
|
||||
return callStack.getFirstStackTraceElement().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "key[" + key + "] type[" + beanType + "] " + callStack.getFirstStackTraceElement() + " ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc = 92821 * callStack.hashCode();
|
||||
hc = 92821 * hc + beanType.hashCode();
|
||||
hc = 92821 * hc + queryHash;
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof ObjectGraphOrigin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectGraphOrigin e = (ObjectGraphOrigin) obj;
|
||||
return e.queryHash == queryHash
|
||||
&& e.beanType.equals(beanType)
|
||||
&& e.callStack.equals(callStack);
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* Holds entity beans by there type and id.
|
||||
* <p>
|
||||
* This is used to ensure only one instance for a given entity type and id is
|
||||
* used to build object graphs from queries and lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
public interface PersistenceContext {
|
||||
|
||||
/**
|
||||
* Put the entity bean into the PersistenceContext.
|
||||
*/
|
||||
void put(Class<?> rootType, Object id, Object bean);
|
||||
|
||||
/**
|
||||
* Put the entity bean into the PersistenceContext if one is not already
|
||||
* present (for this id).
|
||||
* <p>
|
||||
* Returns an existing entity bean (if one is already there) and otherwise
|
||||
* returns null.
|
||||
* </p>
|
||||
*/
|
||||
Object putIfAbsent(Class<?> rootType, Object id, Object bean);
|
||||
|
||||
/**
|
||||
* Return an object given its type and unique id.
|
||||
*/
|
||||
Object get(Class<?> rootType, Object uid);
|
||||
|
||||
/**
|
||||
* Get the bean from the persistence context also checked to see if it had
|
||||
* been previously deleted (if so then you also can't hit the L2 cache to
|
||||
* fetch the bean for this particular persistence context).
|
||||
*/
|
||||
WithOption getWithOption(Class<?> rootType, Object uid);
|
||||
|
||||
/**
|
||||
* Clear all the references.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Clear all the references for a given type of entity bean.
|
||||
*/
|
||||
void clear(Class<?> rootType);
|
||||
|
||||
/**
|
||||
* Clear the reference to a specific entity bean.
|
||||
*/
|
||||
void clear(Class<?> rootType, Object uid);
|
||||
|
||||
/**
|
||||
* Clear the reference as a result of an entity being deleted.
|
||||
*/
|
||||
void deleted(Class<?> rootType, Object id);
|
||||
|
||||
/**
|
||||
* Return the number of beans of the given type in the persistence context.
|
||||
*/
|
||||
int size(Class<?> rootType);
|
||||
|
||||
/**
|
||||
* Wrapper on a bean to also indicate if a bean has been deleted.
|
||||
* <p>
|
||||
* If a bean has been deleted then for the same persistence context is should
|
||||
* not be able to be fetched from persistence context or L2 cache.
|
||||
* </p>
|
||||
*/
|
||||
class WithOption {
|
||||
|
||||
/**
|
||||
* The bean was previously deleted from this persistence context (can't hit
|
||||
* L2 cache).
|
||||
*/
|
||||
public static final WithOption DELETED = new WithOption();
|
||||
|
||||
private final boolean deleted;
|
||||
private final Object bean;
|
||||
|
||||
private WithOption() {
|
||||
this.deleted = true;
|
||||
this.bean = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bean exists in the persistence context (and not been previously deleted).
|
||||
*/
|
||||
public WithOption(Object bean) {
|
||||
this.deleted = false;
|
||||
this.bean = bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the bean was deleted. This means you can't hit the L2
|
||||
* cache.
|
||||
*/
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean (from the persistence context).
|
||||
*/
|
||||
public Object getBean() {
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* A callback that can be registered to fire on getter method calls.
|
||||
* It's primary purpose is to automatically flush JDBC batch buffer.
|
||||
*/
|
||||
public interface PreGetterCallback {
|
||||
|
||||
/**
|
||||
* Trigger the callback based on a getter on a property.
|
||||
*
|
||||
* @param propertyIndex The index of the property
|
||||
*/
|
||||
void preGetterTrigger(int propertyIndex);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
|
||||
<TITLE>Enhanced beans API and Support objects</TITLE>
|
||||
</HEAD>
|
||||
<Body BGCOLOR="#ffffff">
|
||||
Enhanced beans API and Support objects
|
||||
|
||||
|
||||
</Body>
|
||||
</HTML>
|
||||
@@ -1,54 +0,0 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* For query cache entries we additionally hold the dependent tables and timestamp for the query result.
|
||||
* <p>
|
||||
* We use the dependent tables and timestamp to validate that tables the query joins to have not been
|
||||
* modified since the query cache entry was cached. If any dependent tables have since been modified
|
||||
* the query cache entry is treated as invalid.
|
||||
* </p>
|
||||
*/
|
||||
public class QueryCacheEntry {
|
||||
|
||||
private final Object value;
|
||||
|
||||
private final Set<String> dependentTables;
|
||||
|
||||
private final long timestamp;
|
||||
|
||||
/**
|
||||
* Create with dependent tables and timestamp.
|
||||
*
|
||||
* @param value The query result being cached
|
||||
* @param dependentTables The extra tables the query is dependent on (joins to)
|
||||
* @param timestamp The timestamp that the query uses to check for modifications
|
||||
*/
|
||||
public QueryCacheEntry(Object value, Set<String> dependentTables, long timestamp) {
|
||||
this.value = value;
|
||||
this.dependentTables = dependentTables;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual query result.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tables the query result is dependent on.
|
||||
*/
|
||||
public Set<String> getDependentTables() {
|
||||
return dependentTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the timestamp used to check for modifications on the dependent tables.
|
||||
*/
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
/**
|
||||
* Used to validate that a query cache entry is still valid based on dependent tables.
|
||||
*/
|
||||
public interface QueryCacheEntryValidate {
|
||||
|
||||
/**
|
||||
* Return true if the entry is still valid based on dependent tables.
|
||||
*/
|
||||
boolean isValid(QueryCacheEntry queryCacheEntry);
|
||||
}
|
||||
-82
@@ -1,82 +0,0 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents part of the "L2" server side cache.
|
||||
* <p>
|
||||
* This is used to cache beans or query results (bean collections).
|
||||
* </p>
|
||||
* <p>
|
||||
* There are 2 ServerCache's for each bean type. One is used as the 'bean cache'
|
||||
* which holds beans of a given type. The other is the 'query cache' holding
|
||||
* query results for a given type.
|
||||
* </p>
|
||||
*/
|
||||
public interface ServerCache {
|
||||
|
||||
default Map<Object, Object> getAll(Set<Object> keys) {
|
||||
|
||||
Map<Object, Object> map = new LinkedHashMap<>();
|
||||
for (Object key : keys) {
|
||||
Object value = get(key);
|
||||
if (value != null) {
|
||||
map.put(key, value);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value given the key.
|
||||
*/
|
||||
Object get(Object id);
|
||||
|
||||
/**
|
||||
* Put all the values in the cache.
|
||||
*/
|
||||
default void putAll(Map<Object, Object> keyValues) {
|
||||
keyValues.forEach(this::put);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the value in the cache with a given id.
|
||||
*/
|
||||
void put(Object id, Object value);
|
||||
|
||||
/**
|
||||
* Remove the entries from the cache given the id values.
|
||||
*/
|
||||
default void removeAll(Set<Object> keys) {
|
||||
keys.forEach(this::remove);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a entry from the cache given its id.
|
||||
*/
|
||||
void remove(Object id);
|
||||
|
||||
/**
|
||||
* Clear all entries from the cache.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Return the number of entries in the cache.
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Return the hit ratio the cache is currently getting.
|
||||
*/
|
||||
int getHitRatio();
|
||||
|
||||
/**
|
||||
* Return statistics for the cache.
|
||||
*
|
||||
* @param reset if true the statistics are reset.
|
||||
*/
|
||||
ServerCacheStatistics getStatistics(boolean reset);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
import io.ebean.config.CurrentTenantProvider;
|
||||
|
||||
/**
|
||||
* Configuration used to create ServerCache instances.
|
||||
*/
|
||||
public class ServerCacheConfig {
|
||||
|
||||
private final ServerCacheType type;
|
||||
private final String cacheKey;
|
||||
private final ServerCacheOptions cacheOptions;
|
||||
private final CurrentTenantProvider tenantProvider;
|
||||
private final QueryCacheEntryValidate queryCacheEntryValidate;
|
||||
|
||||
public ServerCacheConfig(ServerCacheType type, String cacheKey, ServerCacheOptions cacheOptions, CurrentTenantProvider tenantProvider, QueryCacheEntryValidate queryCacheEntryValidate) {
|
||||
this.type = type;
|
||||
this.cacheKey = cacheKey;
|
||||
this.cacheOptions = cacheOptions;
|
||||
this.tenantProvider = tenantProvider;
|
||||
this.queryCacheEntryValidate = queryCacheEntryValidate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache type.
|
||||
*/
|
||||
public ServerCacheType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the cache.
|
||||
*/
|
||||
public String getCacheKey() {
|
||||
return cacheKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tuning options.
|
||||
*/
|
||||
public ServerCacheOptions getCacheOptions() {
|
||||
return cacheOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current tenant provider.
|
||||
*/
|
||||
public CurrentTenantProvider getTenantProvider() {
|
||||
return tenantProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the service that provides validation for query cache entries.
|
||||
*/
|
||||
public QueryCacheEntryValidate getQueryCacheEntryValidate() {
|
||||
return queryCacheEntryValidate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the cache is a query cache.
|
||||
*/
|
||||
public boolean isQueryCache() {
|
||||
return type == ServerCacheType.QUERY;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
/**
|
||||
* Defines method for constructing caches for beans and queries.
|
||||
*/
|
||||
public interface ServerCacheFactory {
|
||||
|
||||
/**
|
||||
* Create the cache for the given type with options.
|
||||
*/
|
||||
ServerCache createCache(ServerCacheConfig config);
|
||||
|
||||
/**
|
||||
* Return a ServerCacheNotify that we will send ServerCacheNotification events to.
|
||||
* <p>
|
||||
* This is used if a ServerCacheNotifyPlugin is not supplied.
|
||||
* </p>
|
||||
*
|
||||
* @param listener The listener that should be used to process the notification events.
|
||||
*/
|
||||
ServerCacheNotify createCacheNotify(ServerCacheNotify listener);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user