mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
39
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3656091d1f | ||
|
|
5122ea4b4d | ||
|
|
db8dd48e53 | ||
|
|
4606c7c99f | ||
|
|
e3a7c3040b | ||
|
|
cb51ea4238 | ||
|
|
a1a48dac2c | ||
|
|
b8d9273152 | ||
|
|
026f0e161f | ||
|
|
75a2633590 | ||
|
|
362ceea79b | ||
|
|
1c9b974427 | ||
|
|
f181e3946f | ||
|
|
6df145b4fa | ||
|
|
a4cb116d4f | ||
|
|
3161664d58 | ||
|
|
4b3f63f6e0 | ||
|
|
d89b1b0367 | ||
|
|
17433bb70b | ||
|
|
fb6ea92ae9 | ||
|
|
08b0a6350d | ||
|
|
bd330b4c0e | ||
|
|
ec234f1f39 | ||
|
|
dd28b28095 | ||
|
|
2a5be6db3d | ||
|
|
545f40703e | ||
|
|
35d0481644 | ||
|
|
2282ff3c6e | ||
|
|
d1d4bf1da8 | ||
|
|
8c6653605d | ||
|
|
e344b5c0a1 | ||
|
|
0e5859716b | ||
|
|
90a794fca5 | ||
|
|
1d6e480402 | ||
|
|
54706302df | ||
|
|
4a59cf4c3d | ||
|
|
8cb8f9eabf | ||
|
|
58a36e6b67 | ||
|
|
064d282f7b |
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>7.11.2</version>
|
||||
<version>7.11.4</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git</developerConnection>
|
||||
<tag>avaje-ebeanorm-7.11.2</tag>
|
||||
<tag>avaje-ebeanorm-7.11.4</tag>
|
||||
</scm>
|
||||
|
||||
<dependencies>
|
||||
@@ -78,6 +78,12 @@
|
||||
<version>2.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-dbmigration</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
@@ -162,7 +168,7 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-agent</artifactId>
|
||||
<version>4.9.2</version>
|
||||
<version>4.10.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -237,7 +243,7 @@
|
||||
<plugin>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
|
||||
<version>4.9.2</version>
|
||||
<version>4.10.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
|
||||
@@ -1304,13 +1304,19 @@ public interface Query<T> {
|
||||
Query<T> setMapKey(String mapKey);
|
||||
|
||||
/**
|
||||
* Set this to true to use the bean cache.
|
||||
* Set this to false to not use the bean cache.
|
||||
* <p>
|
||||
* If the query result is in cache then by default this same instance is
|
||||
* returned. In this sense it should be treated as a read only object graph.
|
||||
* By default "find by id" and "find by natural key" will use the bean cache
|
||||
* when bean caching is enabled. Setting this to false means that the query
|
||||
* will not use the bean cache and instead hit the database.
|
||||
* </p>
|
||||
* <p>
|
||||
* In the case of other queries (findList(), findEach() etc) then setting this to
|
||||
* false beans that the if lazy loading is invoked that lazy loading will not try
|
||||
* to use the bean cache.
|
||||
* </p>
|
||||
*/
|
||||
Query<T> setUseCache(boolean useBeanCache);
|
||||
Query<T> setUseCache(boolean useCache);
|
||||
|
||||
/**
|
||||
* Set this to true to use the query cache.
|
||||
|
||||
@@ -36,6 +36,8 @@ public final class TxScope {
|
||||
|
||||
int batchSize;
|
||||
|
||||
boolean skipGeneratedKeys;
|
||||
|
||||
boolean readOnly;
|
||||
|
||||
ArrayList<Class<? extends Throwable>> rollbackFor;
|
||||
@@ -188,6 +190,21 @@ public final class TxScope {
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,11 @@ public @interface Cache {
|
||||
* set this to false on a bean type that we want to use query caching but no
|
||||
* bean caching (and this is expected to be a rare case).
|
||||
* </p>
|
||||
* <p>
|
||||
* When bean caching is enabled by default "find by id" and "find by unique natural key"
|
||||
* queries will try to use the bean cache. We use {@link com.avaje.ebean.Query#setUseCache(boolean)}
|
||||
* with <code>false</code> for the case when we do NOT want to use the bean cache.
|
||||
* </p>
|
||||
*/
|
||||
boolean enableBeanCache() default true;
|
||||
|
||||
|
||||
@@ -90,6 +90,16 @@ public @interface Transactional {
|
||||
*/
|
||||
int batchSize() default 0;
|
||||
|
||||
/**
|
||||
* Set to false when we want to skip getting generatedKeys.
|
||||
* <p>
|
||||
* This is typically used in the case of large batch inserts where we get a
|
||||
* performance benefit from not calling getGeneratedKeys (as we are going to
|
||||
* insert a lot of rows and have no need for the Id values after the insert).
|
||||
* </p>
|
||||
*/
|
||||
boolean getGeneratedKeys() default true;
|
||||
|
||||
/**
|
||||
* The transaction isolation level this transaction should have.
|
||||
* <p>
|
||||
|
||||
@@ -54,10 +54,12 @@ public interface BeanCollection<E> extends Serializable {
|
||||
void reset(EntityBean ownerBean, String propertyName);
|
||||
|
||||
/**
|
||||
* Return true if the collection is empty and untouched. Used to detect if a
|
||||
* collection was 'cleared' deliberately or just un-initialised.
|
||||
* 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 isEmptyAndUntouched();
|
||||
boolean isSkipSave();
|
||||
|
||||
/**
|
||||
* Return the bean that owns this collection.
|
||||
@@ -92,11 +94,6 @@ public interface BeanCollection<E> extends Serializable {
|
||||
*/
|
||||
void setFilterMany(ExpressionList<?> filterMany);
|
||||
|
||||
/**
|
||||
* Set a listener to be notified when the BeanCollection is first touched.
|
||||
*/
|
||||
void setBeanCollectionTouched(BeanCollectionTouched notify);
|
||||
|
||||
/**
|
||||
* Return true if the collection has been registered with the batch loading context.
|
||||
*/
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Used to specify a listener to be notified when a BeanCollection is first
|
||||
* used.
|
||||
* <p>
|
||||
* To use this you can set a BeanCollectionTouched onto a BeanCollection before
|
||||
* it has been used. When the BeanCollection is first used by the client code
|
||||
* then the BeanCollectionTouched is notified. It can only be notified once.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface BeanCollectionTouched {
|
||||
|
||||
/**
|
||||
* Notify the listener that the bean collection has been used.
|
||||
*/
|
||||
void notifyTouched(BeanCollection<?> c);
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.ExpressionList;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.BeanCollectionTouched;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Base class for List Set and Map implementations of BeanCollection.
|
||||
*
|
||||
@@ -36,8 +34,6 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
protected String ebeanServerName;
|
||||
|
||||
protected transient BeanCollectionTouched beanCollectionTouched;
|
||||
|
||||
/**
|
||||
* The owning bean (used for lazy fetch).
|
||||
*/
|
||||
@@ -55,12 +51,6 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
protected boolean modifyRemoveListening;
|
||||
protected boolean modifyListening;
|
||||
|
||||
/**
|
||||
* Flag used to tell if empty collections have been cleared etc or just
|
||||
* uninitialised.
|
||||
*/
|
||||
protected boolean touched;
|
||||
|
||||
/**
|
||||
* Constructor not non-lazy loading collection.
|
||||
*/
|
||||
@@ -109,25 +99,6 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
checkEmptyLazyLoad();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touched. If setFlag is false then typically an isEmpty() call and still
|
||||
* considering that to be untouched.
|
||||
*/
|
||||
protected void touched(boolean setFlag) {
|
||||
if (setFlag) {
|
||||
touched = true;
|
||||
}
|
||||
if (beanCollectionTouched != null) {
|
||||
// only call this once
|
||||
beanCollectionTouched.notifyTouched(this);
|
||||
beanCollectionTouched = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setBeanCollectionTouched(BeanCollectionTouched notify) {
|
||||
this.beanCollectionTouched = notify;
|
||||
}
|
||||
|
||||
public boolean isRegisteredWithLoadContext() {
|
||||
return registeredWithLoadContext;
|
||||
}
|
||||
@@ -219,4 +190,11 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
return modifyHolder.getModifyRemovals();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are underlying additions or removals.
|
||||
*/
|
||||
public boolean holdsModifications() {
|
||||
return modifyHolder != null && modifyHolder.hasModifications();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,12 +52,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.list = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (list == null || list.isEmpty());
|
||||
public boolean isSkipSave() {
|
||||
return list == null || (list.isEmpty() && !holdsModifications());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -109,24 +108,14 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
list = new ArrayList<E>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (list == null) {
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +285,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
init();
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@@ -45,11 +45,10 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.map = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (map == null || map.isEmpty());
|
||||
public boolean isSkipSave() {
|
||||
return map == null || (map.isEmpty() && !holdsModifications());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,24 +124,14 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
map = new LinkedHashMap<K, E>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (map == null) {
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +238,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
init();
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@@ -46,11 +46,10 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.set = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (set == null || set.isEmpty());
|
||||
public boolean isSkipSave() {
|
||||
return set == null || (set.isEmpty() && !holdsModifications());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -117,24 +116,14 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
set = new LinkedHashSet<E>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (set == null) {
|
||||
lazyLoadCollection(true);
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,7 +249,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
init();
|
||||
return set.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@@ -71,4 +71,11 @@ class ModifyHolder<E> implements Serializable {
|
||||
Set<E> getModifyRemovals() {
|
||||
return modifyDeletions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there additions or removals.
|
||||
*/
|
||||
boolean hasModifications() {
|
||||
return !modifyDeletions.isEmpty() || !modifyAdditions.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.avaje.ebean.config;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformName;
|
||||
import com.avaje.ebean.dbmigration.DbMigration;
|
||||
import org.avaje.dbmigration.MigrationConfig;
|
||||
import org.avaje.dbmigration.MigrationRunner;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -97,7 +99,7 @@ public class DbMigrationConfig {
|
||||
/**
|
||||
* DB user used to run the DB migration.
|
||||
*/
|
||||
protected String dbUser;
|
||||
protected String dbUsername;
|
||||
|
||||
/**
|
||||
* DB password used to run the DB migration.
|
||||
@@ -242,14 +244,6 @@ public class DbMigrationConfig {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the model, rollback and drop paths to be empty such that all the migration files are generated
|
||||
* into a single directory.
|
||||
*/
|
||||
public void singleDirectory() {
|
||||
this.modelPath = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the table name that holds the migration run details
|
||||
* (used by DB Migration runner only).
|
||||
@@ -323,22 +317,22 @@ public class DbMigrationConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB user to use for running DB migrations.
|
||||
* Return the DB username to use for running DB migrations.
|
||||
*/
|
||||
public String getDbUser() {
|
||||
public String getDbUsername() {
|
||||
// environment properties take precedence
|
||||
String user = readEnvironment("ddl.migration.user");
|
||||
if (user != null) {
|
||||
return user;
|
||||
}
|
||||
return dbUser;
|
||||
return dbUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB user to use for running DB migrations.
|
||||
* Set the DB username to use for running DB migrations.
|
||||
*/
|
||||
public void setDbUser(String dbUser) {
|
||||
this.dbUser = dbUser;
|
||||
public void setDbUsername(String dbUsername) {
|
||||
this.dbUsername = dbUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -365,11 +359,7 @@ public class DbMigrationConfig {
|
||||
public void loadSettings(PropertiesWrapper properties, String serverName) {
|
||||
|
||||
migrationPath = properties.get("migration.migrationPath", migrationPath);
|
||||
if (properties.getBoolean("migration.singleDirectory", false)) {
|
||||
singleDirectory();
|
||||
} else {
|
||||
modelPath = properties.get("migration.modelPath", modelPath);
|
||||
}
|
||||
modelPath = properties.get("migration.modelPath", modelPath);
|
||||
applyPrefix = properties.get("migration.applyPrefix", applyPrefix);
|
||||
applySuffix = properties.get("migration.applySuffix", applySuffix);
|
||||
modelSuffix = properties.get("migration.modelSuffix", modelSuffix);
|
||||
@@ -386,9 +376,9 @@ public class DbMigrationConfig {
|
||||
metaTable = properties.get("migration.metaTable", metaTable);
|
||||
runPlaceholders = properties.get("migration.placeholders", runPlaceholders);
|
||||
|
||||
String adminUser = properties.get("datasource."+serverName+".username", dbUser);
|
||||
String adminUser = properties.get("datasource."+serverName+".username", dbUsername);
|
||||
adminUser = properties.get("datasource."+serverName+".adminusername", adminUser);
|
||||
dbUser = properties.get("migration.dbuser", adminUser);
|
||||
dbUsername = properties.get("migration.dbusername", adminUser);
|
||||
|
||||
String adminPwd = properties.get("datasource."+serverName+".password", dbPassword);
|
||||
adminPwd = properties.get("datasource."+serverName+".adminpassword", adminPwd);
|
||||
@@ -494,4 +484,20 @@ public class DbMigrationConfig {
|
||||
return val == null || val.trim().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the MigrationRunner to run migrations if necessary.
|
||||
*/
|
||||
public MigrationRunner createRunner(ClassLoader classLoader) {
|
||||
|
||||
MigrationConfig runnerConfig = new MigrationConfig();
|
||||
runnerConfig.setMetaTable(metaTable);
|
||||
runnerConfig.setApplySuffix(applySuffix);
|
||||
runnerConfig.setMigrationPath(migrationPath);
|
||||
runnerConfig.setRunPlaceholderMap(runPlaceholderMap);
|
||||
runnerConfig.setRunPlaceholders(runPlaceholders);
|
||||
runnerConfig.setDbUsername(getDbUsername());
|
||||
runnerConfig.setDbPassword(getDbPassword());
|
||||
runnerConfig.setClassLoader(classLoader);
|
||||
return new MigrationRunner(runnerConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Adds ANSI based OFFSET FETCH NEXT clauses to a SQL query.
|
||||
*/
|
||||
public class BasicSqlAnsiLimiter implements BasicSqlLimiter {
|
||||
|
||||
@Override
|
||||
public String limit(String dbSql, int firstRow, int maxRows) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(50 + dbSql.length());
|
||||
|
||||
sb.append(dbSql);
|
||||
if (firstRow > 0) {
|
||||
sb.append(" ").append("offset");
|
||||
sb.append(" ").append(firstRow).append(" rows");
|
||||
}
|
||||
if (maxRows > 0) {
|
||||
sb.append(" fetch next ").append(maxRows).append(" rows only");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Adds LIMIT OFFSET clauses to a SQL query.
|
||||
*/
|
||||
public class BasicSqlLimitOffset implements BasicSqlLimiter {
|
||||
|
||||
/**
|
||||
* LIMIT keyword.
|
||||
*/
|
||||
private static final String LIMIT = "limit";
|
||||
|
||||
/**
|
||||
* OFFSET keyword.
|
||||
*/
|
||||
private static final String OFFSET = "offset";
|
||||
|
||||
@Override
|
||||
public String limit(String dbSql, int firstRow, int maxRows) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(50 + dbSql.length());
|
||||
|
||||
sb.append(dbSql);
|
||||
|
||||
if (maxRows > 0) {
|
||||
sb.append(" ").append(LIMIT);
|
||||
sb.append(" ").append(maxRows);
|
||||
}
|
||||
if (firstRow > 0) {
|
||||
sb.append(" ").append(OFFSET).append(" ");
|
||||
sb.append(firstRow);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Simple SQL limiter for use with SqlQuery.
|
||||
*/
|
||||
public interface BasicSqlLimiter {
|
||||
|
||||
/**
|
||||
* Add basic offset/limit clause to SqlQuery query.
|
||||
*/
|
||||
String limit(String dbSql, int firstRow, int maxRows);
|
||||
}
|
||||
@@ -71,6 +71,11 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected SqlLimiter sqlLimiter = new LimitOffsetSqlLimiter();
|
||||
|
||||
/**
|
||||
* Limit/offset support for SqlQuery only.
|
||||
*/
|
||||
protected BasicSqlLimiter basicSqlLimiter = new BasicSqlLimitOffset();
|
||||
|
||||
/**
|
||||
* Mapping of JDBC to Database types.
|
||||
*/
|
||||
@@ -454,6 +459,13 @@ public class DatabasePlatform {
|
||||
return sqlLimiter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BasicSqlLimiter for limit/offset of SqlQuery queries.
|
||||
*/
|
||||
public BasicSqlLimiter getBasicSqlLimiter() {
|
||||
return basicSqlLimiter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB TRUE literal (from the registered boolean ScalarType)
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,7 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
this.maxConstraintNameLength = 30;
|
||||
this.dbEncrypt = new OracleDbEncrypt();
|
||||
this.sqlLimiter = new RownumSqlLimiter();
|
||||
this.basicSqlLimiter = new BasicSqlAnsiLimiter();
|
||||
this.platformDdl = new Oracle10Ddl(this);
|
||||
this.historySupport = new OracleDbHistorySupport();
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Use top xx and start at xx to limit sql results. Based on
|
||||
* MsSqlServer2005SqlLimiter and LimitOffsetSqlLimiter
|
||||
* Use top xx and start at xx to limit sql results.
|
||||
*/
|
||||
public class SqlAnywhereLimiter implements SqlLimiter {
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.model.CurrentModel;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.extraddl.model.ExtraDdlXmlReader;
|
||||
import org.avaje.dbmigration.ddl.DdlRunner;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.File;
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Parses string content into separate SQL/DDL statements.
|
||||
*/
|
||||
public class DdlParser {
|
||||
|
||||
/**
|
||||
* Break up the sql in reader into a list of statements using the semi-colon and $$ delimiters;
|
||||
*/
|
||||
public List<String> parse(StringReader reader) {
|
||||
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(reader);
|
||||
StatementsSeparator statements = new StatementsSeparator();
|
||||
|
||||
String s;
|
||||
while ((s = br.readLine()) != null) {
|
||||
s = s.trim();
|
||||
statements.nextLine(s);
|
||||
}
|
||||
|
||||
return statements.statements;
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Local utility used to detect the end of statements / separate statements.
|
||||
* This is often just the semicolon character but for trigger/procedures this
|
||||
* detects the $$ demarcation used in the history DDL generation for MySql and
|
||||
* Postgres.
|
||||
*/
|
||||
static class StatementsSeparator {
|
||||
|
||||
ArrayList<String> statements = new ArrayList<String>();
|
||||
|
||||
boolean trimDelimiter;
|
||||
|
||||
boolean inDbProcedure;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
void lineContainsDollars(String line) {
|
||||
if (inDbProcedure) {
|
||||
if (trimDelimiter) {
|
||||
line = line.replace("$$","");
|
||||
}
|
||||
endOfStatement(line);
|
||||
} else {
|
||||
// MySql style delimiter needs to be trimmed/removed
|
||||
trimDelimiter = line.equals("delimiter $$");
|
||||
if (!trimDelimiter) {
|
||||
sb.append(line).append(" ");
|
||||
}
|
||||
}
|
||||
inDbProcedure = !inDbProcedure;
|
||||
}
|
||||
|
||||
void endOfStatement(String line) {
|
||||
// end of Db procedure
|
||||
sb.append(line);
|
||||
statements.add(sb.toString().trim());
|
||||
sb = new StringBuilder();
|
||||
}
|
||||
|
||||
void nextLine(String line) {
|
||||
|
||||
if (line.contains("$$")) {
|
||||
lineContainsDollars(line);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sb.length() == 0 && (line.isEmpty() || line.startsWith("--"))) {
|
||||
// ignore leading empty lines and sql comments
|
||||
return;
|
||||
}
|
||||
|
||||
if (inDbProcedure) {
|
||||
sb.append(line).append(" ");
|
||||
return;
|
||||
}
|
||||
|
||||
int semiPos = line.indexOf(';');
|
||||
if (semiPos == -1) {
|
||||
sb.append(line).append(" ");
|
||||
|
||||
} else if (semiPos == line.length() - 1) {
|
||||
// semicolon at end of line
|
||||
endOfStatement(line);
|
||||
|
||||
} else {
|
||||
// semicolon in middle of line
|
||||
String preSemi = line.substring(0, semiPos);
|
||||
endOfStatement(preSemi);
|
||||
sb.append(line.substring(semiPos + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Runs DDL scripts.
|
||||
*/
|
||||
public class DdlRunner {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(DdlRunner.class);
|
||||
|
||||
private DdlParser ddlParser = new DdlParser();
|
||||
|
||||
private final String scriptName;
|
||||
|
||||
private final boolean expectErrors;
|
||||
|
||||
/**
|
||||
* Construct with a script name (for logging) and flag indicating if errors are expected.
|
||||
*/
|
||||
public DdlRunner(boolean expectErrors, String scriptName) {
|
||||
this.expectErrors = expectErrors;
|
||||
this.scriptName = scriptName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the content into sql statements and execute them in a transaction.
|
||||
*/
|
||||
public int runAll(String content, Connection connection) throws SQLException {
|
||||
|
||||
List<String> statements = ddlParser.parse(new StringReader(content));
|
||||
return runStatements(statements, connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all the statements in a single transaction.
|
||||
*/
|
||||
private int runStatements(List<String> statements, Connection connection) throws SQLException {
|
||||
|
||||
List<String> noDuplicates = new ArrayList<String>();
|
||||
|
||||
for (String statement : statements) {
|
||||
if (!noDuplicates.contains(statement)) {
|
||||
noDuplicates.add(statement);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Executing {} - {} statements", scriptName, noDuplicates.size());
|
||||
|
||||
for (int i = 0; i < noDuplicates.size(); i++) {
|
||||
String xOfy = (i + 1) + " of " + noDuplicates.size();
|
||||
runStatement(expectErrors, xOfy, noDuplicates.get(i), connection);
|
||||
}
|
||||
|
||||
return noDuplicates.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the statement.
|
||||
*/
|
||||
private void runStatement(boolean expectErrors, String oneOf, String stmt, Connection c) throws SQLException {
|
||||
|
||||
PreparedStatement pstmt = null;
|
||||
try {
|
||||
|
||||
// trim and remove trailing ; or /
|
||||
stmt = stmt.trim();
|
||||
if (stmt.endsWith(";")) {
|
||||
stmt = stmt.substring(0, stmt.length() - 1);
|
||||
} else if (stmt.endsWith("/")) {
|
||||
stmt = stmt.substring(0, stmt.length() - 1);
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("executing " + oneOf + " " + getSummary(stmt));
|
||||
}
|
||||
|
||||
pstmt = c.prepareStatement(stmt);
|
||||
pstmt.execute();
|
||||
|
||||
} catch (SQLException e) {
|
||||
if (expectErrors) {
|
||||
logger.debug(" ... ignoring error executing " + getSummary(stmt) + " error: " + e.getMessage());
|
||||
} else {
|
||||
String msg = "Error executing stmt[" + stmt + "] error[" + e.getMessage() + "]";
|
||||
throw new SQLException(msg, e);
|
||||
}
|
||||
|
||||
} finally {
|
||||
if (pstmt != null) {
|
||||
try {
|
||||
pstmt.close();
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error closing pstmt", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getSummary(String s) {
|
||||
if (s.length() > 80) {
|
||||
return s.substring(0, 80).trim() + "...";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.DbMigrationConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.runner.LocalMigrationResource;
|
||||
import com.avaje.ebean.dbmigration.runner.LocalMigrationResources;
|
||||
import com.avaje.ebean.dbmigration.runner.MigrationTable;
|
||||
import com.avaje.ebeaninternal.util.JdbcClose;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Runs the DB migration typically on application start.
|
||||
*/
|
||||
public class MigrationRunner {
|
||||
|
||||
public static final Logger logger = LoggerFactory.getLogger("org.avaje.ebean.DbMigration");
|
||||
|
||||
private final EbeanServer server;
|
||||
|
||||
private final ServerConfig config;
|
||||
|
||||
private final DbMigrationConfig migrationConfig;
|
||||
|
||||
public MigrationRunner(EbeanServer server, DbMigrationConfig migrationConfig) {
|
||||
this.server = server;
|
||||
this.config = server.getPluginApi().getServerConfig();
|
||||
this.migrationConfig = migrationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations if there are any that need running.
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
LocalMigrationResources resources = new LocalMigrationResources(config, migrationConfig);
|
||||
if (!resources.readResources()) {
|
||||
logger.debug("no migrations to check");
|
||||
return;
|
||||
}
|
||||
|
||||
String migrationUser = migrationConfig.getDbUser();
|
||||
String migrationPwd = migrationConfig.getDbPassword();
|
||||
if (migrationUser == null) {
|
||||
throw new IllegalStateException("No DB migration user specified (to run the db migration) ?");
|
||||
}
|
||||
|
||||
DataSource dataSource = server.getPluginApi().getDataSource();
|
||||
if (dataSource == null) {
|
||||
throw new IllegalStateException("No dataSource when trying to run migration? "
|
||||
+"Maybe trying to generate DBMigration when ebean.migration.run=true is set? "
|
||||
+"Perhaps need to set ebean.migration.run=false in test-ebean.properties?");
|
||||
}
|
||||
|
||||
Connection connection;
|
||||
try {
|
||||
connection = dataSource.getConnection(migrationUser, migrationPwd);
|
||||
} catch (SQLException e) {
|
||||
throw new IllegalArgumentException("Error trying to connect to database using DB Migration user [" + migrationUser + "]", e);
|
||||
}
|
||||
|
||||
try {
|
||||
logger.debug("using db user [{}] to run migrations ...");
|
||||
connection.setAutoCommit(false);
|
||||
runMigrations(resources, connection);
|
||||
|
||||
connection.commit();
|
||||
|
||||
} catch (Exception e) {
|
||||
JdbcClose.rollback(connection);
|
||||
throw new RuntimeException(e);
|
||||
|
||||
} finally {
|
||||
JdbcClose.close(connection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all the migrations as needed.
|
||||
*/
|
||||
private void runMigrations(LocalMigrationResources resources, Connection connection) throws SQLException, IOException {
|
||||
|
||||
MigrationTable table = new MigrationTable(server, migrationConfig, connection);
|
||||
table.createIfNeeded();
|
||||
|
||||
// get the migrations in version order
|
||||
List<LocalMigrationResource> localVersions = resources.getVersions();
|
||||
|
||||
logger.info("local migrations:{} existing migrations:{}", localVersions.size(), table.size());
|
||||
|
||||
LocalMigrationResource priorVersion = null;
|
||||
|
||||
// run migrations in order
|
||||
for (int i = 0; i < localVersions.size(); i++) {
|
||||
LocalMigrationResource localVersion = localVersions.get(i);
|
||||
if (!table.shouldRun(localVersion, priorVersion)) {
|
||||
break;
|
||||
}
|
||||
priorVersion = localVersion;
|
||||
connection.commit();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,6 +13,7 @@ public class PostgresDdl extends PlatformDdl {
|
||||
this.dropTableCascade = " cascade";
|
||||
this.columnSetType = "type ";
|
||||
this.alterTableIfExists = "if exists ";
|
||||
this.columnSetNull = "drop not null";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -268,6 +268,10 @@ public class MColumn {
|
||||
return val != null && !val.isEmpty();
|
||||
}
|
||||
|
||||
private boolean hasValue(Boolean val) {
|
||||
return val != null;
|
||||
}
|
||||
|
||||
private AlterColumn getAlterColumn(String tableName, boolean tableWithHistory) {
|
||||
if (alterColumn == null) {
|
||||
alterColumn = new AlterColumn();
|
||||
@@ -396,6 +400,9 @@ public class MColumn {
|
||||
if (hasValue(alterColumn.getType())) {
|
||||
type = alterColumn.getType();
|
||||
}
|
||||
if (hasValue(alterColumn.isNotnull())) {
|
||||
notnull = alterColumn.isNotnull();
|
||||
}
|
||||
if (hasValue(alterColumn.getDefaultValue())) {
|
||||
defaultValue = alterColumn.getDefaultValue();
|
||||
}
|
||||
|
||||
+25
-4
@@ -11,12 +11,13 @@ import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueConstraint;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoinColumn;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Used as part of ModelBuildBeanVisitor and generally adds the MColumn to the associated
|
||||
@@ -249,9 +250,13 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
col.setUnique(determineUniqueConstraintName(col.getName()));
|
||||
indexSetAdd(col.getName());
|
||||
}
|
||||
String checkConstraint = p.getDbConstraintExpression();
|
||||
if (checkConstraint != null) {
|
||||
col.setCheckConstraint(checkConstraint);
|
||||
Set<String> checkConstraintValues = p.getDbCheckConstraintValues();
|
||||
if (checkConstraintValues != null) {
|
||||
if (beanDescriptor.hasInheritance()) {
|
||||
InheritInfo inheritInfo = beanDescriptor.getInheritInfo();
|
||||
inheritInfo.appendCheckConstraintValues(p.getName(), checkConstraintValues);
|
||||
}
|
||||
col.setCheckConstraint(buildCheckConstraint(p.getDbColumn(), checkConstraintValues));
|
||||
col.setCheckConstraintName(determineCheckConstraintName(col.getName()));
|
||||
}
|
||||
|
||||
@@ -268,6 +273,22 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
table.addColumn(col);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the check constraint clause given the db column and values.
|
||||
*/
|
||||
private String buildCheckConstraint(String dbColumn, Set<String> checkConstraintValues) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("check ( ").append(dbColumn).append(" in (");
|
||||
int count = 0;
|
||||
for (String value : checkConstraintValues) {
|
||||
if (count++ > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(value);
|
||||
}
|
||||
sb.append("))");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void indexSetAdd(String column) {
|
||||
indexSet.add(column);
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
/**
|
||||
* Calculates the checksum for the given string content.
|
||||
*/
|
||||
public class Checksum {
|
||||
|
||||
/**
|
||||
* Returns the checksum of this string.
|
||||
*/
|
||||
public static int calculate(String str) {
|
||||
|
||||
final CRC32 crc32 = new CRC32();
|
||||
|
||||
BufferedReader bufferedReader = new BufferedReader(new StringReader(str));
|
||||
try {
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
crc32.update(line.getBytes("UTF-8"));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to calculate checksum", e);
|
||||
}
|
||||
|
||||
return (int) crc32.getValue();
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import com.avaje.ebean.dbmigration.model.MigrationVersion;
|
||||
import org.avaje.classpath.scanner.Resource;
|
||||
|
||||
/**
|
||||
* A DB migration resource (DDL script with version).
|
||||
*/
|
||||
public class LocalMigrationResource implements Comparable<LocalMigrationResource> {
|
||||
|
||||
/**
|
||||
* Code for repeatable migrations.
|
||||
*/
|
||||
private static final String REPEAT_TYPE = "R";
|
||||
|
||||
/**
|
||||
* Code for version migrations.
|
||||
*/
|
||||
private static final String VERSION_TYPE = "V";
|
||||
|
||||
private final MigrationVersion version;
|
||||
|
||||
private final String location;
|
||||
|
||||
private final Resource resource;
|
||||
|
||||
/**
|
||||
* Construct with version and resource.
|
||||
*/
|
||||
public LocalMigrationResource(MigrationVersion version, String location, Resource resource) {
|
||||
this.version = version;
|
||||
this.location = location;
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return version.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the underlying version is "repeatable".
|
||||
*/
|
||||
public boolean isRepeatable() {
|
||||
return version.isRepeatable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the "key" that identifies the migration.
|
||||
*/
|
||||
public String key() {
|
||||
if (isRepeatable()) {
|
||||
return version.getComment().toLowerCase();
|
||||
} else {
|
||||
return version.normalised();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the migration comment.
|
||||
*/
|
||||
public String getComment() {
|
||||
String comment = version.getComment();
|
||||
return (comment == null || comment.isEmpty()) ? "-" : comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default ordering by version.
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(LocalMigrationResource o) {
|
||||
return version.compareTo(o.version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying migration version.
|
||||
*/
|
||||
public MigrationVersion getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resource location.
|
||||
*/
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the content for the migration apply ddl script.
|
||||
*/
|
||||
public String getContent() {
|
||||
return resource.loadAsString("UTF-8");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type code ("R" or "V") for this migration.
|
||||
*/
|
||||
public String getType() {
|
||||
return isRepeatable() ? REPEAT_TYPE : VERSION_TYPE;
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import com.avaje.ebean.config.DbMigrationConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.model.MigrationVersion;
|
||||
import org.avaje.classpath.scanner.Resource;
|
||||
import org.avaje.classpath.scanner.ResourceFilter;
|
||||
import org.avaje.classpath.scanner.Scanner;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Loads the DB migration resources and sorts them into execution order.
|
||||
*/
|
||||
public class LocalMigrationResources {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LocalMigrationResources.class);
|
||||
|
||||
private final ServerConfig serverConfig;
|
||||
|
||||
private final DbMigrationConfig migrationConfig;
|
||||
|
||||
private final List<LocalMigrationResource> versions = new ArrayList<LocalMigrationResource>();
|
||||
|
||||
/**
|
||||
* Construct with configuration options.
|
||||
*/
|
||||
public LocalMigrationResources(ServerConfig serverConfig, DbMigrationConfig migrationConfig) {
|
||||
this.serverConfig = serverConfig;
|
||||
this.migrationConfig = migrationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all the migration resources (SQL scripts) returning true if there are versions.
|
||||
*/
|
||||
public boolean readResources() {
|
||||
|
||||
String migrationPath = migrationConfig.getMigrationPath();
|
||||
|
||||
ClassLoader classLoader = serverConfig.getClassLoadConfig().getClassLoader();
|
||||
|
||||
Scanner scanner = new Scanner(classLoader);
|
||||
List<Resource> resourceList = scanner.scanForResources(migrationPath, new Match(migrationConfig));
|
||||
|
||||
logger.debug("resources: {}", resourceList);
|
||||
|
||||
for (Resource resource : resourceList) {
|
||||
String filename = resource.getFilename();
|
||||
if (filename.endsWith(migrationConfig.getApplySuffix())) {
|
||||
int pos = filename.lastIndexOf(migrationConfig.getApplySuffix());
|
||||
String mainName = filename.substring(0, pos);
|
||||
|
||||
MigrationVersion migrationVersion = MigrationVersion.parse(mainName);
|
||||
LocalMigrationResource res = new LocalMigrationResource(migrationVersion, resource.getLocation(), resource);
|
||||
versions.add(res);
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(versions);
|
||||
return !versions.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of migration resources in version order.
|
||||
*/
|
||||
public List<LocalMigrationResource> getVersions() {
|
||||
return versions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Filter used to find the migration scripts.
|
||||
*/
|
||||
private static class Match implements ResourceFilter {
|
||||
|
||||
private final DbMigrationConfig migrationConfig;
|
||||
|
||||
Match(DbMigrationConfig migrationConfig) {
|
||||
this.migrationConfig = migrationConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(String name) {
|
||||
return name.endsWith(migrationConfig.getApplySuffix());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import com.avaje.ebean.SqlRow;
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* Bean holding migration execution details stored in the migration table.
|
||||
*/
|
||||
class MigrationMetaRow {
|
||||
|
||||
private int id;
|
||||
|
||||
private String type;
|
||||
|
||||
private String version;
|
||||
|
||||
private String comment;
|
||||
|
||||
private int checksum;
|
||||
|
||||
private Timestamp runOn;
|
||||
|
||||
private String runBy;
|
||||
|
||||
private long runTime;
|
||||
|
||||
/**
|
||||
* Construct for inserting into table.
|
||||
*/
|
||||
MigrationMetaRow(int id, String type, String version, String comment, int checksum, String runBy, Timestamp runOn, long runTime) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.version = version;
|
||||
this.checksum = checksum;
|
||||
this.comment = comment;
|
||||
this.runBy = runBy;
|
||||
this.runOn = runOn;
|
||||
this.runTime = runTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct from the SqlRow (read from table).
|
||||
*/
|
||||
MigrationMetaRow(SqlRow row) {
|
||||
id = row.getInteger("id");
|
||||
type = row.getString("mtype");
|
||||
version = row.getString("mversion");
|
||||
comment = row.getString("mcomment");
|
||||
checksum = row.getInteger("mchecksum");
|
||||
runBy = row.getString("run_by");
|
||||
runTime = row.getLong("run_time");
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "id:" + id + " type:" + type + " runVersion:" + version + " comment:" + comment + " runOn:" + runOn + " runBy:" + runBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the id for this migration.
|
||||
*/
|
||||
int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the normalised version for this migration.
|
||||
*/
|
||||
String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the checksum for this migration.
|
||||
*/
|
||||
int getChecksum() {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind to the insert statement.
|
||||
*/
|
||||
void bindInsert(SqlUpdate insert) {
|
||||
insert.setParameter(1, id);
|
||||
insert.setParameter(2, type);
|
||||
insert.setParameter(3, "SUCCESS");
|
||||
insert.setParameter(4, version);
|
||||
insert.setParameter(5, comment);
|
||||
insert.setParameter(6, checksum);
|
||||
insert.setParameter(7, runOn);
|
||||
insert.setParameter(8, runBy);
|
||||
insert.setParameter(9, runTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL insert given the table migration meta data is stored in.
|
||||
*/
|
||||
static String insertSql(String table) {
|
||||
return "insert into " + table
|
||||
+ " (id, mtype, mstatus, mversion, mcomment, mchecksum, run_on, run_by, run_time)"
|
||||
+ " values (?,?,?,?,?,?,?,?,?)";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import com.avaje.ebean.dbmigration.DdlRunner;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Runs the DDL migration scripts.
|
||||
*/
|
||||
public class MigrationScriptRunner {
|
||||
|
||||
private final Connection connection;
|
||||
|
||||
/**
|
||||
* Construct with a given connection.
|
||||
*/
|
||||
public MigrationScriptRunner(Connection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all the DDL statements in the script.
|
||||
*/
|
||||
int runScript(boolean expectErrors, String content, String scriptName) throws SQLException {
|
||||
|
||||
DdlRunner runner = new DdlRunner(expectErrors, scriptName);
|
||||
return runner.runAll(content, connection);
|
||||
}
|
||||
}
|
||||
@@ -1,263 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.SqlQuery;
|
||||
import com.avaje.ebean.SqlRow;
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebean.config.DbMigrationConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.dbmigration.MigrationRunner;
|
||||
import com.avaje.ebean.plugin.SpiServer;
|
||||
import com.avaje.ebeaninternal.server.transaction.ExternalJdbcTransaction;
|
||||
import com.avaje.ebeaninternal.util.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Manages the migration table.
|
||||
*/
|
||||
public class MigrationTable {
|
||||
|
||||
private static final Logger logger = MigrationRunner.logger;
|
||||
|
||||
private final Connection connection;
|
||||
|
||||
private final EbeanServer server;
|
||||
|
||||
private final DatabasePlatform databasePlatform;
|
||||
|
||||
private final String catalog;
|
||||
private final String schema;
|
||||
private final String table;
|
||||
private final ServerConfig serverConfig;
|
||||
private final String envUserName;
|
||||
|
||||
private final Timestamp runOn = new Timestamp(System.currentTimeMillis());
|
||||
|
||||
private final ScriptTransform scriptTransform;
|
||||
|
||||
private final String insertSql;
|
||||
|
||||
private final LinkedHashMap<String, MigrationMetaRow> migrations;
|
||||
|
||||
private MigrationMetaRow lastMigration;
|
||||
|
||||
/**
|
||||
* Construct with server, configuration and jdbc connection (DB admin user).
|
||||
*/
|
||||
public MigrationTable(EbeanServer server, DbMigrationConfig migrationConfig, Connection connection) {
|
||||
this.connection = connection;
|
||||
this.server = server;
|
||||
this.migrations = new LinkedHashMap<String, MigrationMetaRow>();
|
||||
|
||||
SpiServer pluginApi = server.getPluginApi();
|
||||
this.serverConfig = pluginApi.getServerConfig();
|
||||
this.databasePlatform = pluginApi.getDatabasePlatform();
|
||||
this.catalog = null;
|
||||
this.schema = null;
|
||||
this.table = migrationConfig.getMetaTable();
|
||||
this.insertSql = MigrationMetaRow.insertSql(table);
|
||||
this.scriptTransform = createScriptTransform(migrationConfig);
|
||||
this.envUserName = System.getProperty("user.name");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of migrations in the DB migration table.
|
||||
*/
|
||||
public int size() {
|
||||
return migrations.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the ScriptTransform for placeholder key/value replacement.
|
||||
*/
|
||||
private ScriptTransform createScriptTransform(DbMigrationConfig config) {
|
||||
|
||||
Map<String, String> map = PlaceholderBuilder.build(config.getRunPlaceholders(), config.getRunPlaceholderMap());
|
||||
return new ScriptTransform(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the table is it does not exist.
|
||||
*/
|
||||
public void createIfNeeded() throws SQLException, IOException {
|
||||
|
||||
if (!tableExists(connection)) {
|
||||
createTable(connection);
|
||||
}
|
||||
|
||||
ExternalJdbcTransaction t = new ExternalJdbcTransaction(connection);
|
||||
SqlQuery sqlQuery = server.createSqlQuery("select * from " + table + " order by id for update");
|
||||
List<SqlRow> metaRows = server.findList(sqlQuery, t);
|
||||
|
||||
for (SqlRow row : metaRows) {
|
||||
MigrationMetaRow metaRow = new MigrationMetaRow(row);
|
||||
addMigration(metaRow.getVersion(), metaRow);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void createTable(Connection connection) throws IOException, SQLException {
|
||||
|
||||
String script = ScriptTransform.table(table, getCreateTableScript());
|
||||
|
||||
MigrationScriptRunner run = new MigrationScriptRunner(connection);
|
||||
run.runScript(false, script, "create migration table");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the create table script.
|
||||
*/
|
||||
private String getCreateTableScript() throws IOException {
|
||||
// supply a script to override the default table create script
|
||||
String script = readResource("migration-support/create-table.sql");
|
||||
if (script == null) {
|
||||
// no, just use the default script
|
||||
script = readResource("migration-support/default-create-table.sql");
|
||||
}
|
||||
return script;
|
||||
}
|
||||
|
||||
private String readResource(String location) throws IOException {
|
||||
|
||||
Enumeration<URL> resources = serverConfig.getClassLoadConfig().getResources(location);
|
||||
if (resources.hasMoreElements()) {
|
||||
URL url = resources.nextElement();
|
||||
return IOUtils.readUtf8(url.openStream());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the table exists.
|
||||
*/
|
||||
private boolean tableExists(Connection connection) throws SQLException {
|
||||
boolean exists = databasePlatform.tableExists(connection, catalog, schema, table);
|
||||
if (!exists) {
|
||||
exists = databasePlatform.tableExists(connection, catalog, schema, table.toUpperCase());
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the migration ran successfully and false if the migration failed.
|
||||
*/
|
||||
public boolean shouldRun(LocalMigrationResource localVersion, LocalMigrationResource priorVersion) throws SQLException {
|
||||
|
||||
if (priorVersion != null && !localVersion.isRepeatable()) {
|
||||
if (!migrationExists(priorVersion)) {
|
||||
logger.error("Migration {} requires prior migration {} which has not been run", localVersion.getVersion(), priorVersion.getVersion());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MigrationMetaRow existing = migrations.get(localVersion.key());
|
||||
return runMigration(localVersion, existing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migration script.
|
||||
*
|
||||
* @param local The local migration resource
|
||||
* @param existing The information for this migration existing in the table
|
||||
*
|
||||
* @return True if the migrations should continue
|
||||
*/
|
||||
private boolean runMigration(LocalMigrationResource local, MigrationMetaRow existing) throws SQLException {
|
||||
|
||||
String script = convertScript(local.getContent());
|
||||
int checksum = Checksum.calculate(script);
|
||||
|
||||
if (existing != null) {
|
||||
|
||||
boolean matchChecksum = (existing.getChecksum() == checksum);
|
||||
|
||||
if (!local.isRepeatable()) {
|
||||
if (!matchChecksum) {
|
||||
logger.error("Checksum mismatch on migration {}", local.getLocation());
|
||||
}
|
||||
return true;
|
||||
|
||||
} else if (matchChecksum) {
|
||||
logger.trace("... skip unchanged repeatable migration {}", local.getLocation());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
runMigration(local, script, checksum);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a migration script as new migration or update on existing repeatable migration.
|
||||
*/
|
||||
private void runMigration(LocalMigrationResource local, String script, int checksum) throws SQLException {
|
||||
|
||||
logger.debug("run migration {}", local.getLocation());
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
MigrationScriptRunner run = new MigrationScriptRunner(connection);
|
||||
run.runScript(false, script, "run migration version: " + local.getVersion());
|
||||
|
||||
long exeMillis = System.currentTimeMillis() - start;
|
||||
// insert new migration row
|
||||
SqlUpdate insert = server.createSqlUpdate(insertSql);
|
||||
MigrationMetaRow metaRow = createMetaRow(local, checksum, exeMillis);
|
||||
metaRow.bindInsert(insert);
|
||||
server.execute(insert, new ExternalJdbcTransaction(connection));
|
||||
|
||||
addMigration(local.key(), metaRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the MigrationMetaRow for this migration.
|
||||
*/
|
||||
private MigrationMetaRow createMetaRow(LocalMigrationResource migration, int checksum, long exeMillis) {
|
||||
|
||||
int nextId = 1;
|
||||
if (lastMigration != null) {
|
||||
nextId = lastMigration.getId() + 1;
|
||||
}
|
||||
|
||||
String type = migration.getType();
|
||||
String runVersion = migration.key();
|
||||
String comment = migration.getComment();
|
||||
|
||||
return new MigrationMetaRow(nextId, type, runVersion, comment, checksum, envUserName, runOn, exeMillis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the migration exists.
|
||||
*/
|
||||
private boolean migrationExists(LocalMigrationResource priorVersion) {
|
||||
return migrations.containsKey(priorVersion.key());
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the placeholder key/value replacement on the script.
|
||||
*/
|
||||
private String convertScript(String script) {
|
||||
return scriptTransform.transform(script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the successfully executed migration (to allow dependant scripts to run).
|
||||
*/
|
||||
private void addMigration(String key, MigrationMetaRow metaRow) {
|
||||
lastMigration = metaRow;
|
||||
if (metaRow.getVersion() == null) {
|
||||
throw new IllegalStateException("No runVersion in db migration table row? " + metaRow);
|
||||
}
|
||||
migrations.put(key, metaRow);
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Joins placeholder map and comma/equals delimited string.
|
||||
*/
|
||||
class PlaceholderBuilder {
|
||||
|
||||
private final Map<String,String> map = new HashMap<String,String>();
|
||||
|
||||
/**
|
||||
* Create with raw comma and equals delimited pairs plus map of key value pairs.
|
||||
*/
|
||||
public static Map<String,String> build(String commaDelimited, Map<String,String> placeholders) {
|
||||
|
||||
PlaceholderBuilder builder = new PlaceholderBuilder();
|
||||
builder.add(commaDelimited);
|
||||
builder.add(placeholders);
|
||||
|
||||
return builder.map;
|
||||
}
|
||||
|
||||
private PlaceholderBuilder() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a comma and equals delimited string to parse for key value pairs.
|
||||
*/
|
||||
public void add(String commaDelimited) {
|
||||
|
||||
if (commaDelimited != null) {
|
||||
String[] split = commaDelimited.split("[,;]");
|
||||
for (String keyValue : split) {
|
||||
String[] pair = keyValue.split("=");
|
||||
if (pair.length == 2) {
|
||||
map.put(pair[0].trim(), pair[1].trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a map of key value placeholder pairs.
|
||||
*/
|
||||
public void add(Map<String,String> placeholders) {
|
||||
if (placeholders != null) {
|
||||
map.putAll(placeholders);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration.runner;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Transforms a SQL script given a map of key/value substitutions.
|
||||
*/
|
||||
class ScriptTransform {
|
||||
|
||||
/**
|
||||
* Transform just ${table} with the table name.
|
||||
*/
|
||||
public static String table(String tableName, String script) {
|
||||
return script.replace("${table}", tableName);
|
||||
}
|
||||
|
||||
private final Map<String,String> placeholders = new HashMap<String, String>();
|
||||
|
||||
ScriptTransform(Map<String,String> map) {
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
placeholders.put(wrapKey(entry.getKey()), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private String wrapKey(String key) {
|
||||
return "${"+key+"}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this contains no placeholders.
|
||||
*/
|
||||
boolean isEmpty() {
|
||||
return placeholders.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the script replacing placeholders in the form <code>${key}</code> with <code>value</code>.
|
||||
*/
|
||||
String transform(String source) {
|
||||
|
||||
for (Map.Entry<String, String> entry : placeholders.entrySet()) {
|
||||
source = source.replace(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return source;
|
||||
}
|
||||
}
|
||||
@@ -74,4 +74,23 @@ public class ReadAuditQueryPlan {
|
||||
public void setSql(String sql) {
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ReadAuditQueryPlan that = (ReadAuditQueryPlan) o;
|
||||
if (!beanType.equals(that.beanType)) return false;
|
||||
if (!queryKey.equals(that.queryKey)) return false;
|
||||
return sql.equals(that.sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = beanType.hashCode();
|
||||
result = 31 * result + queryKey.hashCode();
|
||||
result = 31 * result + sql.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.avaje.ebean.TxScope;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Used internally to handle the scoping of transactions for methods.
|
||||
*/
|
||||
public class ScopeTrans implements Thread.UncaughtExceptionHandler {
|
||||
|
||||
private static final int OPCODE_ATHROW = 191;
|
||||
private static final int OPCODE_ATHROW = 191;
|
||||
|
||||
private final SpiTransactionScopeManager scopeMgr;
|
||||
private final SpiTransactionScopeManager scopeMgr;
|
||||
|
||||
/**
|
||||
* The suspended transaction (can be null).
|
||||
*/
|
||||
private final SpiTransaction suspendedTransaction;
|
||||
/**
|
||||
* The suspended transaction (can be null).
|
||||
*/
|
||||
private final SpiTransaction suspendedTransaction;
|
||||
|
||||
/**
|
||||
* The transaction in scope (can be null).
|
||||
*/
|
||||
private final SpiTransaction transaction;
|
||||
/**
|
||||
* The transaction in scope (can be null).
|
||||
*/
|
||||
private final SpiTransaction transaction;
|
||||
|
||||
/**
|
||||
* If true by default rollback on Checked exceptions.
|
||||
*/
|
||||
private final boolean rollbackOnChecked;
|
||||
/**
|
||||
* If true by default rollback on Checked exceptions.
|
||||
*/
|
||||
private final boolean rollbackOnChecked;
|
||||
|
||||
/**
|
||||
* True if the transaction was created and hence should be committed
|
||||
* on finally if it hasn't already been rolled back.
|
||||
*/
|
||||
private final boolean created;
|
||||
/**
|
||||
* True if the transaction was created and hence should be committed
|
||||
* on finally if it hasn't already been rolled back.
|
||||
*/
|
||||
private final boolean created;
|
||||
|
||||
/**
|
||||
* Explicit set of Exceptions that DO NOT cause a rollback to occur.
|
||||
*/
|
||||
private final ArrayList<Class<? extends Throwable>> noRollbackFor;
|
||||
/**
|
||||
* Explicit set of Exceptions that DO NOT cause a rollback to occur.
|
||||
*/
|
||||
private final ArrayList<Class<? extends Throwable>> noRollbackFor;
|
||||
|
||||
/**
|
||||
* Explicit set of Exceptions that DO cause a rollback to occur.
|
||||
*/
|
||||
private final ArrayList<Class<? extends Throwable>> rollbackFor;
|
||||
/**
|
||||
* Explicit set of Exceptions that DO cause a rollback to occur.
|
||||
*/
|
||||
private final ArrayList<Class<? extends Throwable>> rollbackFor;
|
||||
|
||||
private PersistBatch restoreBatch;
|
||||
|
||||
@@ -51,29 +51,32 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler {
|
||||
|
||||
private int restoreBatchSize;
|
||||
|
||||
/**
|
||||
* Flag set when a rollback has occurred.
|
||||
*/
|
||||
private boolean rolledBack;
|
||||
|
||||
|
||||
public ScopeTrans(boolean rollbackOnChecked, boolean created, SpiTransaction transaction, TxScope txScope,
|
||||
SpiTransaction suspendedTransaction, SpiTransactionScopeManager scopeMgr) {
|
||||
private Boolean restoreBatchGeneratedKeys;
|
||||
|
||||
this.rollbackOnChecked = rollbackOnChecked;
|
||||
this.created = created;
|
||||
this.transaction = transaction;
|
||||
this.suspendedTransaction = suspendedTransaction;
|
||||
this.scopeMgr = scopeMgr;
|
||||
|
||||
this.noRollbackFor = txScope.getNoRollbackFor();
|
||||
this.rollbackFor = txScope.getRollbackFor();
|
||||
/**
|
||||
* Flag set when a rollback has occurred.
|
||||
*/
|
||||
private boolean rolledBack;
|
||||
|
||||
|
||||
public ScopeTrans(boolean rollbackOnChecked, boolean created, SpiTransaction transaction, TxScope txScope,
|
||||
SpiTransaction suspendedTransaction, SpiTransactionScopeManager scopeMgr) {
|
||||
|
||||
this.rollbackOnChecked = rollbackOnChecked;
|
||||
this.created = created;
|
||||
this.transaction = transaction;
|
||||
this.suspendedTransaction = suspendedTransaction;
|
||||
this.scopeMgr = scopeMgr;
|
||||
|
||||
this.noRollbackFor = txScope.getNoRollbackFor();
|
||||
this.rollbackFor = txScope.getRollbackFor();
|
||||
|
||||
if (transaction != null) {
|
||||
if (!created && txScope.isBatchSet() || txScope.isBatchOnCascadeSet() || txScope.isBatchSizeSet()) {
|
||||
restoreBatch = transaction.getBatch();
|
||||
restoreBatchOnCascade = transaction.getBatchOnCascade();
|
||||
restoreBatchSize = transaction.getBatchSize();
|
||||
restoreBatchGeneratedKeys = transaction.getBatchGetGeneratedKeys();
|
||||
}
|
||||
if (txScope.isBatchSet()) {
|
||||
transaction.setBatch(txScope.getBatch());
|
||||
@@ -84,70 +87,74 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler {
|
||||
if (txScope.isBatchSizeSet()) {
|
||||
transaction.setBatchSize(txScope.getBatchSize());
|
||||
}
|
||||
if (txScope.isSkipGeneratedKeys()) {
|
||||
transaction.setBatchGetGeneratedKeys(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current/active transaction.
|
||||
*/
|
||||
protected SpiTransaction getTransaction() {
|
||||
return transaction;
|
||||
}
|
||||
/**
|
||||
* Return the current/active transaction.
|
||||
*/
|
||||
protected SpiTransaction getTransaction() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the Thread catches any uncaught exception.
|
||||
* For example, an unexpected NullPointerException or Error.
|
||||
*/
|
||||
public void uncaughtException(Thread thread, Throwable e) {
|
||||
|
||||
// rollback transaction if required
|
||||
caughtThrowable(e);
|
||||
|
||||
// reinstate suspended transaction
|
||||
onFinally();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returned via RETURN or expected Exception from the method.
|
||||
* @param returnOrThrowable the return value or Throwable
|
||||
* @param opCode indicates
|
||||
*/
|
||||
public void onExit(Object returnOrThrowable, int opCode) {
|
||||
|
||||
if (opCode == OPCODE_ATHROW){
|
||||
// exited with a Throwable
|
||||
caughtThrowable((Throwable)returnOrThrowable);
|
||||
}
|
||||
onFinally();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Commit if the transaction exists and has not already been rolled back.
|
||||
* Also reinstate the suspended transaction if there was one.
|
||||
*/
|
||||
public void onFinally() {
|
||||
/**
|
||||
* Called when the Thread catches any uncaught exception.
|
||||
* For example, an unexpected NullPointerException or Error.
|
||||
*/
|
||||
public void uncaughtException(Thread thread, Throwable e) {
|
||||
|
||||
try {
|
||||
if (!rolledBack) {
|
||||
commitTransaction();
|
||||
}
|
||||
} finally {
|
||||
restoreSuspended();
|
||||
}
|
||||
}
|
||||
// rollback transaction if required
|
||||
caughtThrowable(e);
|
||||
|
||||
protected void restoreSuspended() {
|
||||
if (suspendedTransaction != null){
|
||||
// reinstate suspended transaction
|
||||
onFinally();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returned via RETURN or expected Exception from the method.
|
||||
*
|
||||
* @param returnOrThrowable the return value or Throwable
|
||||
* @param opCode indicates
|
||||
*/
|
||||
public void onExit(Object returnOrThrowable, int opCode) {
|
||||
|
||||
if (opCode == OPCODE_ATHROW) {
|
||||
// exited with a Throwable
|
||||
caughtThrowable((Throwable) returnOrThrowable);
|
||||
}
|
||||
onFinally();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Commit if the transaction exists and has not already been rolled back.
|
||||
* Also reinstate the suspended transaction if there was one.
|
||||
*/
|
||||
public void onFinally() {
|
||||
|
||||
try {
|
||||
if (!rolledBack) {
|
||||
commitTransaction();
|
||||
}
|
||||
} finally {
|
||||
restoreSuspended();
|
||||
}
|
||||
}
|
||||
|
||||
protected void restoreSuspended() {
|
||||
if (suspendedTransaction != null) {
|
||||
// put the previously suspended transaction
|
||||
// back onto the ThreadLocal or equivalent
|
||||
scopeMgr.replace(suspendedTransaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void commitTransaction() {
|
||||
if (created) {
|
||||
protected void commitTransaction() {
|
||||
if (created) {
|
||||
transaction.commit();
|
||||
} else {
|
||||
if (restoreBatch != null) {
|
||||
@@ -159,78 +166,81 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler {
|
||||
if (restoreBatchSize > 0) {
|
||||
transaction.setBatchSize(restoreBatchSize);
|
||||
}
|
||||
if (restoreBatchGeneratedKeys != null) {
|
||||
transaction.setBatchGetGeneratedKeys(restoreBatchGeneratedKeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An Error was caught and this ALWAYS causes a rollback to occur.
|
||||
* Returns the error and this should be thrown by the calling code.
|
||||
*/
|
||||
public Error caughtError(Error e) {
|
||||
rollback(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* An Exception was caught and may or may not cause a rollback to occur.
|
||||
* Returns the exception and this should be thrown by the calling code.
|
||||
*/
|
||||
public <T extends Throwable> T caughtThrowable(T e) {
|
||||
|
||||
if (isRollbackThrowable(e)) {
|
||||
rollback(e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
/**
|
||||
* An Error was caught and this ALWAYS causes a rollback to occur.
|
||||
* Returns the error and this should be thrown by the calling code.
|
||||
*/
|
||||
public Error caughtError(Error e) {
|
||||
rollback(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
protected void rollback(Throwable e) {
|
||||
if (transaction != null && transaction.isActive()) {
|
||||
// transaction is null for NOT_SUPPORTED and sometimes SUPPORTS
|
||||
// and Inactive (already rolled back) if nested REQUIRED
|
||||
transaction.rollback(e);
|
||||
}
|
||||
rolledBack = true;
|
||||
}
|
||||
/**
|
||||
* An Exception was caught and may or may not cause a rollback to occur.
|
||||
* Returns the exception and this should be thrown by the calling code.
|
||||
*/
|
||||
public <T extends Throwable> T caughtThrowable(T e) {
|
||||
|
||||
/**
|
||||
* Return true if this throwable should cause a rollback to occur.
|
||||
*/
|
||||
private boolean isRollbackThrowable(Throwable e) {
|
||||
if (isRollbackThrowable(e)) {
|
||||
rollback(e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
if (e instanceof Error){
|
||||
return true;
|
||||
}
|
||||
|
||||
if (noRollbackFor != null){
|
||||
for (int i = 0; i < noRollbackFor.size(); i++) {
|
||||
if (noRollbackFor.get(i).equals(e.getClass())) {
|
||||
|
||||
// explicit no rollback for this one
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
protected void rollback(Throwable e) {
|
||||
if (transaction != null && transaction.isActive()) {
|
||||
// transaction is null for NOT_SUPPORTED and sometimes SUPPORTS
|
||||
// and Inactive (already rolled back) if nested REQUIRED
|
||||
transaction.rollback(e);
|
||||
}
|
||||
rolledBack = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this throwable should cause a rollback to occur.
|
||||
*/
|
||||
private boolean isRollbackThrowable(Throwable e) {
|
||||
|
||||
if (e instanceof Error) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (noRollbackFor != null) {
|
||||
for (int i = 0; i < noRollbackFor.size(); i++) {
|
||||
if (noRollbackFor.get(i).equals(e.getClass())) {
|
||||
|
||||
// explicit no rollback for this one
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rollbackFor != null) {
|
||||
for (int i = 0; i < rollbackFor.size(); i++) {
|
||||
if (rollbackFor.get(i).equals(e.getClass())) {
|
||||
// explicit rollback for this one
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (e instanceof RuntimeException) {
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// checked exceptions...
|
||||
// EJB defaults this to false which is not intuitive IMO
|
||||
// Ebean makes this configurable (default to true)
|
||||
return rollbackOnChecked;
|
||||
}
|
||||
}
|
||||
|
||||
if (rollbackFor != null){
|
||||
for (int i = 0; i < rollbackFor.size(); i++) {
|
||||
if (rollbackFor.get(i).equals(e.getClass())) {
|
||||
// explicit rollback for this one
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (e instanceof RuntimeException) {
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// checked exceptions...
|
||||
// EJB defaults this to false which is not intuitive IMO
|
||||
// Ebean makes this configurable (default to true)
|
||||
return rollbackOnChecked;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -230,6 +230,11 @@ public class ScopedTransaction implements SpiTransaction {
|
||||
transaction.setBatchGetGeneratedKeys(getGeneratedKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getBatchGetGeneratedKeys() {
|
||||
return transaction.getBatchGetGeneratedKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBatchFlushOnMixed(boolean batchFlushOnMixed) {
|
||||
transaction.setBatchFlushOnMixed(batchFlushOnMixed);
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.avaje.ebean.ExpressionList;
|
||||
import com.avaje.ebean.OrderBy;
|
||||
import com.avaje.ebean.PersistenceContextScope;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.bean.BeanCollectionTouched;
|
||||
import com.avaje.ebean.bean.CallStack;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
@@ -226,18 +225,6 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
|
||||
List<String> getSoftDeletePredicates();
|
||||
|
||||
/**
|
||||
* Return a listener that wants to be notified when the bean collection is
|
||||
* first used.
|
||||
*/
|
||||
BeanCollectionTouched getBeanCollectionTouched();
|
||||
|
||||
/**
|
||||
* Set a listener to be notified when the bean collection has been touched
|
||||
* (when the list/set/map is first used).
|
||||
*/
|
||||
void setBeanCollectionTouched(BeanCollectionTouched notify);
|
||||
|
||||
/**
|
||||
* Set the list of Id's that is being populated.
|
||||
* <p>
|
||||
@@ -526,9 +513,15 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
boolean hasMaxRowsOrFirstRow();
|
||||
|
||||
/**
|
||||
* Return true if this query should use/check the bean cache.
|
||||
* Return true if the bean cache should be exclude for query or lazy loading.
|
||||
*/
|
||||
Boolean isUseBeanCache();
|
||||
boolean isExcludeBeanCache();
|
||||
|
||||
/**
|
||||
* Return true if this query should use the bean cache.
|
||||
* It is not skipped and bean caching is supported.
|
||||
*/
|
||||
boolean isUseBeanCache();
|
||||
|
||||
/**
|
||||
* Return true if this query should use/check the query cache.
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
@@ -12,6 +9,9 @@ import com.avaje.ebeaninternal.server.core.PersistRequest;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.persist.BatchControl;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Extends Transaction with additional API required on server.
|
||||
* <p>
|
||||
@@ -125,6 +125,11 @@ public interface SpiTransaction extends Transaction {
|
||||
*/
|
||||
int getBatchSize();
|
||||
|
||||
/**
|
||||
* Return the getGeneratedKeys setting for this transaction.
|
||||
*/
|
||||
Boolean getBatchGetGeneratedKeys();
|
||||
|
||||
/**
|
||||
* Modify and return the current 'depth' of the transaction.
|
||||
* <p>
|
||||
|
||||
@@ -14,7 +14,6 @@ import com.avaje.ebean.config.EncryptKeyManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.dbmigration.DdlGenerator;
|
||||
import com.avaje.ebean.dbmigration.MigrationRunner;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebean.event.readaudit.ReadAuditLogger;
|
||||
import com.avaje.ebean.event.readaudit.ReadAuditPrepare;
|
||||
@@ -65,6 +64,7 @@ import com.avaje.ebeaninternal.server.transaction.TransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.util.ParamTypeHelper;
|
||||
import com.avaje.ebeaninternal.util.ParamTypeHelper.TypeInfo;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreIntegration;
|
||||
import org.avaje.dbmigration.MigrationRunner;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -344,10 +344,13 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
DbMigrationConfig migrationConfig = serverConfig.getMigrationConfig();
|
||||
if (migrationConfig != null) {
|
||||
migrationConfig.generateOnStart(this);
|
||||
}
|
||||
|
||||
if (migrationConfig.isRunMigration()) {
|
||||
new MigrationRunner(this, migrationConfig).run();
|
||||
if (migrationConfig.isRunMigration()) {
|
||||
// classLoader used to load resources
|
||||
ClassLoader classLoader = serverConfig.getClassLoadConfig().getClassLoader();
|
||||
MigrationRunner runner = migrationConfig.createRunner(classLoader);
|
||||
runner.run(serverConfig.getDataSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1047,8 +1050,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
}
|
||||
|
||||
if (!desc.calculateUseCache(query.isUseBeanCache())) {
|
||||
// not using bean cache
|
||||
if (!query.isUseBeanCache()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -425,7 +425,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
}
|
||||
|
||||
public boolean isUseBeanCache() {
|
||||
return beanDescriptor.calculateUseCache(query.isUseBeanCache());
|
||||
return query.isUseBeanCache();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -305,7 +305,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
* Set the cache notify status.
|
||||
*/
|
||||
private void setNotifyCache() {
|
||||
this.notifyCache = beanDescriptor.isCacheNotify(publish);
|
||||
this.notifyCache = beanDescriptor.isCacheNotify(type, publish);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,8 +31,6 @@ import java.util.List;
|
||||
*/
|
||||
public final class RelationalQueryRequest {
|
||||
|
||||
private static final int GLOBAL_ROW_LIMIT = Integer.valueOf(System.getProperty("ebean.query.globallimit", "1000000"));
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RelationalQueryRequest.class);
|
||||
|
||||
private final SpiSqlQuery query;
|
||||
@@ -212,7 +210,18 @@ public final class RelationalQueryRequest {
|
||||
// convert any named parameters if required
|
||||
sql = BindParamsParser.parse(bindParams, sql);
|
||||
}
|
||||
this.sql = sql;
|
||||
this.sql = limitOffset(sql);
|
||||
}
|
||||
|
||||
private String limitOffset(String sql) {
|
||||
|
||||
int firstRow = query.getFirstRow();
|
||||
int maxRows = query.getMaxRows();
|
||||
if (firstRow > 0 || maxRows > 0) {
|
||||
return ebeanServer.getDatabasePlatform().getBasicSqlLimiter()
|
||||
.limit(query.getQuery(), firstRow, maxRows);
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,13 +259,6 @@ public final class RelationalQueryRequest {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maxRows allowed to fetch.
|
||||
*/
|
||||
public int getMaxRows() {
|
||||
return query.getMaxRows() >= 1 ? query.getMaxRows() : GLOBAL_ROW_LIMIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL executed for this query.
|
||||
*/
|
||||
|
||||
@@ -726,6 +726,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
}
|
||||
docMapping = docStoreAdapter.createDocMapping();
|
||||
docStoreAdapter.registerPaths();
|
||||
cacheHelp.deriveNotifyFlags();
|
||||
}
|
||||
|
||||
public void initInheritInfo() {
|
||||
@@ -866,10 +867,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean calculateUseCache(Boolean queryUseCache) {
|
||||
return (queryUseCache != null) ? queryUseCache : isBeanCaching();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache options.
|
||||
*/
|
||||
@@ -1059,12 +1056,12 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
/**
|
||||
* Return true if the persist request needs to notify the cache.
|
||||
*/
|
||||
public boolean isCacheNotify(boolean publish) {
|
||||
public boolean isCacheNotify(PersistRequest.Type type, boolean publish) {
|
||||
if (draftable && !publish) {
|
||||
// no caching when editing draft beans
|
||||
return false;
|
||||
}
|
||||
return cacheHelp.isCacheNotify();
|
||||
return cacheHelp.isCacheNotify(type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1657,7 +1654,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
return assocProp.getTargetDescriptor().getBeanDescriptor(splitBegin[1]);
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Error getting BeanDescriptor for path " + path + " from " + getFullName());
|
||||
throw new PersistenceException("Invalid path " + path + " from " + getFullName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.avaje.ebeaninternal.server.cache.CachedBeanDataFromBean;
|
||||
import com.avaje.ebeaninternal.server.cache.CachedBeanDataToBean;
|
||||
import com.avaje.ebeaninternal.server.cache.CachedManyIds;
|
||||
import com.avaje.ebeaninternal.server.core.CacheOptions;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequest;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.querydefn.NaturalKeyBindParam;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
|
||||
@@ -33,6 +34,8 @@ import java.util.Map;
|
||||
*/
|
||||
final class BeanDescriptorCacheHelp<T> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BeanDescriptorCacheHelp.class);
|
||||
|
||||
private static final Logger queryLog = LoggerFactory.getLogger("org.avaje.ebean.cache.QUERY");
|
||||
private static final Logger beanLog = LoggerFactory.getLogger("org.avaje.ebean.cache.BEAN");
|
||||
private static final Logger manyLog = LoggerFactory.getLogger("org.avaje.ebean.cache.COLL");
|
||||
@@ -60,6 +63,16 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
private final ServerCache naturalKeyCache;
|
||||
private final ServerCache queryCache;
|
||||
|
||||
/**
|
||||
* Set to true if all persist changes need to notify the cache.
|
||||
*/
|
||||
private boolean cacheNotifyOnAll;
|
||||
|
||||
/**
|
||||
* Set to true if delete changes need to notify cache.
|
||||
*/
|
||||
private boolean cacheNotifyOnDelete;
|
||||
|
||||
BeanDescriptorCacheHelp(BeanDescriptor<T> desc, ServerCacheManager cacheManager, CacheOptions cacheOptions,
|
||||
boolean cacheSharableBeans, BeanPropertyAssocOne<?>[] propertiesOneImported) {
|
||||
|
||||
@@ -91,6 +104,43 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive the cache notify flags.
|
||||
*/
|
||||
public void deriveNotifyFlags() {
|
||||
cacheNotifyOnAll = (beanCache != null || queryCache != null);
|
||||
cacheNotifyOnDelete = !cacheNotifyOnAll && isNotifyOnDeletes();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
if (isBeanCaching() || isQueryCaching() || cacheNotifyOnAll || cacheNotifyOnDelete) {
|
||||
String notifyMode = cacheNotifyOnAll ? "All" : (cacheNotifyOnDelete ? "Delete" : "None");
|
||||
logger.debug("l2 caching on {} - beanCaching:{} queryCaching:{} notifyMode:{} ",
|
||||
desc.getFullName(), isBeanCaching(), isQueryCaching(), notifyMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is an imported bi-directional relationship to a bea
|
||||
* that does have bean caching enabled.
|
||||
*/
|
||||
private boolean isNotifyOnDeletes() {
|
||||
for (int i = 0; i < propertiesOneImported.length; i++) {
|
||||
if (propertiesOneImported[i].isCacheNotify()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the persist request needs to notify the cache.
|
||||
*/
|
||||
boolean isCacheNotify(PersistRequest.Type type) {
|
||||
return cacheNotifyOnAll
|
||||
|| cacheNotifyOnDelete && (type == PersistRequest.Type.DELETE || type == PersistRequest.Type.DELETE_PERMANENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is currently query caching for this type of bean.
|
||||
*/
|
||||
@@ -105,22 +155,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
return beanCache != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the persist request needs to notify the cache.
|
||||
*/
|
||||
boolean isCacheNotify() {
|
||||
|
||||
if (isBeanCaching() || isQueryCaching()) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < propertiesOneImported.length; i++) {
|
||||
if (propertiesOneImported[i].getTargetDescriptor().isBeanCaching()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CacheOptions getCacheOptions() {
|
||||
return cacheOptions;
|
||||
}
|
||||
@@ -539,7 +573,7 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add appropriate cache changes to support delete.
|
||||
* Add appropriate cache changes to support delete by id.
|
||||
*/
|
||||
void handleDelete(Object id, CacheChangeSet changeSet) {
|
||||
if (beanCache != null) {
|
||||
@@ -549,7 +583,7 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add appropriate cache changes to support delete.
|
||||
* Add appropriate cache changes to support delete bean.
|
||||
*/
|
||||
void handleDelete(Object id, PersistRequestBean<T> deleteRequest, CacheChangeSet changeSet) {
|
||||
queryCacheClear(changeSet);
|
||||
|
||||
@@ -6,11 +6,9 @@ import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.config.EncryptKey;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocMappingBuilder;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyMapping;
|
||||
import com.avaje.ebean.plugin.Property;
|
||||
import com.avaje.ebean.text.StringParser;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedWhenCreated;
|
||||
@@ -28,7 +26,10 @@ import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeBoolean;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeEnum;
|
||||
import com.avaje.ebeaninternal.util.ValueUtil;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocMappingBuilder;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyMapping;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyOptions;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import com.avaje.ebeanservice.docstore.api.support.DocStructure;
|
||||
@@ -45,6 +46,7 @@ import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Description of a property of a bean. Includes its deployment information such
|
||||
@@ -231,11 +233,6 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
*/
|
||||
final String dbComment;
|
||||
|
||||
/**
|
||||
* DB Constraint (typically check constraint on enum)
|
||||
*/
|
||||
final String dbConstraintExpression;
|
||||
|
||||
final DbEncryptFunction dbEncryptFunction;
|
||||
|
||||
int deployOrder;
|
||||
@@ -304,7 +301,6 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
this.dbLength = deploy.getDbLength();
|
||||
this.dbScale = deploy.getDbScale();
|
||||
this.dbColumnDefn = InternString.intern(deploy.getDbColumnDefn());
|
||||
this.dbConstraintExpression = InternString.intern(deploy.getDbConstraintExpression());
|
||||
this.dbColumnDefault = deploy.getDbColumnDefault();
|
||||
|
||||
this.inherited = false;// deploy.isInherited();
|
||||
@@ -414,7 +410,6 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
this.dbLength = source.getDbLength();
|
||||
this.dbScale = source.getDbScale();
|
||||
this.dbColumnDefn = InternString.intern(source.getDbColumnDefn());
|
||||
this.dbConstraintExpression = InternString.intern(source.getDbConstraintExpression());
|
||||
this.dbColumnDefault = source.dbColumnDefault;
|
||||
|
||||
this.inherited = source.isInherited();
|
||||
@@ -977,8 +972,11 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
* For an Enum returns IN expression for the set of Enum values.
|
||||
* </p>
|
||||
*/
|
||||
public String getDbConstraintExpression() {
|
||||
return dbConstraintExpression;
|
||||
public Set<String> getDbCheckConstraintValues() {
|
||||
if (scalarType instanceof ScalarTypeEnum) {
|
||||
return ((ScalarTypeEnum) scalarType).getDbCheckConstraintValues();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -238,13 +238,13 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
|
||||
/**
|
||||
* Return true if this is considered 'empty' from a save perspective.
|
||||
*/
|
||||
public boolean isEmptyBeanCollection(EntityBean bean, boolean insertedParent) {
|
||||
public boolean isSkipSaveBeanCollection(EntityBean bean, boolean insertedParent) {
|
||||
Object val = getValue(bean);
|
||||
if (val == null) {
|
||||
return true;
|
||||
}
|
||||
if ((val instanceof BeanCollection<?>)) {
|
||||
return ((BeanCollection<?>) val).isEmptyAndUntouched();
|
||||
return ((BeanCollection<?>) val).isSkipSave();
|
||||
}
|
||||
if (insertedParent) {
|
||||
// check 'vanilla' collection types
|
||||
|
||||
@@ -134,19 +134,28 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
this.relationshipProperty = relationshipProperty;
|
||||
}
|
||||
|
||||
BeanPropertyAssocMany<?> getRelationshipProperty() {
|
||||
return relationshipProperty;
|
||||
/**
|
||||
* Return true if this relationship needs to maintain/update L2 cache.
|
||||
*/
|
||||
boolean isCacheNotify() {
|
||||
return targetDescriptor.isBeanCaching() && relationshipProperty != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the L2 relationship cache for this property.
|
||||
*/
|
||||
void cacheClear() {
|
||||
if (targetDescriptor.isBeanCaching() && relationshipProperty != null) {
|
||||
if (isCacheNotify()) {
|
||||
targetDescriptor.cacheManyPropClear(relationshipProperty.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear part of the L2 relationship cache for this property.
|
||||
*/
|
||||
void cacheDelete(boolean clear, EntityBean bean, CacheChangeSet changeSet) {
|
||||
|
||||
if (targetDescriptor.isBeanCaching() && relationshipProperty != null) {
|
||||
if (isCacheNotify()) {
|
||||
if (clear) {
|
||||
changeSet.addManyClear(targetDescriptor, relationshipProperty.getName());
|
||||
} else {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.deploy;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
@@ -88,6 +89,25 @@ public class InheritInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append check constraint values for the entire inheritance hierarchy.
|
||||
*/
|
||||
public void appendCheckConstraintValues(final String propertyName, final Set<String> checkConstraintValues) {
|
||||
|
||||
visitChildren(new InheritInfoVisitor() {
|
||||
@Override
|
||||
public void visit(InheritInfo inheritInfo) {
|
||||
BeanProperty prop = inheritInfo.desc().getBeanProperty(propertyName);
|
||||
if (prop != null) {
|
||||
Set<String> values = prop.getDbCheckConstraintValues();
|
||||
if (values != null) {
|
||||
checkConstraintValues.addAll(values);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if anything in the inheritance hierarchy has a relationship with a save cascade on
|
||||
* it.
|
||||
|
||||
@@ -393,17 +393,6 @@ public class DeployBeanProperty {
|
||||
}
|
||||
}
|
||||
|
||||
public String getDbConstraintExpression() {
|
||||
if (scalarType instanceof ScalarTypeEnum) {
|
||||
// create a check constraint for the enum
|
||||
ScalarTypeEnum etype = (ScalarTypeEnum) scalarType;
|
||||
|
||||
// check dbColName IN ('A', 'I', 'D')
|
||||
return "check (" + dbColumn + " in " + etype.getConstraintInValues() + ")";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the scalarType. This returns null for native JDBC types, otherwise
|
||||
* it is used to convert between logical types and jdbc types.
|
||||
|
||||
@@ -185,7 +185,9 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
|
||||
// check each of the beans in the batch to see if they are in the L2 cache.
|
||||
Iterator<EntityBeanIntercept> iterator = list.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
if (context.desc.cacheBeanLoad(iterator.next(), persistenceContext)) {
|
||||
EntityBeanIntercept batchEbi = iterator.next();
|
||||
if (batchEbi != ebi && context.desc.cacheBeanLoad(batchEbi, persistenceContext)) {
|
||||
// bean successfully loaded from L2 cache so remove from batch load
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ public class DLoadContext implements LoadContext {
|
||||
this.readOnly = query.isReadOnly();
|
||||
this.disableReadAudit = query.isDisableReadAudit();
|
||||
this.disableLazyLoading = query.isDisableLazyLoading();
|
||||
this.excludeBeanCache = Boolean.FALSE.equals(query.isUseBeanCache());
|
||||
this.excludeBeanCache = query.isExcludeBeanCache();
|
||||
this.useProfiling = query.getProfilingListener() != null;
|
||||
|
||||
ObjectGraphNode parentNode = query.getParentNode();
|
||||
|
||||
@@ -806,8 +806,8 @@ public final class DefaultPersister implements Persister {
|
||||
// many's with cascade save
|
||||
BeanPropertyAssocMany<?>[] manys = desc.propertiesManySave();
|
||||
for (int i = 0; i < manys.length; i++) {
|
||||
// check that property is loaded and not empty uninitialised collection
|
||||
if (request.isLoadedProperty(manys[i]) && !manys[i].isEmptyBeanCollection(parentBean, insertedParent)) {
|
||||
// check that property is loaded and collection should be cascaded to
|
||||
if (request.isLoadedProperty(manys[i]) && !manys[i].isSkipSaveBeanCollection(parentBean, insertedParent)) {
|
||||
saveMany(new SaveManyPropRequest(insertedParent, manys[i], parentBean, request), insertMode);
|
||||
if (!insertedParent) {
|
||||
request.addUpdatedManyProperty(manys[i]);
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionTouched;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
@@ -300,14 +299,6 @@ public class CQueryEngine {
|
||||
}
|
||||
|
||||
BeanCollection<T> beanCollection = cquery.readCollection();
|
||||
|
||||
BeanCollectionTouched collectionTouched = query.getBeanCollectionTouched();
|
||||
if (collectionTouched != null) {
|
||||
// register a listener that wants to be notified when the
|
||||
// bean collection is first used
|
||||
beanCollection.setBeanCollectionTouched(collectionTouched);
|
||||
}
|
||||
|
||||
if (request.isLogSummary()) {
|
||||
logFindManySummary(cquery);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.RawSql.ColumnMapping;
|
||||
import com.avaje.ebean.config.dbplatform.SqlLimitResponse;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.type.DataReader;
|
||||
import com.avaje.ebeaninternal.server.type.RsetDataReaderIndexed;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* RawSql based query plan.
|
||||
*/
|
||||
@@ -18,9 +17,7 @@ public class CQueryPlanRawSql extends CQueryPlan {
|
||||
private final int[] rsetIndexPositions;
|
||||
|
||||
public CQueryPlanRawSql(OrmQueryRequest<?> request, SqlLimitResponse sqlRes, SqlTree sqlTree, String logWhereSql) {
|
||||
|
||||
super(request, sqlRes, sqlTree, true, logWhereSql);
|
||||
|
||||
this.rsetIndexPositions = createIndexPositions(request, sqlTree);
|
||||
}
|
||||
|
||||
@@ -34,23 +31,11 @@ public class CQueryPlanRawSql extends CQueryPlan {
|
||||
List<String> chain = sqlTree.buildRawSqlSelectChain();
|
||||
ColumnMapping columnMapping = request.getQuery().getRawSql().getColumnMapping();
|
||||
|
||||
// if the top level bean has inheritance expect first column
|
||||
// to be the discriminator type column (and use offset 1)
|
||||
InheritInfo inheritInfo = request.getBeanDescriptor().getInheritInfo();
|
||||
boolean addDiscriminator = inheritInfo != null;
|
||||
int offset = addDiscriminator ? 1 : 0;
|
||||
|
||||
int[] indexPositions = new int[chain.size() + offset];
|
||||
if (addDiscriminator) {
|
||||
// discriminator column must always be first in the query
|
||||
indexPositions[0] = 1;
|
||||
}
|
||||
int[] indexPositions = new int[chain.size()];
|
||||
|
||||
// set the resultSet index positions for the property expressions
|
||||
for (int i = 0; i < chain.size(); i++) {
|
||||
String expr = chain.get(i);
|
||||
int indexPos = 1 + columnMapping.getIndexPosition(expr);
|
||||
indexPositions[i + offset] = indexPos;
|
||||
indexPositions[i] = 1 + columnMapping.getIndexPosition(chain.get(i));
|
||||
}
|
||||
|
||||
// check and handle the case where a discriminator column for
|
||||
|
||||
@@ -74,19 +74,9 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine {
|
||||
try {
|
||||
request.executeSql(binder);
|
||||
|
||||
int maxRows = request.getMaxRows();
|
||||
|
||||
int loadRowCount = 0;
|
||||
|
||||
List<SqlRow> rows = new ArrayList<SqlRow>();
|
||||
|
||||
while (request.next()) {
|
||||
rows.add(readRow(request));
|
||||
loadRowCount++;
|
||||
if (loadRowCount == maxRows) {
|
||||
// break, as we have hit the max rows to fetch...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
logSummary(request, startTime);
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
|
||||
|
||||
/**
|
||||
* Special Map of the logical property joins to table alias.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class SqlTreeAlias {
|
||||
|
||||
@@ -61,7 +60,10 @@ public class SqlTreeAlias {
|
||||
if (propJoins != null) {
|
||||
for (String propJoin : propJoins) {
|
||||
ElPropertyDeploy elProp = desc.getElPropertyDeploy(propJoin);
|
||||
if (elProp != null && elProp.getBeanProperty().isEmbedded()) {
|
||||
if (elProp == null) {
|
||||
throw new PersistenceException("Invalid path " + propJoin + " from " + desc.getFullName());
|
||||
|
||||
} else if (elProp.getBeanProperty().isEmbedded()) {
|
||||
addEmbeddedPropertyJoin(propJoin);
|
||||
|
||||
} else {
|
||||
|
||||
@@ -160,6 +160,10 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
|
||||
public void buildRawSqlSelectChain(List<String> selectChain) {
|
||||
if (readId) {
|
||||
if (desc.hasInheritance()) {
|
||||
// discriminator column always proceeds id column
|
||||
selectChain.add(getPath(prefix, desc.getInheritInfo().getDiscriminatorColumn()));
|
||||
}
|
||||
idBinder.buildRawSqlSelectChain(prefix, selectChain);
|
||||
}
|
||||
for (int i = 0, x = properties.length; i < x; i++) {
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.avaje.ebeaninternal.server.querydefn;
|
||||
|
||||
import com.avaje.ebean.*;
|
||||
import com.avaje.ebean.OrderBy.Property;
|
||||
import com.avaje.ebean.bean.BeanCollectionTouched;
|
||||
import com.avaje.ebean.bean.CallStack;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.ObjectGraphOrigin;
|
||||
@@ -48,8 +47,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
private final EbeanServer server;
|
||||
|
||||
private BeanCollectionTouched beanCollectionTouched;
|
||||
|
||||
private final ExpressionFactory expressionFactory;
|
||||
|
||||
/**
|
||||
@@ -189,7 +186,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
private boolean loadBeanCache;
|
||||
|
||||
private Boolean useBeanCache;
|
||||
private boolean excludeBeanCache;
|
||||
|
||||
private Boolean useQueryCache;
|
||||
|
||||
@@ -330,6 +327,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
* This table alias is for a @History entity involved in the query and as
|
||||
* such we need to add a 'as of predicate' to the query using this alias.
|
||||
*/
|
||||
@Override
|
||||
public void addAsOfTableAlias(String tableAlias) {
|
||||
if (asOfTableAlias == null) {
|
||||
asOfTableAlias = new ArrayList<String>();
|
||||
@@ -337,20 +335,24 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
asOfTableAlias.add(tableAlias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAsOfTableAlias() {
|
||||
return asOfTableAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timestamp getAsOf() {
|
||||
return asOf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> asOf(Timestamp asOfDateTime) {
|
||||
this.temporalMode = (asOfDateTime != null) ? TemporalMode.AS_OF : TemporalMode.CURRENT;
|
||||
this.asOf = asOfDateTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> asDraft() {
|
||||
this.temporalMode = TemporalMode.DRAFT;
|
||||
return this;
|
||||
@@ -367,10 +369,12 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RawSql getRawSql() {
|
||||
return rawSql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setRawSql(RawSql rawSql) {
|
||||
this.rawSql = rawSql;
|
||||
return this;
|
||||
@@ -381,19 +385,23 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return lazyLoadBatchSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setLazyLoadBatchSize(int lazyLoadBatchSize) {
|
||||
this.lazyLoadBatchSize = lazyLoadBatchSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLazyLoadProperty() {
|
||||
return lazyLoadProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLazyLoadProperty(String lazyLoadProperty) {
|
||||
this.lazyLoadProperty = lazyLoadProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionFactory getExpressionFactory() {
|
||||
return expressionFactory;
|
||||
}
|
||||
@@ -411,6 +419,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Return the extra joins required to support the where clause for 'Many' properties.
|
||||
*/
|
||||
@Override
|
||||
public ManyWhereJoins getManyWhereJoins() {
|
||||
return manyWhereJoins;
|
||||
}
|
||||
@@ -419,6 +428,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
* Return true if select all properties was used to ensure the property invoking a lazy load was
|
||||
* included in the query.
|
||||
*/
|
||||
@Override
|
||||
public boolean selectAllForLazyLoadProperty() {
|
||||
if (lazyLoadProperty != null) {
|
||||
if (!detail.containsProperty(lazyLoadProperty)) {
|
||||
@@ -461,6 +471,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return detail.removeSecondaryLazyQueries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLazyLoadManyPath(String lazyLoadManyPath) {
|
||||
this.lazyLoadManyPath = lazyLoadManyPath;
|
||||
}
|
||||
@@ -495,28 +506,34 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
this.detail = detail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultSelectClause() {
|
||||
detail.setDefaultSelectClause(beanDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDetail(OrmQueryDetail detail) {
|
||||
this.detail = detail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tuneFetchProperties(OrmQueryDetail tunedDetail) {
|
||||
return detail.tuneFetchProperties(tunedDetail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrmQueryDetail getDetail() {
|
||||
return detail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> filterMany(String prop) {
|
||||
|
||||
OrmQueryProperties chunk = detail.getChunk(prop, true);
|
||||
return chunk.filterMany(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFilterMany(String prop, ExpressionList<?> filterMany) {
|
||||
if (filterMany != null) {
|
||||
OrmQueryProperties chunk = detail.getChunk(prop, true);
|
||||
@@ -527,6 +544,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Setup to be a delete query.
|
||||
*/
|
||||
@Override
|
||||
public void setDelete() {
|
||||
// unset any paging and select on the id in the case where the query
|
||||
// includes joins and we use - delete ... where id in (...)
|
||||
@@ -540,12 +558,14 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Set the select clause to select the Id property.
|
||||
*/
|
||||
@Override
|
||||
public void setSelectId() {
|
||||
// clear select and fetch joins..
|
||||
detail.clear();
|
||||
select(beanDescriptor.getIdBinder().getIdProperty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalKeyBindParam getNaturalKeyBindParam() {
|
||||
NaturalKeyBindParam namedBind = null;
|
||||
if (bindParams != null) {
|
||||
@@ -577,10 +597,12 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> copy() {
|
||||
return copy(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> copy(EbeanServer server) {
|
||||
|
||||
DefaultOrmQuery<T> copy = new DefaultOrmQuery<T>(beanDescriptor, server, expressionFactory, (String) null);
|
||||
@@ -598,7 +620,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
copy.mapKey = mapKey;
|
||||
copy.id = id;
|
||||
copy.loadBeanCache = loadBeanCache;
|
||||
copy.useBeanCache = useBeanCache;
|
||||
copy.excludeBeanCache = excludeBeanCache;
|
||||
copy.useQueryCache = useQueryCache;
|
||||
copy.readOnly = readOnly;
|
||||
copy.sqlSelect = sqlSelect;
|
||||
@@ -637,26 +659,32 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistenceContextScope getPersistenceContextScope() {
|
||||
return persistenceContextScope;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLoadDescription() {
|
||||
return loadDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLoadMode() {
|
||||
return loadMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoadDescription(String loadMode, String loadDescription) {
|
||||
this.loadMode = loadMode;
|
||||
this.loadDescription = loadDescription;
|
||||
@@ -669,6 +697,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
* Transaction is used (transaction scoped persistence context).
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return persistenceContext;
|
||||
}
|
||||
@@ -680,6 +709,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
* Transaction is used (transaction scoped persistence context).
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public void setPersistenceContext(PersistenceContext persistenceContext) {
|
||||
this.persistenceContext = persistenceContext;
|
||||
}
|
||||
@@ -697,26 +727,32 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Return true if the query detail has neither select or joins specified.
|
||||
*/
|
||||
@Override
|
||||
public boolean isDetailEmpty() {
|
||||
return detail.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoTuned() {
|
||||
return autoTuned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutoTuned(boolean autoTuned) {
|
||||
this.autoTuned = autoTuned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isAutoTune() {
|
||||
return sqlSelect ? Boolean.FALSE : autoTune;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForUpdate() {
|
||||
return forUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setAutoTune(boolean autoTune) {
|
||||
this.autoTune = autoTune;
|
||||
return this;
|
||||
@@ -748,6 +784,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return temporalMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAsOfQuery() {
|
||||
return asOf != null;
|
||||
}
|
||||
@@ -762,22 +799,27 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return TemporalMode.SOFT_DELETED == temporalMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMode(Mode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsageProfiling() {
|
||||
return usageProfiling;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsageProfiling(boolean usageProfiling) {
|
||||
this.usageProfiling = usageProfiling;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogSecondaryQuery(boolean logSecondaryQuery) {
|
||||
this.logSecondaryQuery = logSecondaryQuery;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLogSecondaryQuery() {
|
||||
return logSecondaryQuery;
|
||||
}
|
||||
@@ -789,6 +831,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return loggedSecondaryQueries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logSecondaryQuery(SpiQuery<?> query) {
|
||||
if (loggedSecondaryQueries == null) {
|
||||
loggedSecondaryQueries = new ArrayList<SpiQuery<?>>();
|
||||
@@ -796,14 +839,17 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
loggedSecondaryQueries.add(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParentNode(ObjectGraphNode parentNode) {
|
||||
this.parentNode = parentNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectGraphNode getParentNode() {
|
||||
return parentNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectGraphNode setOrigin(CallStack callStack) {
|
||||
|
||||
// create a 'origin' which links this query to the profiling information
|
||||
@@ -845,6 +891,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Prepare the query which prepares any expressions (sub-query expressions etc) and calculates the query plan key.
|
||||
*/
|
||||
@Override
|
||||
public CQueryPlanKey prepare(BeanQueryRequest<?> request) {
|
||||
|
||||
prepareExpressions(request);
|
||||
@@ -871,6 +918,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
* Used with queryPlanHash() to get a unique hash for a query.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hc = (id == null ? 0 : id.hashCode());
|
||||
hc = hc * 31 + (whereExpressions == null ? 0 : whereExpressions.queryBindHash());
|
||||
@@ -889,6 +937,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
* values) before.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public HashQuery queryHash() {
|
||||
// calculateQueryPlanHash is called just after potential AutoTune tuning
|
||||
// so queryPlanHash is calculated well before this method is called
|
||||
@@ -900,14 +949,17 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Return the query name.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSqlSelect() {
|
||||
return sqlSelect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRawSql() {
|
||||
return rawSql != null;
|
||||
}
|
||||
@@ -915,6 +967,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Return any additional where clauses.
|
||||
*/
|
||||
@Override
|
||||
public String getAdditionalWhere() {
|
||||
return additionalWhere;
|
||||
}
|
||||
@@ -922,6 +975,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Return the timeout.
|
||||
*/
|
||||
@Override
|
||||
public int getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
@@ -929,10 +983,12 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Return any additional having clauses.
|
||||
*/
|
||||
@Override
|
||||
public String getAdditionalHaving() {
|
||||
return additionalHaving;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMaxRowsOrFirstRow() {
|
||||
return maxRows > 0 || firstRow > 0;
|
||||
}
|
||||
@@ -952,45 +1008,58 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return versionsEnd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean isUseBeanCache() {
|
||||
public boolean isExcludeBeanCache() {
|
||||
// not using L2 cache for asDraft() query
|
||||
return isAsDraft() ? Boolean.FALSE : useBeanCache;
|
||||
return excludeBeanCache || isAsDraft() ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseBeanCache() {
|
||||
return !isExcludeBeanCache() && beanDescriptor.isBeanCaching();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseQueryCache() {
|
||||
// not using L2 cache for asDraft() query
|
||||
return !isAsDraft() && Boolean.TRUE.equals(useQueryCache);
|
||||
}
|
||||
|
||||
public DefaultOrmQuery<T> setUseCache(boolean useBeanCache) {
|
||||
this.useBeanCache = useBeanCache;
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setUseCache(boolean useCache) {
|
||||
this.excludeBeanCache = !useCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setUseQueryCache(boolean useQueryCache) {
|
||||
this.useQueryCache = useQueryCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoadBeanCache() {
|
||||
// not using L2 cache for asDraft() query
|
||||
return !isAsDraft() && loadBeanCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setLoadBeanCache(boolean loadBeanCache) {
|
||||
this.loadBeanCache = loadBeanCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setTimeout(int secs) {
|
||||
this.timeout = secs;
|
||||
return this;
|
||||
@@ -1010,23 +1079,28 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
this.rawWhereClause = rawWhereClause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> select(String columns) {
|
||||
detail.select(columns);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> fetch(String property) {
|
||||
return fetch(property, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> fetch(String property, FetchConfig joinConfig) {
|
||||
return fetch(property, null, joinConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> fetch(String property, String columns) {
|
||||
return fetch(property, columns, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> fetch(String property, String columns, FetchConfig config) {
|
||||
detail.fetch(property, columns, config);
|
||||
return this;
|
||||
@@ -1037,6 +1111,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return server.delete(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> findIds() {
|
||||
// a copy of this query is made in the server
|
||||
// as the query needs to modified (so we modify
|
||||
@@ -1044,6 +1119,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return server.findIds(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findRowCount() {
|
||||
// a copy of this query is made in the server
|
||||
// as the query needs to modified (so we modify
|
||||
@@ -1078,40 +1154,49 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return server.findVersions(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryIterator<T> findIterate() {
|
||||
return server.findIterate(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> findList() {
|
||||
return server.findList(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<T> findSet() {
|
||||
return server.findSet(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<?, T> findMap() {
|
||||
return server.findMap(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
|
||||
setMapKey(keyProperty);
|
||||
return (Map<K, T>) findMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T findUnique() {
|
||||
return server.findUnique(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FutureIds<T> findFutureIds() {
|
||||
return server.findFutureIds(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FutureList<T> findFutureList() {
|
||||
return server.findFutureList(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FutureRowCount<T> findFutureRowCount() {
|
||||
return server.findFutureRowCount(this, null);
|
||||
}
|
||||
@@ -1131,6 +1216,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
* be consistent with JDBC PreparedStatement. You need to set a parameter value for each ? you
|
||||
* have in the query.
|
||||
*/
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setParameter(int position, Object value) {
|
||||
if (bindParams == null) {
|
||||
bindParams = new BindParams();
|
||||
@@ -1142,6 +1228,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Set a named bind parameter. Named parameters have a colon to prefix the name.
|
||||
*/
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setParameter(String name, Object value) {
|
||||
if (bindParams == null) {
|
||||
bindParams = new BindParams();
|
||||
@@ -1150,6 +1237,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderBy<T> getOrderBy() {
|
||||
return orderBy;
|
||||
}
|
||||
@@ -1157,14 +1245,17 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Return the order by clause.
|
||||
*/
|
||||
@Override
|
||||
public String getRawWhereClause() {
|
||||
return rawWhereClause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderBy<T> orderBy() {
|
||||
return order();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderBy<T> order() {
|
||||
if (orderBy == null) {
|
||||
orderBy = new OrderBy<T>(this, null);
|
||||
@@ -1172,10 +1263,12 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return orderBy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> orderBy(String orderByClause) {
|
||||
return order(orderByClause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> order(String orderByClause) {
|
||||
if (orderByClause == null || orderByClause.trim().length() == 0) {
|
||||
this.orderBy = null;
|
||||
@@ -1185,10 +1278,12 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setOrderBy(OrderBy<T> orderBy) {
|
||||
return setOrder(orderBy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setOrder(OrderBy<T> orderBy) {
|
||||
this.orderBy = orderBy;
|
||||
if (orderBy != null) {
|
||||
@@ -1200,6 +1295,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* return true if user specified to use SQL DISTINCT (effectively excludes id property).
|
||||
*/
|
||||
@Override
|
||||
public boolean isDistinct() {
|
||||
return distinct;
|
||||
}
|
||||
@@ -1207,6 +1303,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Internally set to use SQL DISTINCT on the query but still have id property included.
|
||||
*/
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setDistinct(boolean distinct) {
|
||||
this.distinct = distinct;
|
||||
return this;
|
||||
@@ -1216,6 +1313,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
* Return true if this query uses SQL DISTINCT either explicitly by the user or internally defined
|
||||
* by ebean.
|
||||
*/
|
||||
@Override
|
||||
public boolean isDistinctQuery() {
|
||||
return distinct || sqlDistinct;
|
||||
}
|
||||
@@ -1223,10 +1321,12 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Internally set to use SQL DISTINCT on the query but still have id property included.
|
||||
*/
|
||||
@Override
|
||||
public void setSqlDistinct(boolean sqlDistinct) {
|
||||
this.sqlDistinct = sqlDistinct;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getBeanType() {
|
||||
return beanType;
|
||||
}
|
||||
@@ -1235,10 +1335,12 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return "Query [" + whereExpressions + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableJoin getIncludeTableJoin() {
|
||||
return includeTableJoin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIncludeTableJoin(TableJoin includeTableJoin) {
|
||||
this.includeTableJoin = includeTableJoin;
|
||||
}
|
||||
@@ -1249,41 +1351,50 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisableLazyLoading() {
|
||||
return disableLazyLoading;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstRow() {
|
||||
return firstRow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setFirstRow(int firstRow) {
|
||||
this.firstRow = firstRow;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxRows() {
|
||||
return maxRows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setMaxRows(int maxRows) {
|
||||
this.maxRows = maxRows;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMapKey() {
|
||||
return mapKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setMapKey(String mapKey) {
|
||||
this.mapKey = mapKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setId(Object id) {
|
||||
if (id == null) {
|
||||
throw new NullPointerException("The id is null");
|
||||
@@ -1292,14 +1403,17 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BindParams getBindParams() {
|
||||
return bindParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> where(String addToWhereClause) {
|
||||
if (additionalWhere == null) {
|
||||
additionalWhere = addToWhereClause;
|
||||
@@ -1309,6 +1423,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> where(Expression expression) {
|
||||
if (whereExpressions == null) {
|
||||
whereExpressions = new DefaultExpressionList<T>(this, null);
|
||||
@@ -1326,6 +1441,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return textExpressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> where() {
|
||||
if (whereExpressions == null) {
|
||||
whereExpressions = new DefaultExpressionList<T>(this, null);
|
||||
@@ -1333,6 +1449,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return whereExpressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> having(String addToHavingClause) {
|
||||
if (additionalHaving == null) {
|
||||
additionalHaving = addToHavingClause;
|
||||
@@ -1342,6 +1459,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> having(Expression expression) {
|
||||
if (havingExpressions == null) {
|
||||
havingExpressions = new DefaultExpressionList<T>(this, null);
|
||||
@@ -1350,6 +1468,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> having() {
|
||||
if (havingExpressions == null) {
|
||||
havingExpressions = new DefaultExpressionList<T>(this, null);
|
||||
@@ -1357,10 +1476,12 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return havingExpressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiExpressionList<T> getHavingExpressions() {
|
||||
return havingExpressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiExpressionList<T> getWhereExpressions() {
|
||||
return whereExpressions;
|
||||
}
|
||||
@@ -1370,19 +1491,23 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return textExpressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGeneratedSql() {
|
||||
return generatedSql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGeneratedSql(String generatedSql) {
|
||||
this.generatedSql = generatedSql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setBufferFetchSizeHint(int bufferFetchSizeHint) {
|
||||
this.bufferFetchSizeHint = bufferFetchSizeHint;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBufferFetchSizeHint() {
|
||||
return bufferFetchSizeHint;
|
||||
}
|
||||
@@ -1393,30 +1518,27 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisableReadAudit() {
|
||||
return disableReadAudit;
|
||||
}
|
||||
|
||||
public void setBeanCollectionTouched(BeanCollectionTouched notify) {
|
||||
this.beanCollectionTouched = notify;
|
||||
}
|
||||
|
||||
public BeanCollectionTouched getBeanCollectionTouched() {
|
||||
return beanCollectionTouched;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> getIdList() {
|
||||
return partialIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdList(List<Object> partialIds) {
|
||||
this.partialIds = partialIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFutureFetch() {
|
||||
return futureFetch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFutureFetch(boolean backgroundFetch) {
|
||||
this.futureFetch = backgroundFetch;
|
||||
}
|
||||
@@ -1431,6 +1553,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return futureFetchAudit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelableQuery(CancelableQuery cancelableQuery) {
|
||||
synchronized (this) {
|
||||
this.cancelableQuery = cancelableQuery;
|
||||
@@ -1448,6 +1571,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return rootTableAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
synchronized (this) {
|
||||
cancelled = true;
|
||||
@@ -1457,6 +1581,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
synchronized (this) {
|
||||
return cancelled;
|
||||
@@ -1471,6 +1596,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Validate all the expression properties/paths given the bean descriptor.
|
||||
*/
|
||||
@Override
|
||||
public Set<String> validate(BeanType<T> desc) {
|
||||
|
||||
SpiExpressionValidation validation = new SpiExpressionValidation(desc);
|
||||
|
||||
@@ -353,7 +353,10 @@ public class OrmQueryDetail implements Serializable {
|
||||
|
||||
for (String fetchPath : fetchPaths.keySet()) {
|
||||
ElPropertyDeploy elProp = beanDescriptor.getElPropertyDeploy(fetchPath);
|
||||
if (elProp != null && elProp.containsManySince(manyFetchProperty)) {
|
||||
if (elProp == null) {
|
||||
throw new PersistenceException("Invalid fetch path " + fetchPath + " from " + beanDescriptor.getFullName());
|
||||
}
|
||||
if (elProp.containsManySince(manyFetchProperty)) {
|
||||
|
||||
// this is a join to a *ToMany
|
||||
OrmQueryProperties chunk = fetchPaths.get(fetchPath);
|
||||
|
||||
@@ -500,6 +500,11 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
return batchOnCascadeMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getBatchGetGeneratedKeys() {
|
||||
return batchGetGeneratedKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBatchGetGeneratedKeys(boolean getGeneratedKeys) {
|
||||
this.batchGetGeneratedKeys = getGeneratedKeys;
|
||||
|
||||
@@ -37,9 +37,9 @@ public interface ArrayElementConverter<T> {
|
||||
@Override
|
||||
public Long toElement(Object rawValue) {
|
||||
if (rawValue instanceof Long) {
|
||||
return (Long)rawValue;
|
||||
return (Long) rawValue;
|
||||
} else {
|
||||
return ((Number)rawValue).longValue();
|
||||
return ((Number) rawValue).longValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,9 +49,9 @@ public interface ArrayElementConverter<T> {
|
||||
@Override
|
||||
public Integer toElement(Object rawValue) {
|
||||
if (rawValue instanceof Integer) {
|
||||
return (Integer)rawValue;
|
||||
return (Integer) rawValue;
|
||||
} else {
|
||||
return ((Number)rawValue).intValue();
|
||||
return ((Number) rawValue).intValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ public interface ArrayElementConverter<T> {
|
||||
|
||||
@Override
|
||||
public T toElement(Object rawValue) {
|
||||
return (T)rawValue;
|
||||
return (T) rawValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ public class CompoundTypePeriod implements CompoundType<Period> {
|
||||
|
||||
@Override
|
||||
public Period create(Object[] propertyValues) {
|
||||
return Period.of((Integer)propertyValues[0], (Integer)propertyValues[1], (Integer)propertyValues[2]);
|
||||
return Period.of((Integer) propertyValues[0], (Integer) propertyValues[1], (Integer) propertyValues[2]);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,69 +1,67 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebean.config.CompoundTypeProperty;
|
||||
import com.avaje.ebeaninternal.server.query.SplitName;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.config.CompoundTypeProperty;
|
||||
import com.avaje.ebeaninternal.server.query.SplitName;
|
||||
|
||||
/**
|
||||
* Used to build a flat list of all the scalar types nested in a compound type.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public final class CtCompoundTypeScalarList {
|
||||
|
||||
private final LinkedHashMap<String,ScalarType<?>> scalarProps = new LinkedHashMap<String,ScalarType<?>>();
|
||||
private final LinkedHashMap<String, ScalarType<?>> scalarProps = new LinkedHashMap<String, ScalarType<?>>();
|
||||
|
||||
private final LinkedHashMap<String,CtCompoundProperty> compoundProperties = new LinkedHashMap<String, CtCompoundProperty>();
|
||||
|
||||
/**
|
||||
* Return the list of non-scalar properties. These occur when compound types are nested.
|
||||
*/
|
||||
public List<CtCompoundProperty> getNonScalarProperties() {
|
||||
|
||||
List<CtCompoundProperty> nonScalarProps = new ArrayList<CtCompoundProperty>();
|
||||
|
||||
for (String propKey: compoundProperties.keySet()) {
|
||||
if (!scalarProps.containsKey(propKey)){
|
||||
nonScalarProps.add(compoundProperties.get(propKey));
|
||||
}
|
||||
}
|
||||
|
||||
return nonScalarProps;
|
||||
private final LinkedHashMap<String, CtCompoundProperty> compoundProperties = new LinkedHashMap<String, CtCompoundProperty>();
|
||||
|
||||
/**
|
||||
* Return the list of non-scalar properties. These occur when compound types are nested.
|
||||
*/
|
||||
public List<CtCompoundProperty> getNonScalarProperties() {
|
||||
|
||||
List<CtCompoundProperty> nonScalarProps = new ArrayList<CtCompoundProperty>();
|
||||
|
||||
for (String propKey : compoundProperties.keySet()) {
|
||||
if (!scalarProps.containsKey(propKey)) {
|
||||
nonScalarProps.add(compoundProperties.get(propKey));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a property with it's associated compound type and relative name.
|
||||
*/
|
||||
public void addCompoundProperty(String propName, CtCompoundType<?> t, CompoundTypeProperty<?,?> prop) {
|
||||
|
||||
CtCompoundProperty parent = null;
|
||||
String[] split = SplitName.split(propName);
|
||||
if (split[0] != null){
|
||||
parent = compoundProperties.get(split[0]);
|
||||
}
|
||||
|
||||
CtCompoundProperty p = new CtCompoundProperty(propName, parent, t, prop);
|
||||
compoundProperties.put(propName, p);
|
||||
|
||||
return nonScalarProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a property with it's associated compound type and relative name.
|
||||
*/
|
||||
public void addCompoundProperty(String propName, CtCompoundType<?> t, CompoundTypeProperty<?, ?> prop) {
|
||||
|
||||
CtCompoundProperty parent = null;
|
||||
String[] split = SplitName.split(propName);
|
||||
if (split[0] != null) {
|
||||
parent = compoundProperties.get(split[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a scalarType used in the compound type with its given property name.
|
||||
*/
|
||||
public void addScalarType(String propName, ScalarType<?> scalar){
|
||||
scalarProps.put(propName, scalar);
|
||||
}
|
||||
|
||||
public CtCompoundProperty getCompoundType(String propName) {
|
||||
return compoundProperties.get(propName);
|
||||
}
|
||||
|
||||
public Set<Entry<String, ScalarType<?>>> entries() {
|
||||
return scalarProps.entrySet();
|
||||
}
|
||||
|
||||
|
||||
CtCompoundProperty p = new CtCompoundProperty(propName, parent, t, prop);
|
||||
compoundProperties.put(propName, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a scalarType used in the compound type with its given property name.
|
||||
*/
|
||||
public void addScalarType(String propName, ScalarType<?> scalar) {
|
||||
scalarProps.put(propName, scalar);
|
||||
}
|
||||
|
||||
public CtCompoundProperty getCompoundType(String propName) {
|
||||
return compoundProperties.get(propName);
|
||||
}
|
||||
|
||||
public Set<Entry<String, ScalarType<?>>> entries() {
|
||||
return scalarProps.entrySet();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Array;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@@ -61,7 +61,7 @@ public final class DecimalUtils {
|
||||
|
||||
public static BigDecimal toDecimal(Timestamp instant) {
|
||||
long millis = instant.getTime();
|
||||
long secs = millis/1000;
|
||||
long secs = millis / 1000;
|
||||
return new BigDecimal(toDecimal(secs, instant.getNanos()));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.sql.Types;
|
||||
import java.util.Calendar;
|
||||
|
||||
import com.avaje.ebean.config.JsonConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.sql.Types;
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* Helper to create some default ScalarType objects for Booleans,
|
||||
* java.util.Date, java.util.Calendar etc.
|
||||
|
||||
@@ -377,7 +377,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
// fallback to JSON storage in VARCHAR column
|
||||
return new ScalarTypeJsonList.Varchar(getDocType(getValueType(genericType)));
|
||||
}
|
||||
throw new IllegalStateException("Type ["+type+"] not supported for @DbArray");
|
||||
throw new IllegalStateException("Type [" + type + "] not supported for @DbArray");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -411,11 +411,16 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
|
||||
if (type.equals(JsonNode.class)) {
|
||||
switch (dbType) {
|
||||
case Types.VARCHAR : return jsonNodeVarchar;
|
||||
case Types.BLOB: return jsonNodeBlob;
|
||||
case Types.CLOB : return jsonNodeClob;
|
||||
case DbType.JSONB: return jsonNodeJsonb;
|
||||
case DbType.JSON: return jsonNodeJson;
|
||||
case Types.VARCHAR:
|
||||
return jsonNodeVarchar;
|
||||
case Types.BLOB:
|
||||
return jsonNodeBlob;
|
||||
case Types.CLOB:
|
||||
return jsonNodeClob;
|
||||
case DbType.JSONB:
|
||||
return jsonNodeJsonb;
|
||||
case DbType.JSON:
|
||||
return jsonNodeJson;
|
||||
default:
|
||||
return jsonNodeJson;
|
||||
}
|
||||
@@ -520,11 +525,9 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
|
||||
/**
|
||||
* Convert the Object to the required datatype. The
|
||||
*
|
||||
* @param value
|
||||
* the Object value
|
||||
* @param toJdbcType
|
||||
* the type as per java.sql.Types.
|
||||
*
|
||||
* @param value the Object value
|
||||
* @param toJdbcType the type as per java.sql.Types.
|
||||
*/
|
||||
public Object convert(Object value, int toJdbcType) {
|
||||
if (value == null) {
|
||||
@@ -586,7 +589,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
|
||||
return createEnumScalarType(enumType, nameValueMap, integerType, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a ScalarType for an Enum that has additional mapping.
|
||||
* <p>
|
||||
@@ -599,7 +602,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
public ScalarType<?> createEnumScalarType(Class<? extends Enum<?>> enumType) {
|
||||
|
||||
Method[] methods = enumType.getMethods();
|
||||
for (int i = 0; i <methods.length; i++) {
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
DbEnumValue dbValue = methods[i].getAnnotation(DbEnumValue.class);
|
||||
if (dbValue != null) {
|
||||
boolean integerValues = DbEnumType.INTEGER == dbValue.storage();
|
||||
@@ -628,7 +631,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
Object value = method.invoke(enumConstants[i]);
|
||||
nameValueMap.put(enumConstants[i].name(), value.toString());
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Error trying to invoke DbEnumValue method on "+enumConstants[i], e);
|
||||
throw new IllegalArgumentException("Error trying to invoke DbEnumValue method on " + enumConstants[i], e);
|
||||
}
|
||||
}
|
||||
if (nameValueMap.isEmpty()) {
|
||||
@@ -643,14 +646,14 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
* Given the name value mapping and integer/string type and explicit DB column
|
||||
* length create the ScalarType for the Enum.
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private ScalarType<?> createEnumScalarType(Class enumType, Map<String, String> nameValueMap, boolean integerType, int dbColumnLength) {
|
||||
|
||||
EnumToDbValueMap<?> beanDbMap = EnumToDbValueMap.create(integerType);
|
||||
|
||||
int maxValueLen = 0;
|
||||
|
||||
for (Map.Entry<String,String> entry : nameValueMap.entrySet()) {
|
||||
for (Map.Entry<String, String> entry : nameValueMap.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
|
||||
@@ -694,7 +697,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
try {
|
||||
// first try objectMapper constructor
|
||||
Constructor<?> constructor = cls.getConstructor(ObjectMapper.class);
|
||||
scalarType = (ScalarType<?>)constructor.newInstance((ObjectMapper)objectMapper);
|
||||
scalarType = (ScalarType<?>) constructor.newInstance((ObjectMapper) objectMapper);
|
||||
} catch (NoSuchMethodException e) {
|
||||
scalarType = (ScalarType<?>) cls.newInstance();
|
||||
}
|
||||
@@ -720,7 +723,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
protected void initialiseScalarConverters(BootupClasses bootupClasses) {
|
||||
|
||||
List<Class<?>> foundTypes = bootupClasses.getScalarConverters();
|
||||
@@ -782,7 +785,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
protected CtCompoundType createCompoundScalarDataReader(Class<?> compoundTypeClass, CompoundType<?> compoundType, String info) {
|
||||
|
||||
CtCompoundType<?> ctCompoundType = compoundTypeMap.get(compoundTypeClass);
|
||||
@@ -844,7 +847,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
|
||||
logger.trace("Registering JsonNode type support");
|
||||
|
||||
ObjectMapper mapper = (ObjectMapper)objectMapper;
|
||||
ObjectMapper mapper = (ObjectMapper) objectMapper;
|
||||
jsonNodeClob = new ScalarTypeJsonNode.Clob(mapper);
|
||||
jsonNodeBlob = new ScalarTypeJsonNode.Blob(mapper);
|
||||
jsonNodeVarchar = new ScalarTypeJsonNode.Varchar(mapper);
|
||||
@@ -887,10 +890,10 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
createCompoundScalarDataReader(Period.class, new CompoundTypePeriod(), "");
|
||||
|
||||
boolean localTimeNanos = config.isLocalTimeWithNanos();
|
||||
typeMap.put(java.time.LocalTime.class, (localTimeNanos)? new ScalarTypeLocalTimeWithNanos() : new ScalarTypeLocalTime());
|
||||
typeMap.put(java.time.LocalTime.class, (localTimeNanos) ? new ScalarTypeLocalTimeWithNanos() : new ScalarTypeLocalTime());
|
||||
|
||||
boolean durationNanos = config.isDurationWithNanos();
|
||||
typeMap.put(Duration.class, (durationNanos)? new ScalarTypeDurationWithNanos() : new ScalarTypeDuration());
|
||||
typeMap.put(Duration.class, (durationNanos) ? new ScalarTypeDurationWithNanos() : new ScalarTypeDuration());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -921,7 +924,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register all the standard types supported. This is the standard JDBC types
|
||||
* plus some other common types such as java.util.Date and java.util.Calendar.
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
/**
|
||||
* Used to map enum values to database integer values.
|
||||
*/
|
||||
|
||||
+73
-76
@@ -10,89 +10,86 @@ import java.util.Map;
|
||||
* been collected then the immutable compound value object is created and
|
||||
* returned.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public final class ImmutableCompoundTypeBuilder {
|
||||
|
||||
private static final ThreadLocal<ImmutableCompoundTypeBuilder> local = new ThreadLocal<ImmutableCompoundTypeBuilder>() {
|
||||
protected synchronized ImmutableCompoundTypeBuilder initialValue() {
|
||||
return new ImmutableCompoundTypeBuilder();
|
||||
}
|
||||
};
|
||||
private static final ThreadLocal<ImmutableCompoundTypeBuilder> local = new ThreadLocal<ImmutableCompoundTypeBuilder>() {
|
||||
protected synchronized ImmutableCompoundTypeBuilder initialValue() {
|
||||
return new ImmutableCompoundTypeBuilder();
|
||||
}
|
||||
};
|
||||
|
||||
private final Map<Class<?>, Entry> entryMap = new HashMap<Class<?>, Entry>();
|
||||
private final Map<Class<?>, Entry> entryMap = new HashMap<Class<?>, Entry>();
|
||||
|
||||
/**
|
||||
* Clear the cache of partial compound objects.
|
||||
*/
|
||||
public static void clear() {
|
||||
local.get().entryMap.clear();
|
||||
/**
|
||||
* Clear the cache of partial compound objects.
|
||||
*/
|
||||
public static void clear() {
|
||||
local.get().entryMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the property of a compound type.
|
||||
* <p>
|
||||
* If this is the last value required for the compound type then the
|
||||
* compound type is created and returned, otherwise null is returned (and we
|
||||
* need more values set).
|
||||
* </p>
|
||||
*/
|
||||
public static Object set(CtCompoundType<?> ct, String propName, Object value) {
|
||||
return local.get().setValue(ct, propName, value);
|
||||
}
|
||||
|
||||
private Object setValue(CtCompoundType<?> ct, String propName, Object value) {
|
||||
|
||||
Entry e = getEntry(ct);
|
||||
Object compoundValue = e.set(propName, value);
|
||||
if (compoundValue != null) {
|
||||
removeEntry(ct);
|
||||
}
|
||||
return compoundValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Once we have built a compound value we remove the entry.
|
||||
*/
|
||||
private void removeEntry(CtCompoundType<?> ct) {
|
||||
entryMap.remove(ct.getCompoundTypeClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Entry which contains the values collected so far for this type.
|
||||
*/
|
||||
private Entry getEntry(CtCompoundType<?> ct) {
|
||||
Entry e = entryMap.get(ct.getCompoundTypeClass());
|
||||
if (e == null) {
|
||||
e = new Entry(ct);
|
||||
entryMap.put(ct.getCompoundTypeClass(), e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds the values collected so far for a given compound type.
|
||||
*/
|
||||
private static class Entry {
|
||||
|
||||
private final CtCompoundType<?> ct;
|
||||
|
||||
private final Map<String, Object> valueMap;
|
||||
|
||||
private Entry(CtCompoundType<?> ct) {
|
||||
this.ct = ct;
|
||||
this.valueMap = new HashMap<String, Object>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the property of a compound type.
|
||||
* <p>
|
||||
* If this is the last value required for the compound type then the
|
||||
* compound type is created and returned, otherwise null is returned (and we
|
||||
* need more values set).
|
||||
* </p>
|
||||
*/
|
||||
public static Object set(CtCompoundType<?> ct, String propName, Object value) {
|
||||
return local.get().setValue(ct, propName, value);
|
||||
}
|
||||
private Object set(String propName, Object value) {
|
||||
// collect the values...
|
||||
valueMap.put(propName, value);
|
||||
|
||||
private Object setValue(CtCompoundType<?> ct, String propName, Object value) {
|
||||
|
||||
Entry e = getEntry(ct);
|
||||
Object compoundValue = e.set(propName, value);
|
||||
if (compoundValue != null) {
|
||||
removeEntry(ct);
|
||||
}
|
||||
return compoundValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Once we have built a compound value we remove the entry.
|
||||
*/
|
||||
private void removeEntry(CtCompoundType<?> ct) {
|
||||
entryMap.remove(ct.getCompoundTypeClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Entry which contains the values collected so far for this type.
|
||||
*/
|
||||
private Entry getEntry(CtCompoundType<?> ct) {
|
||||
Entry e = entryMap.get(ct.getCompoundTypeClass());
|
||||
if (e == null) {
|
||||
e = new Entry(ct);
|
||||
entryMap.put(ct.getCompoundTypeClass(), e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds the values collected so far for a given compound type.
|
||||
*/
|
||||
private static class Entry {
|
||||
|
||||
private final CtCompoundType<?> ct;
|
||||
|
||||
private final Map<String, Object> valueMap;
|
||||
|
||||
private Entry(CtCompoundType<?> ct) {
|
||||
this.ct = ct;
|
||||
this.valueMap = new HashMap<String, Object>();
|
||||
}
|
||||
|
||||
private Object set(String propName, Object value) {
|
||||
// collect the values...
|
||||
valueMap.put(propName, value);
|
||||
|
||||
// when got all the values this returns the
|
||||
// compound value, otherwise null
|
||||
return ct.create(valueMap);
|
||||
}
|
||||
// when got all the values this returns the
|
||||
// compound value, otherwise null
|
||||
return ct.create(valueMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import com.avaje.ebean.config.ScalarTypeConverter;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
public class LongToTimestampConverter implements ScalarTypeConverter<Long, Timestamp> {
|
||||
|
||||
public Long getNullValue() {
|
||||
|
||||
@@ -167,7 +167,7 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
|
||||
|
||||
@Override
|
||||
public List<E> subList(int fromIndex, int toIndex) {
|
||||
return new ModifyAwareList<E>(owner,list.subList(fromIndex, toIndex));
|
||||
return new ModifyAwareList<E>(owner, list.subList(fromIndex, toIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,9 @@ import com.avaje.ebeaninternal.server.core.timezone.DataTimeZone;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
/**
|
||||
* A DataReader with indexed positions for the properties to read specifically for RawSql use.
|
||||
*/
|
||||
public class RsetDataReaderIndexed extends RsetDataReader {
|
||||
|
||||
private final int[] rsetIndexPositions;
|
||||
|
||||
@@ -45,7 +45,7 @@ public class ScalarTypeArrayList extends ScalarTypeJsonCollection<List> {
|
||||
if (valueType.equals(String.class)) {
|
||||
return STRING;
|
||||
}
|
||||
throw new IllegalArgumentException("Type ["+valueType+"] not supported for @DbArray mapping");
|
||||
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
|
||||
}
|
||||
|
||||
private final String arrayType;
|
||||
@@ -67,7 +67,7 @@ public class ScalarTypeArrayList extends ScalarTypeJsonCollection<List> {
|
||||
* Return the DB column definition for DDL generation.
|
||||
*/
|
||||
public String getDbColumnDefn() {
|
||||
return arrayType+"[]";
|
||||
return arrayType + "[]";
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -86,12 +86,16 @@ public class ScalarTypeArrayList extends ScalarTypeJsonCollection<List> {
|
||||
@Override
|
||||
public List read(DataReader reader) throws SQLException {
|
||||
Array array = reader.getArray();
|
||||
return fromArray((Object[])array.getArray());
|
||||
return fromArray((Object[]) array.getArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind bind, List value) throws SQLException {
|
||||
bind.setArray(arrayType, toArray(value));
|
||||
if (value == null) {
|
||||
bind.setNull(Types.ARRAY);
|
||||
} else {
|
||||
bind.setArray(arrayType, toArray(value));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,7 +112,7 @@ public class ScalarTypeArrayList extends ScalarTypeJsonCollection<List> {
|
||||
try {
|
||||
return EJson.parseList(value, false);
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException("Failed to parse JSON content as List: ["+value+"]", e);
|
||||
throw new PersistenceException("Failed to parse JSON content as List: [" + value + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -212,12 +212,12 @@ public class ScalarTypeBoolean {
|
||||
|
||||
@Override
|
||||
public String getDbFalseLiteral() {
|
||||
return "'"+falseValue+"'";
|
||||
return "'" + falseValue + "'";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDbTrueLiteral() {
|
||||
return "'"+trueValue+"'";
|
||||
return "'" + trueValue + "'";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInput;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebean.config.JsonConfig;
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.util.Calendar;
|
||||
|
||||
import com.avaje.ebean.config.JsonConfig;
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
|
||||
/**
|
||||
* ScalarType for java.util.Calendar.
|
||||
*/
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
|
||||
/**
|
||||
* ScalarType for char.
|
||||
*/
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* ScalarType for char[].
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
|
||||
/**
|
||||
* ScalarType for String.
|
||||
*/
|
||||
public class ScalarTypeClob extends ScalarTypeBaseVarchar<String> {
|
||||
|
||||
|
||||
protected ScalarTypeClob(boolean jdbcNative, int jdbcType) {
|
||||
super(String.class, jdbcNative, jdbcType);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
|
||||
/**
|
||||
* ScalarType for java.sql.Date.
|
||||
*/
|
||||
|
||||
@@ -31,7 +31,7 @@ public class ScalarTypeDayOfWeek extends ScalarTypeEnumWithMapping {
|
||||
b.setNull(Types.INTEGER);
|
||||
} else {
|
||||
// avoiding the map lookup
|
||||
b.setInt(((DayOfWeek)value).getValue());
|
||||
b.setInt(((DayOfWeek) value).getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Marker interface for the Enum scalar types.
|
||||
*/
|
||||
@@ -8,6 +10,6 @@ public interface ScalarTypeEnum {
|
||||
/**
|
||||
* Return the IN values for DB constraint construction.
|
||||
*/
|
||||
String getConstraintInValues();
|
||||
Set<String> getDbCheckConstraintValues();
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* JPA standard based Enum scalar type.
|
||||
@@ -41,22 +43,17 @@ public class ScalarTypeEnumStandard {
|
||||
/**
|
||||
* Return the IN values for DB constraint construction.
|
||||
*/
|
||||
public String getConstraintInValues() {
|
||||
@Override
|
||||
public Set<String> getDbCheckConstraintValues() {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
LinkedHashSet<String> values = new LinkedHashSet<String>();
|
||||
|
||||
sb.append("(");
|
||||
Object[] ea = enumType.getEnumConstants();
|
||||
for (int i = 0; i < ea.length; i++) {
|
||||
Enum<?> e = (Enum<?>) ea[i];
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append("'").append(e.name()).append("'");
|
||||
values.add("'" + e.name() + "'");
|
||||
}
|
||||
sb.append(")");
|
||||
|
||||
return sb.toString();
|
||||
return values;
|
||||
}
|
||||
|
||||
private int maxValueLength(Class<?> enumType) {
|
||||
@@ -129,21 +126,15 @@ public class ScalarTypeEnumStandard {
|
||||
/**
|
||||
* Return the IN values for DB constraint construction.
|
||||
*/
|
||||
public String getConstraintInValues() {
|
||||
@Override
|
||||
public Set<String> getDbCheckConstraintValues() {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("(");
|
||||
LinkedHashSet<String> values = new LinkedHashSet<String>();
|
||||
for (int i = 0; i < enumArray.length; i++) {
|
||||
Enum<?> e = (Enum<?>) enumArray[i];
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(e.ordinal());
|
||||
values.add(Integer.toString(e.ordinal()));
|
||||
}
|
||||
sb.append(")");
|
||||
|
||||
return sb.toString();
|
||||
return values;
|
||||
}
|
||||
|
||||
public void bind(DataBind b, Object value) throws SQLException {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Additional control over mapping to DB values.
|
||||
@@ -37,32 +37,21 @@ public class ScalarTypeEnumWithMapping extends ScalarTypeEnumStandard.EnumBase i
|
||||
/**
|
||||
* Return the IN values for DB constraint construction.
|
||||
*/
|
||||
public String getConstraintInValues() {
|
||||
@Override
|
||||
public Set<String> getDbCheckConstraintValues() {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int i = 0;
|
||||
|
||||
sb.append("(");
|
||||
LinkedHashSet values = new LinkedHashSet();
|
||||
|
||||
Iterator<?> it = beanDbMap.dbValues();
|
||||
while (it.hasNext()) {
|
||||
Object dbValue = it.next();
|
||||
if (i++ > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
if (!beanDbMap.isIntegerType()) {
|
||||
sb.append("'");
|
||||
}
|
||||
sb.append(dbValue.toString());
|
||||
if (!beanDbMap.isIntegerType()) {
|
||||
sb.append("'");
|
||||
if (beanDbMap.isIntegerType()) {
|
||||
values.add(dbValue.toString());
|
||||
} else {
|
||||
values.add("'" + dbValue.toString() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
sb.append(")");
|
||||
|
||||
return sb.toString();
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.avaje.ebean.text.TextException;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import com.avaje.ebean.text.TextException;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* ScalarType for java.net.URI which converts to and from a VARCHAR database column.
|
||||
*/
|
||||
|
||||
@@ -47,13 +47,13 @@ public class ScalarTypeInstant extends ScalarTypeBaseDateTime<Instant> {
|
||||
|
||||
@Override
|
||||
public Object toJdbcType(Object value) {
|
||||
if (value instanceof Timestamp) return value;
|
||||
if (value instanceof Timestamp) return value;
|
||||
return convertToTimestamp((Instant) value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant toBeanType(Object value) {
|
||||
if (value instanceof Instant) return (Instant) value;
|
||||
if (value instanceof Instant) return (Instant) value;
|
||||
return convertFromTimestamp((Timestamp) value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import org.joda.time.DateMidnight;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.joda.time.DateMidnight;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
|
||||
/**
|
||||
* ScalarType for Joda DateMidnight. This maps to a JDBC Date.
|
||||
*/
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebean.config.JsonConfig;
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import org.joda.time.LocalDateTime;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
|
||||
import com.avaje.ebean.config.JsonConfig;
|
||||
import org.joda.time.LocalDateTime;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
|
||||
/**
|
||||
* ScalarType for Joda LocalDateTime. This maps to a JDBC Timestamp.
|
||||
*/
|
||||
|
||||
@@ -39,7 +39,7 @@ abstract class ScalarTypeJsonCollection<T> extends ScalarTypeBase<T> {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public T toBeanType(Object value) {
|
||||
return (T)value;
|
||||
return (T) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,15 +15,17 @@ import java.util.List;
|
||||
/**
|
||||
* Types for mapping List in JSON format to DB types VARCHAR, JSON and JSONB.
|
||||
*/
|
||||
public class ScalarTypeJsonList {
|
||||
public class ScalarTypeJsonList {
|
||||
/**
|
||||
* Return the appropriate ScalarType based requested dbType and if Postgres.
|
||||
*/
|
||||
public static ScalarType<?> typeFor(boolean postgres, int dbType, DocPropertyType docType) {
|
||||
if (postgres) {
|
||||
switch (dbType) {
|
||||
case DbType.JSONB: return new ScalarTypeJsonList.JsonB(docType);
|
||||
case DbType.JSON: return new ScalarTypeJsonList.Json(docType);
|
||||
case DbType.JSONB:
|
||||
return new ScalarTypeJsonList.JsonB(docType);
|
||||
case DbType.JSON:
|
||||
return new ScalarTypeJsonList.Json(docType);
|
||||
}
|
||||
}
|
||||
return new ScalarTypeJsonList.Varchar(docType);
|
||||
@@ -71,7 +73,7 @@ public class ScalarTypeJsonList {
|
||||
// parse JSON into modifyAware list
|
||||
return EJson.parseList(dataReader.getString(), true);
|
||||
} catch (IOException e) {
|
||||
throw new SQLException("Failed to parse JSON content as List: ["+ dataReader.getString() +"]", e);
|
||||
throw new SQLException("Failed to parse JSON content as List: [" + dataReader.getString() + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +107,7 @@ public class ScalarTypeJsonList {
|
||||
try {
|
||||
return EJson.parseList(value, false);
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException("Failed to parse JSON content as List: ["+value+"]", e);
|
||||
throw new PersistenceException("Failed to parse JSON content as List: [" + value + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,13 +35,18 @@ public abstract class ScalarTypeJsonMap extends ScalarTypeBase<Map> {
|
||||
public static ScalarTypeJsonMap typeFor(boolean postgres, int dbType) {
|
||||
|
||||
switch (dbType) {
|
||||
case Types.VARCHAR : return VARCHAR;
|
||||
case Types.BLOB: return BLOB;
|
||||
case Types.CLOB : return CLOB;
|
||||
case DbType.JSONB: return postgres ? JSONB : CLOB;
|
||||
case DbType.JSON: return postgres ? JSON : CLOB;
|
||||
case Types.VARCHAR:
|
||||
return VARCHAR;
|
||||
case Types.BLOB:
|
||||
return BLOB;
|
||||
case Types.CLOB:
|
||||
return CLOB;
|
||||
case DbType.JSONB:
|
||||
return postgres ? JSONB : CLOB;
|
||||
case DbType.JSON:
|
||||
return postgres ? JSON : CLOB;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown dbType "+dbType);
|
||||
throw new IllegalStateException("Unknown dbType " + dbType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,8 +45,10 @@ public class ScalarTypeJsonObjectMapper {
|
||||
private static String getPostgresType(boolean postgres, int dbType) {
|
||||
if (postgres) {
|
||||
switch (dbType) {
|
||||
case DbType.JSON : return PostgresHelper.JSON_TYPE;
|
||||
case DbType.JSONB : return PostgresHelper.JSONB_TYPE;
|
||||
case DbType.JSON:
|
||||
return PostgresHelper.JSON_TYPE;
|
||||
case DbType.JSONB:
|
||||
return PostgresHelper.JSONB_TYPE;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -25,8 +25,10 @@ public class ScalarTypeJsonSet {
|
||||
public static ScalarType<?> typeFor(boolean postgres, int dbType, DocPropertyType docPropertyType) {
|
||||
if (postgres) {
|
||||
switch (dbType) {
|
||||
case DbType.JSONB: return new ScalarTypeJsonSet.JsonB(docPropertyType);
|
||||
case DbType.JSON: return new ScalarTypeJsonSet.Json(docPropertyType);
|
||||
case DbType.JSONB:
|
||||
return new ScalarTypeJsonSet.JsonB(docPropertyType);
|
||||
case DbType.JSON:
|
||||
return new ScalarTypeJsonSet.Json(docPropertyType);
|
||||
}
|
||||
}
|
||||
return new ScalarTypeJsonSet.Varchar(docPropertyType);
|
||||
@@ -74,7 +76,7 @@ public class ScalarTypeJsonSet {
|
||||
// parse JSON into modifyAware list
|
||||
return EJson.parseSet(dataReader.getString(), true);
|
||||
} catch (IOException e) {
|
||||
throw new SQLException("Failed to parse JSON content as List: ["+ dataReader.getString() +"]", e);
|
||||
throw new SQLException("Failed to parse JSON content as List: [" + dataReader.getString() + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +110,7 @@ public class ScalarTypeJsonSet {
|
||||
try {
|
||||
return convertList(EJson.parseList(value));
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException("Failed to parse JSON content as Set: ["+value+"]", e);
|
||||
throw new PersistenceException("Failed to parse JSON content as Set: [" + value + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,12 +49,12 @@ public class ScalarTypeLocalDateTime extends ScalarTypeBaseDateTime<LocalDateTim
|
||||
@Override
|
||||
public Object toJdbcType(Object value) {
|
||||
if (value instanceof Timestamp) return value;
|
||||
return convertToTimestamp((LocalDateTime)value);
|
||||
return convertToTimestamp((LocalDateTime) value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime toBeanType(Object value) {
|
||||
if (value instanceof LocalDateTime) return (LocalDateTime)value;
|
||||
return convertFromTimestamp((Timestamp)value);
|
||||
if (value instanceof LocalDateTime) return (LocalDateTime) value;
|
||||
return convertFromTimestamp((Timestamp) value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.avaje.ebeaninternal.server.type;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user