mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
30
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eac68166d9 | ||
|
|
cb0023345f | ||
|
|
f0f7feb125 | ||
|
|
c8e32253a5 | ||
|
|
01541bb208 | ||
|
|
2d44d06f36 | ||
|
|
fda930a162 | ||
|
|
5a6cdb9a86 | ||
|
|
5ef7fe8504 | ||
|
|
11586fb635 | ||
|
|
d555122067 | ||
|
|
b6d3dc3516 | ||
|
|
bbf54d6196 | ||
|
|
74c88ce511 | ||
|
|
309bf6a11a | ||
|
|
02b6ab0f74 | ||
|
|
0c41993ce7 | ||
|
|
d949c48245 | ||
|
|
93e603ca25 | ||
|
|
117d22fd67 | ||
|
|
f13de2c8a6 | ||
|
|
5b8ef8154a | ||
|
|
df892f4509 | ||
|
|
2755e6d1ec | ||
|
|
2024193da9 | ||
|
|
72788c7428 | ||
|
|
8789709fb8 | ||
|
|
588aaf9361 | ||
|
|
68649d0e98 | ||
|
|
f6047d3b73 |
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>11.18.3</version>
|
||||
<version>11.18.6</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-11.18.3</tag>
|
||||
<tag>ebean-11.18.6</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
@@ -360,7 +360,7 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<doctitle>Ebean 10</doctitle>
|
||||
<doctitle>Ebean 11</doctitle>
|
||||
<overview>src/main/java/io/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
|
||||
@@ -246,6 +246,9 @@ public class PlatformDdl {
|
||||
* Convert the standard type to the platform specific type.
|
||||
*/
|
||||
public String convert(String type, boolean identity) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
if (type.contains("[]")) {
|
||||
return convertArrayType(type);
|
||||
}
|
||||
|
||||
@@ -133,8 +133,7 @@ public class VisitAllUsing {
|
||||
InheritInfo inheritInfo = descriptor.getInheritInfo();
|
||||
if (inheritInfo != null && inheritInfo.isRoot()) {
|
||||
// add all properties on the children objects
|
||||
InheritChildVisitor childVisitor = new InheritChildVisitor(this, pv);
|
||||
inheritInfo.visitChildren(childVisitor);
|
||||
inheritInfo.visitChildren(new InheritChildVisitor(this, pv));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,9 +154,10 @@ public class VisitAllUsing {
|
||||
|
||||
@Override
|
||||
public void visit(InheritInfo inheritInfo) {
|
||||
BeanProperty[] propertiesLocal = inheritInfo.desc().propertiesLocal();
|
||||
for (BeanProperty aPropertiesLocal : propertiesLocal) {
|
||||
owner.visit(pv, aPropertiesLocal);
|
||||
for (BeanProperty beanProperty : inheritInfo.desc().propertiesLocal()) {
|
||||
if (beanProperty.isDDLColumn()) {
|
||||
owner.visit(pv, beanProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1384,7 +1384,18 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
request.markNotQueryOnly();
|
||||
return request.delete();
|
||||
if (request.isDeleteByStatement()) {
|
||||
return request.delete();
|
||||
} else {
|
||||
// escalate to fetch the ids of the beans to delete due
|
||||
// to cascading deletes or l2 caching etc
|
||||
List<Object> ids = request.findIds();
|
||||
if (ids.isEmpty()) {
|
||||
return 0;
|
||||
} else {
|
||||
return persister.deleteByIds(request.getBeanDescriptor(), ids, request.getTransaction(), false);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
}
|
||||
|
||||
@@ -116,6 +116,11 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeleteByStatement() {
|
||||
return beanDescriptor.isDeleteByStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMultiValueIdSupported() {
|
||||
return beanDescriptor.isMultiValueIdSupported();
|
||||
|
||||
@@ -356,7 +356,15 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
|
||||
private boolean flushBatchOnGetter(int propertyIndex) {
|
||||
// propertyIndex of -1 the Id property, no flush for get Id on UPDATE
|
||||
return propertyIndex == -1 ? type == Type.INSERT : beanDescriptor.isGeneratedProperty(propertyIndex);
|
||||
if (propertyIndex == -1) {
|
||||
if (beanDescriptor.isIdLoaded(intercept)) {
|
||||
return false;
|
||||
} else {
|
||||
return type == Type.INSERT;
|
||||
}
|
||||
} else {
|
||||
return beanDescriptor.isGeneratedProperty(propertyIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSkipBatchForTopLevel() {
|
||||
|
||||
@@ -63,6 +63,11 @@ public interface Persister {
|
||||
*/
|
||||
int deleteMany(Class<?> beanType, Collection<?> ids, Transaction transaction, boolean permanent);
|
||||
|
||||
/**
|
||||
* Delete multiple beans when escalated from a delete query.
|
||||
*/
|
||||
int deleteByIds(BeanDescriptor<?> descriptor, List<Object> idList, Transaction transaction, boolean permanent);
|
||||
|
||||
/**
|
||||
* Execute the Update.
|
||||
*/
|
||||
|
||||
@@ -171,4 +171,9 @@ public interface SpiOrmQueryRequest<T> extends BeanQueryRequest<T>, DocQueryRequ
|
||||
* Set profile location for "find all" if not set.
|
||||
*/
|
||||
void profileLocationAll();
|
||||
|
||||
/**
|
||||
* Return true if delete by statement is allowed for this type given cascade rules etc.
|
||||
*/
|
||||
boolean isDeleteByStatement();
|
||||
}
|
||||
|
||||
@@ -3160,6 +3160,10 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
public boolean hasIdPropertyOnly(EntityBeanIntercept ebi) {
|
||||
return ebi.hasIdOnly(idPropertyIndex);
|
||||
}
|
||||
|
||||
public boolean isIdLoaded(EntityBeanIntercept ebi) {
|
||||
return ebi.isLoadedProperty(idPropertyIndex);
|
||||
}
|
||||
|
||||
public boolean hasIdValue(EntityBean bean) {
|
||||
return (idProperty != null && !DmlUtil.isNullOrZero(idProperty.getValue(bean)));
|
||||
|
||||
@@ -739,6 +739,7 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
if (invalidateQueryCache) {
|
||||
changeSet.addInvalidate(desc);
|
||||
} else {
|
||||
queryCacheClear(changeSet);
|
||||
if (beanCache != null) {
|
||||
changeSet.addBeanRemoveMany(desc, ids);
|
||||
}
|
||||
|
||||
@@ -357,14 +357,34 @@ public abstract class BeanPropertyAssoc<T> extends BeanProperty implements STree
|
||||
* Return true if this association is updateable.
|
||||
*/
|
||||
public boolean isUpdateable() {
|
||||
return tableJoin.columns().length <= 0 || tableJoin.columns()[0].isUpdateable();
|
||||
TableJoinColumn[] columns = tableJoin.columns();
|
||||
if (columns.length <= 0) {
|
||||
return true;
|
||||
}
|
||||
for (TableJoinColumn column : columns) {
|
||||
if (column.isUpdateable()) {
|
||||
// at least 1 is updatable
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this association is insertable.
|
||||
*/
|
||||
public boolean isInsertable() {
|
||||
return tableJoin.columns().length <= 0 || tableJoin.columns()[0].isInsertable();
|
||||
TableJoinColumn[] columns = tableJoin.columns();
|
||||
if (columns.length <= 0) {
|
||||
return true;
|
||||
}
|
||||
for (TableJoinColumn column : columns) {
|
||||
if (column.isInsertable()) {
|
||||
// at least 1 is insertable
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -443,16 +463,18 @@ public abstract class BeanPropertyAssoc<T> extends BeanProperty implements STree
|
||||
String matchColumn = col.getForeignDbColumn();
|
||||
String localColumn = col.getLocalDbColumn();
|
||||
String localSqlFormula = col.getLocalSqlFormula();
|
||||
boolean insertable = col.isInsertable();
|
||||
boolean updateable = col.isUpdateable();
|
||||
|
||||
for (int j = 0; j < props.length; j++) {
|
||||
if (props[j].getDbColumn().equalsIgnoreCase(matchColumn)) {
|
||||
return new ImportedIdSimple(owner, localColumn, localSqlFormula, props[j], j);
|
||||
return new ImportedIdSimple(owner, localColumn, localSqlFormula, props[j], j, insertable, updateable);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < others.length; j++) {
|
||||
if (others[j].getDbColumn().equalsIgnoreCase(matchColumn)) {
|
||||
return new ImportedIdSimple(owner, localColumn, localSqlFormula, others[j], j + props.length);
|
||||
return new ImportedIdSimple(owner, localColumn, localSqlFormula, others[j], j + props.length, insertable, updateable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -187,6 +187,6 @@ public abstract class DeployParser {
|
||||
}
|
||||
|
||||
private boolean isWordStart(char ch) {
|
||||
return Character.isLetter(ch);
|
||||
return Character.isLetter(ch) || ch == UNDERSCORE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,8 +64,11 @@ public class ImportedIdEmbedded implements ImportedId {
|
||||
@Override
|
||||
public void dmlAppend(GenerateDmlRequest request) {
|
||||
|
||||
boolean update = request.isUpdate();
|
||||
for (ImportedIdSimple anImported : imported) {
|
||||
request.appendColumn(anImported.localDbColumn);
|
||||
if (anImported.isInclude(update)) {
|
||||
request.appendColumn(anImported.localDbColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,30 +103,28 @@ public class ImportedIdEmbedded implements ImportedId {
|
||||
@Override
|
||||
public Object bind(BindableRequest request, EntityBean bean) throws SQLException {
|
||||
|
||||
Object embeddedId = null;
|
||||
|
||||
if (bean != null) {
|
||||
embeddedId = foreignAssocOne.getValue(bean);
|
||||
}
|
||||
Object embeddedId = (bean == null) ? null : foreignAssocOne.getValue(bean);
|
||||
|
||||
boolean update = request.isUpdate();
|
||||
if (embeddedId == null) {
|
||||
for (ImportedIdSimple anImported : imported) {
|
||||
if (anImported.owner.isUpdateable()) {
|
||||
if (anImported.isInclude(update)) {
|
||||
request.bind(null, anImported.foreignProperty);
|
||||
}
|
||||
}
|
||||
// return anything non-null to skip a derived relationship update
|
||||
return Object.class;
|
||||
|
||||
} else {
|
||||
EntityBean embedded = (EntityBean) embeddedId;
|
||||
for (ImportedIdSimple anImported : imported) {
|
||||
if (anImported.owner.isUpdateable()) {
|
||||
if (anImported.isInclude(update)) {
|
||||
Object scalarValue = anImported.foreignProperty.getValue(embedded);
|
||||
request.bind(scalarValue, anImported.foreignProperty);
|
||||
}
|
||||
}
|
||||
return embedded;
|
||||
}
|
||||
// hmmm, not worrying about this just yet
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -47,15 +47,32 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
|
||||
|
||||
protected final int position;
|
||||
|
||||
public ImportedIdSimple(BeanPropertyAssoc<?> owner, String localDbColumn, String localSqlFormula, BeanProperty foreignProperty, int position) {
|
||||
/**
|
||||
* If true include in insert.
|
||||
*/
|
||||
private final boolean insertable;
|
||||
|
||||
/**
|
||||
* If true include in update.
|
||||
*/
|
||||
private final boolean updateable;
|
||||
|
||||
public ImportedIdSimple(BeanPropertyAssoc<?> owner, String localDbColumn, String localSqlFormula, BeanProperty foreignProperty, int position,
|
||||
boolean insertable, boolean updateable) {
|
||||
this.owner = owner;
|
||||
this.localDbColumn = InternString.intern(localDbColumn);
|
||||
this.localSqlFormula = InternString.intern(localSqlFormula);
|
||||
this.foreignProperty = foreignProperty;
|
||||
this.position = position;
|
||||
this.insertable = insertable;
|
||||
this.updateable = updateable;
|
||||
this.logicalName = InternString.intern(owner.getName() + "." + foreignProperty.getName());
|
||||
}
|
||||
|
||||
public ImportedIdSimple(BeanPropertyAssoc<?> owner, String localDbColumn, String localSqlFormula, BeanProperty foreignProperty, int position) {
|
||||
this(owner, localDbColumn, localSqlFormula, foreignProperty, position, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list as an array sorted into the same order as the Bean Properties.
|
||||
*/
|
||||
@@ -68,6 +85,13 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
|
||||
return importedIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if it should be included in the update (or insert).
|
||||
*/
|
||||
public boolean isInclude(boolean update) {
|
||||
return (update) ? updateable : insertable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
// remove FindBugs warning
|
||||
|
||||
@@ -116,6 +116,10 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
prop.setFetchPreference(fetchPreference.value());
|
||||
}
|
||||
|
||||
io.ebean.annotation.NotNull nonNull = get(prop, io.ebean.annotation.NotNull.class);
|
||||
if (nonNull != null) {
|
||||
prop.setNullable(false);
|
||||
}
|
||||
if (validationAnnotations) {
|
||||
NotNull notNull = get(prop, NotNull.class);
|
||||
if (notNull != null && isEbeanValidationGroups(notNull.groups())) {
|
||||
|
||||
@@ -18,6 +18,7 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import io.ebeaninternal.server.type.DataEncryptSupport;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.ScalarTypeArray;
|
||||
import io.ebeaninternal.server.type.ScalarTypeWrapper;
|
||||
import io.ebeaninternal.server.type.SimpleAesEncryptor;
|
||||
import io.ebeaninternal.server.type.TypeManager;
|
||||
import org.slf4j.Logger;
|
||||
@@ -116,8 +117,8 @@ public class DeployUtil {
|
||||
throw new IllegalArgumentException("Class [" + enumType + "] is Not a Enum?");
|
||||
}
|
||||
try {
|
||||
Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) enumType;
|
||||
EnumType type = enumerated != null ? enumerated.value() : null;
|
||||
Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) enumType;
|
||||
EnumType type = enumerated != null ? enumerated.value() : null;
|
||||
ScalarType<?> scalarType = typeManager.createEnumScalarType(enumClass, type);
|
||||
prop.setScalarType(scalarType);
|
||||
prop.setDbType(scalarType.getJdbcType());
|
||||
@@ -278,19 +279,25 @@ public class DeployUtil {
|
||||
*/
|
||||
public void setLobType(DeployBeanProperty prop) {
|
||||
|
||||
// is String or byte[] ? used to determine if its a CLOB or BLOB
|
||||
Class<?> type = prop.getPropertyType();
|
||||
ScalarType<?> scalarType = prop.getScalarType();
|
||||
|
||||
// this also sets the lob flag on DeployBeanProperty
|
||||
int lobType = isClobType(type) ? dbCLOBType : dbBLOBType;
|
||||
if (scalarType instanceof ScalarTypeWrapper) {
|
||||
int lobType = scalarType.getJdbcType() == Types.VARCHAR ? dbCLOBType : dbBLOBType;
|
||||
prop.setDbType(lobType);
|
||||
} else {
|
||||
// is String or byte[] ? used to determine if its a CLOB or BLOB
|
||||
Class<?> type = prop.getPropertyType();
|
||||
// this also sets the lob flag on DeployBeanProperty
|
||||
int lobType = isClobType(type) ? dbCLOBType : dbBLOBType;
|
||||
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(type, lobType);
|
||||
if (scalarType == null) {
|
||||
// this should never occur actually
|
||||
throw new RuntimeException("No ScalarType for LOB type [" + type + "] [" + lobType + "]");
|
||||
scalarType = typeManager.getScalarType(type, lobType);
|
||||
if (scalarType == null) {
|
||||
// this should never occur actually
|
||||
throw new RuntimeException("No ScalarType for LOB type [" + type + "] [" + lobType + "]");
|
||||
}
|
||||
prop.setDbType(lobType);
|
||||
prop.setScalarType(scalarType);
|
||||
}
|
||||
prop.setDbType(lobType);
|
||||
prop.setScalarType(scalarType);
|
||||
}
|
||||
|
||||
private boolean isClobType(Class<?> type) {
|
||||
|
||||
@@ -680,6 +680,12 @@ public final class DefaultPersister implements Persister {
|
||||
return delete(descriptor, id, null, transaction, deleteMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteByIds(BeanDescriptor<?> descriptor, List<Object> idList, Transaction transaction, boolean permanent) {
|
||||
DeleteMode deleteMode = (permanent || !descriptor.isSoftDelete()) ? DeleteMode.HARD : DeleteMode.SOFT;
|
||||
return delete(descriptor, null, idList, transaction, deleteMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete by Id or a List of Id's.
|
||||
*/
|
||||
@@ -739,18 +745,20 @@ public final class DefaultPersister implements Persister {
|
||||
// OneToMany's with delete cascade
|
||||
BeanPropertyAssocMany<?>[] manys = descriptor.propertiesManyDelete();
|
||||
for (BeanPropertyAssocMany<?> many : manys) {
|
||||
BeanDescriptor<?> targetDesc = many.getTargetDescriptor();
|
||||
// only cascade soft deletes when supported by target
|
||||
if (deleteMode.isHard() || targetDesc.isSoftDelete()) {
|
||||
if (deleteMode.isHard() && targetDesc.isDeleteByStatement()) {
|
||||
// we can just delete children with a single statement
|
||||
SqlUpdate sqlDelete = many.deleteByParentId(id, idList);
|
||||
executeSqlUpdate(sqlDelete, t);
|
||||
} else {
|
||||
// we need to fetch the Id's to delete (recurse or notify L2 cache)
|
||||
List<Object> childIds = many.findIdsByParentId(id, idList, t, null);
|
||||
if (!childIds.isEmpty()) {
|
||||
delete(targetDesc, null, childIds, t, deleteMode);
|
||||
if (!many.isManyToMany()) {
|
||||
BeanDescriptor<?> targetDesc = many.getTargetDescriptor();
|
||||
// only cascade soft deletes when supported by target
|
||||
if (deleteMode.isHard() || targetDesc.isSoftDelete()) {
|
||||
if (deleteMode.isHard() && targetDesc.isDeleteByStatement()) {
|
||||
// we can just delete children with a single statement
|
||||
SqlUpdate sqlDelete = many.deleteByParentId(id, idList);
|
||||
executeSqlUpdate(sqlDelete, t);
|
||||
} else {
|
||||
// we need to fetch the Id's to delete (recurse or notify L2 cache)
|
||||
List<Object> childIds = many.findIdsByParentId(id, idList, t, null);
|
||||
if (!childIds.isEmpty()) {
|
||||
delete(targetDesc, null, childIds, t, deleteMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,11 @@ public class DeleteHandler extends DmlHandler {
|
||||
this.meta = meta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and bind the delete statement.
|
||||
*/
|
||||
|
||||
@@ -29,10 +29,6 @@ public class GenerateDmlRequest {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void appendColumnIsNull(String column) {
|
||||
appendColumn(column, IS_NULL);
|
||||
}
|
||||
|
||||
public void appendColumn(String column) {
|
||||
//String bind = (insertMode > 0) ? "?" : "=?";
|
||||
appendColumn(column, "?");
|
||||
@@ -91,4 +87,7 @@ public class GenerateDmlRequest {
|
||||
this.prefix2 = ", ";
|
||||
}
|
||||
|
||||
public boolean isUpdate() {
|
||||
return insertMode == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,11 @@ public class InsertHandler extends DmlHandler {
|
||||
this.concatinatedKey = meta.isConcatenatedKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and bind the insert statement.
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,11 @@ public class UpdateHandler extends DmlHandler {
|
||||
this.meta = meta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpdate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and bind the update statement.
|
||||
*/
|
||||
|
||||
@@ -59,4 +59,8 @@ public interface BindableRequest {
|
||||
*/
|
||||
long now();
|
||||
|
||||
/**
|
||||
* Return true if this is an update request.
|
||||
*/
|
||||
boolean isUpdate();
|
||||
}
|
||||
|
||||
@@ -19,9 +19,7 @@ public class FactoryAssocOnes {
|
||||
*/
|
||||
public void create(List<Bindable> list, BeanDescriptor<?> desc, DmlMode mode) {
|
||||
|
||||
BeanPropertyAssocOne<?>[] ones = desc.propertiesOneImported();
|
||||
|
||||
for (BeanPropertyAssocOne<?> one : ones) {
|
||||
for (BeanPropertyAssocOne<?> one : desc.propertiesOneImported()) {
|
||||
if (!one.isImportedPrimaryKey()) {
|
||||
switch (mode) {
|
||||
case INSERT:
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebean.OrderBy;
|
||||
import io.ebean.OrderBy.Property;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
|
||||
@@ -18,27 +17,22 @@ class CQueryOrderBy {
|
||||
|
||||
private final BeanDescriptor<?> desc;
|
||||
|
||||
private final SpiQuery<?> query;
|
||||
private final OrderBy<?> orderBy;
|
||||
|
||||
/**
|
||||
* Create the logical order by clause.
|
||||
*/
|
||||
public static String parse(BeanDescriptor<?> desc, SpiQuery<?> query) {
|
||||
return new CQueryOrderBy(desc, query).parseInternal();
|
||||
public static String parse(BeanDescriptor<?> desc, OrderBy<?> orderBy) {
|
||||
return new CQueryOrderBy(desc, orderBy).parseInternal();
|
||||
}
|
||||
|
||||
private CQueryOrderBy(BeanDescriptor<?> desc, SpiQuery<?> query) {
|
||||
private CQueryOrderBy(BeanDescriptor<?> desc, OrderBy<?> orderBy) {
|
||||
this.desc = desc;
|
||||
this.query = query;
|
||||
this.orderBy = orderBy;
|
||||
}
|
||||
|
||||
private String parseInternal() {
|
||||
|
||||
OrderBy<?> orderBy = query.getOrderBy();
|
||||
if (orderBy == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
List<Property> properties = orderBy.getProperties();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebean.OrderBy;
|
||||
import io.ebeaninternal.api.BindParams;
|
||||
import io.ebeaninternal.api.SpiExpressionList;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
@@ -329,7 +330,11 @@ public class CQueryPredicates {
|
||||
|
||||
private String parseOrderBy() {
|
||||
|
||||
return CQueryOrderBy.parse(request.getBeanDescriptor(), query);
|
||||
OrderBy<?> orderBy = query.getOrderBy();
|
||||
if (orderBy == null) {
|
||||
return null;
|
||||
}
|
||||
return CQueryOrderBy.parse(request.getBeanDescriptor(), orderBy);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,6 +51,7 @@ public class ScalarTypeChar extends ScalarTypeBaseVarchar<Character> {
|
||||
|
||||
@Override
|
||||
public Character toBeanType(Object value) {
|
||||
if (value == null) return null;
|
||||
String s = BasicTypeConverter.toString(value);
|
||||
return s.charAt(0);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ public class ScalarTypeCharArray extends ScalarTypeBaseVarchar<char[]> {
|
||||
|
||||
@Override
|
||||
public char[] toBeanType(Object value) {
|
||||
if (value == null) return null;
|
||||
String s = BasicTypeConverter.toString(value);
|
||||
return s.toCharArray();
|
||||
}
|
||||
|
||||
@@ -1,66 +1,24 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
import io.ebeaninternal.server.core.BasicTypeConverter;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* ScalarType for String.
|
||||
*/
|
||||
public class ScalarTypeClob extends ScalarTypeBaseVarchar<String> {
|
||||
public class ScalarTypeClob extends ScalarTypeStringBase {
|
||||
|
||||
protected ScalarTypeClob(boolean jdbcNative, int jdbcType) {
|
||||
super(String.class, jdbcNative, jdbcType);
|
||||
ScalarTypeClob(boolean jdbcNative, int jdbcType) {
|
||||
super(jdbcNative, jdbcType);
|
||||
}
|
||||
|
||||
public ScalarTypeClob() {
|
||||
super(String.class, true, Types.CLOB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertFromDbString(String dbValue) {
|
||||
return dbValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertToDbString(String beanValue) {
|
||||
return beanValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind b, String value) throws SQLException {
|
||||
if (value == null) {
|
||||
b.setNull(Types.VARCHAR);
|
||||
} else {
|
||||
b.setString(value);
|
||||
}
|
||||
super(true, Types.CLOB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String read(DataReader dataReader) throws SQLException {
|
||||
|
||||
return dataReader.getStringFromStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object toJdbcType(Object value) {
|
||||
return BasicTypeConverter.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toBeanType(Object value) {
|
||||
return BasicTypeConverter.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatValue(String t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parse(String value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ public class ScalarTypeDuration extends ScalarTypeBase<Duration> {
|
||||
@Override
|
||||
public Duration toBeanType(Object value) {
|
||||
if (value instanceof Duration) return (Duration) value;
|
||||
if (value == null) return null;
|
||||
return Duration.ofSeconds(BasicTypeConverter.toLong(value));
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ public class ScalarTypeDurationWithNanos extends ScalarTypeDuration {
|
||||
@Override
|
||||
public Duration toBeanType(Object value) {
|
||||
if (value instanceof Duration) return (Duration) value;
|
||||
if (value == null) return null;
|
||||
return convertFromBigDecimal(BasicTypeConverter.toBigDecimal(value));
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ public class ScalarTypeInstant extends ScalarTypeBaseDateTime<Instant> {
|
||||
|
||||
@Override
|
||||
public Instant toBeanType(Object value) {
|
||||
if (value instanceof Instant) return (Instant) value;
|
||||
return convertFromTimestamp((Timestamp) value);
|
||||
if (value instanceof Timestamp) return convertFromTimestamp((Timestamp) value);
|
||||
return (Instant) value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public class ScalarTypeLocalDateTime extends ScalarTypeBaseDateTime<LocalDateTim
|
||||
|
||||
@Override
|
||||
public LocalDateTime toBeanType(Object value) {
|
||||
if (value instanceof LocalDateTime) return (LocalDateTime) value;
|
||||
return convertFromTimestamp((Timestamp) value);
|
||||
if (value instanceof Timestamp) return convertFromTimestamp((Timestamp) value);
|
||||
return (LocalDateTime) value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
@@ -12,8 +11,4 @@ public class ScalarTypeLongVarchar extends ScalarTypeClob {
|
||||
super(true, Types.LONGVARCHAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String read(DataReader dataReader) throws SQLException {
|
||||
return dataReader.getStringFromStream();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public class ScalarTypeOffsetDateTime extends ScalarTypeBaseDateTime<OffsetDateT
|
||||
|
||||
@Override
|
||||
public OffsetDateTime toBeanType(Object value) {
|
||||
if (value instanceof OffsetDateTime) return (OffsetDateTime) value;
|
||||
return convertFromTimestamp((Timestamp) value);
|
||||
if (value instanceof Timestamp) return convertFromTimestamp((Timestamp) value);
|
||||
return (OffsetDateTime) value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,103 +1,15 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import io.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* ScalarType for String.
|
||||
*/
|
||||
public class ScalarTypeString extends ScalarTypeBase<String> {
|
||||
public class ScalarTypeString extends ScalarTypeStringBase {
|
||||
|
||||
public static final ScalarTypeString INSTANCE = new ScalarTypeString();
|
||||
|
||||
private ScalarTypeString() {
|
||||
super(String.class, true, Types.VARCHAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind b, String value) throws SQLException {
|
||||
if (value == null) {
|
||||
b.setNull(Types.VARCHAR);
|
||||
} else {
|
||||
b.setString(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String read(DataReader dataReader) throws SQLException {
|
||||
return dataReader.getString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object toJdbcType(Object value) {
|
||||
return BasicTypeConverter.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toBeanType(Object value) {
|
||||
return BasicTypeConverter.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatValue(String value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parse(String value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertFromMillis(long systemTimeMillis) {
|
||||
return String.valueOf(systemTimeMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDateTimeCapable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readData(DataInput dataInput) throws IOException {
|
||||
if (!dataInput.readBoolean()) {
|
||||
return null;
|
||||
} else {
|
||||
return dataInput.readUTF();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeData(DataOutput dataOutput, String value) throws IOException {
|
||||
|
||||
if (value == null) {
|
||||
dataOutput.writeBoolean(false);
|
||||
} else {
|
||||
dataOutput.writeBoolean(true);
|
||||
dataOutput.writeUTF(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String jsonRead(JsonParser parser) throws IOException {
|
||||
return parser.getValueAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator writer, String value) throws IOException {
|
||||
writer.writeString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocPropertyType getDocType() {
|
||||
return DocPropertyType.TEXT;
|
||||
super(true, Types.VARCHAR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import io.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Base ScalarType for String type using Varchar, Clob and LongVarchar.
|
||||
*/
|
||||
public abstract class ScalarTypeStringBase extends ScalarTypeBase<String> {
|
||||
|
||||
ScalarTypeStringBase(boolean jdbcNative, int jdbcType) {
|
||||
super(String.class, jdbcNative, jdbcType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind b, String value) throws SQLException {
|
||||
if (value == null) {
|
||||
b.setNull(Types.VARCHAR);
|
||||
} else {
|
||||
b.setString(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String read(DataReader dataReader) throws SQLException {
|
||||
return dataReader.getString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object toJdbcType(Object value) {
|
||||
return BasicTypeConverter.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toBeanType(Object value) {
|
||||
return BasicTypeConverter.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatValue(String value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parse(String value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertFromMillis(long systemTimeMillis) {
|
||||
return String.valueOf(systemTimeMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDateTimeCapable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readData(DataInput dataInput) throws IOException {
|
||||
if (!dataInput.readBoolean()) {
|
||||
return null;
|
||||
} else {
|
||||
return dataInput.readUTF();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeData(DataOutput dataOutput, String value) throws IOException {
|
||||
|
||||
if (value == null) {
|
||||
dataOutput.writeBoolean(false);
|
||||
} else {
|
||||
dataOutput.writeBoolean(true);
|
||||
dataOutput.writeUTF(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String jsonRead(JsonParser parser) throws IOException {
|
||||
return parser.getValueAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator writer, String value) throws IOException {
|
||||
writer.writeString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocPropertyType getDocType() {
|
||||
return DocPropertyType.TEXT;
|
||||
}
|
||||
}
|
||||
@@ -65,6 +65,7 @@ public class ScalarTypeYear extends ScalarTypeBase<Year> {
|
||||
@Override
|
||||
public Year toBeanType(Object value) {
|
||||
if (value instanceof Year) return (Year) value;
|
||||
if (value == null) return null;
|
||||
return Year.of(BasicTypeConverter.toInteger(value));
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ public class ScalarTypeYearMonthDate extends ScalarTypeBaseDate<YearMonth> {
|
||||
public YearMonth toBeanType(Object value) {
|
||||
if (value instanceof YearMonth) return (YearMonth) value;
|
||||
if (value instanceof LocalDate) return fromLocalDate((LocalDate) value);
|
||||
if (value == null) return null;
|
||||
return fromLocalDate(BasicTypeConverter.toDate(value).toLocalDate());
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public class ScalarTypeZonedDateTime extends ScalarTypeBaseDateTime<ZonedDateTim
|
||||
|
||||
@Override
|
||||
public ZonedDateTime toBeanType(Object value) {
|
||||
if (value instanceof ZonedDateTime) return (ZonedDateTime) value;
|
||||
return convertFromTimestamp((Timestamp) value);
|
||||
if (value instanceof Timestamp) return convertFromTimestamp((Timestamp) value);
|
||||
return (ZonedDateTime) value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,6 @@ public class EBasic {
|
||||
@DbDefault("42")
|
||||
int newInteger;
|
||||
|
||||
@NotNull
|
||||
@ManyToOne
|
||||
@DbMigration(preAlter= "insert into migtest_e_user (id) select distinct user_id from migtest_e_basic") // ensure all users exist
|
||||
EUser user;
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package org.tests.basic.delete;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.Query;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.tests.model.onetoone.OtoUser;
|
||||
import org.tests.model.onetoone.OtoUserOptional;
|
||||
|
||||
public class TestDeleteCascadeByQuery extends BaseTestCase {
|
||||
|
||||
private OtoUser testUser;
|
||||
private OtoUserOptional userOptional;
|
||||
private Query<OtoUserOptional> userOptionalQuery = Ebean.find(OtoUserOptional.class);
|
||||
private Query<OtoUser> userQuery = Ebean.find(OtoUser.class);
|
||||
|
||||
/**
|
||||
* Init each test. Delete all existing beans. Then create OtoUser, add OtoUserOptional and save.
|
||||
*/
|
||||
@Before
|
||||
public void init() {
|
||||
Ebean.deleteAll(userQuery.findList());
|
||||
Ebean.deleteAll(userOptionalQuery.findList());
|
||||
|
||||
userOptional = new OtoUserOptional();
|
||||
Ebean.save(userOptional);
|
||||
testUser = new OtoUser();
|
||||
testUser.setOptional(userOptional);
|
||||
Ebean.save(testUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that validates deleting a bean using Ebean.delete() respects the CascadeType.DELETE
|
||||
* setting.
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteCascadeByEbeanDelete() {
|
||||
|
||||
assertThat(Ebean.delete(testUser)).isTrue();
|
||||
|
||||
assertThat(userOptionalQuery.findCount())
|
||||
.overridingErrorMessage("Entity OtoUserOptional found. Ebean.delete() on the user "
|
||||
+ "did not delete the OneToOne mapped entity as set with CascadeType.ALL")
|
||||
.isEqualTo(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that validates deleting a bean with OneToOne mapping with a query respects the
|
||||
* CascadeType.DELETE setting.
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteCascadeByQuery() {
|
||||
|
||||
assertThat(userQuery.delete()).isEqualTo(1);
|
||||
|
||||
assertThat(userOptionalQuery.findCount())
|
||||
.overridingErrorMessage("Entity OtoUserOptional found. Ebean query delete() on the user "
|
||||
+ "did not delete the OneToOne mapped entity as set with CascadeType.ALL")
|
||||
.isEqualTo(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup - Delete all existing beans for the next test.
|
||||
*/
|
||||
@After
|
||||
public void cleanup() {
|
||||
Ebean.deleteAll(userQuery.findList());
|
||||
Ebean.deleteAll(userOptionalQuery.findList());
|
||||
}
|
||||
}
|
||||
@@ -122,15 +122,20 @@ public class TestBatchInsertFlush extends BaseTestCase {
|
||||
public void transactional_flushOnGetId() {
|
||||
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
EBasicVer b1 = new EBasicVer("b1");
|
||||
server.save(b1);
|
||||
|
||||
EBasicVer b2 = new EBasicVer("b2");
|
||||
server.save(b2);
|
||||
|
||||
//flush here
|
||||
assertThat(LoggedSqlCollector.current()).isEmpty();
|
||||
Integer id = b1.getId();
|
||||
assertNotNull(id);
|
||||
assertThat(LoggedSqlCollector.current()).hasSize(2);
|
||||
|
||||
EBasicVer b3 = new EBasicVer("b3");
|
||||
server.save(b3);
|
||||
}
|
||||
@@ -141,7 +146,8 @@ public class TestBatchInsertFlush extends BaseTestCase {
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
Transaction txn = server.beginTransaction();
|
||||
try {
|
||||
txn.setBatch(PersistBatch.ALL);
|
||||
LoggedSqlCollector.start();
|
||||
txn.setBatchMode(true);
|
||||
|
||||
EBasicVer b1 = new EBasicVer("b1");
|
||||
server.save(b1, txn);
|
||||
@@ -149,8 +155,11 @@ public class TestBatchInsertFlush extends BaseTestCase {
|
||||
EBasicVer b2 = new EBasicVer("b2");
|
||||
server.save(b2, txn);
|
||||
|
||||
//flush here
|
||||
assertThat(LoggedSqlCollector.current()).isEmpty();
|
||||
Integer id = b1.getId();
|
||||
assertNotNull(id);
|
||||
assertThat(LoggedSqlCollector.current()).hasSize(2);
|
||||
|
||||
EBasicVer b3 = new EBasicVer("b3");
|
||||
server.save(b3, txn);
|
||||
@@ -161,6 +170,67 @@ public class TestBatchInsertFlush extends BaseTestCase {
|
||||
txn.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional(batch = PersistBatch.ALL)
|
||||
public void transactional_noflushWhenIdIsLoaded() {
|
||||
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
EBasicVer b1 = new EBasicVer("b1");
|
||||
b1.setId(78965);
|
||||
server.save(b1);
|
||||
|
||||
EBasicVer b2 = new EBasicVer("b2");
|
||||
b2.setId(78645);
|
||||
server.save(b2);
|
||||
|
||||
assertThat(LoggedSqlCollector.current()).isEmpty();
|
||||
// dont flush here
|
||||
Integer id = b1.getId();
|
||||
assertNotNull(id);
|
||||
assertThat(LoggedSqlCollector.current()).isEmpty();
|
||||
|
||||
EBasicVer b3 = new EBasicVer("b3");
|
||||
server.save(b3);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noflushWhenIdIsLoaded() {
|
||||
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
Transaction txn = server.beginTransaction();
|
||||
try {
|
||||
LoggedSqlCollector.start();
|
||||
txn.setBatchMode(true);
|
||||
|
||||
EBasicVer b1 = new EBasicVer("b1");
|
||||
b1.setId(546864);
|
||||
server.save(b1, txn);
|
||||
|
||||
EBasicVer b2 = new EBasicVer("b2");
|
||||
b2.setId(21354);
|
||||
server.save(b2, txn);
|
||||
|
||||
assertThat(LoggedSqlCollector.current()).isEmpty();
|
||||
//dont flush here
|
||||
Integer id = b1.getId();
|
||||
assertNotNull(id);
|
||||
assertThat(LoggedSqlCollector.current()).isEmpty();
|
||||
|
||||
EBasicVer b3 = new EBasicVer("b3");
|
||||
server.save(b3, txn);
|
||||
|
||||
txn.commit();
|
||||
assertThat(LoggedSqlCollector.current()).hasSize(3);
|
||||
|
||||
} finally {
|
||||
txn.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushOnGetProperty() {
|
||||
|
||||
@@ -7,7 +7,9 @@ import io.ebean.Query;
|
||||
import io.ebean.annotation.IgnorePlatform;
|
||||
import io.ebean.annotation.Platform;
|
||||
|
||||
import org.tests.model.basic.BBookmarkUser;
|
||||
import org.tests.model.basic.Contact;
|
||||
import org.tests.model.basic.Country;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
@@ -22,7 +24,46 @@ public class TestDeleteByQuery extends BaseTestCase {
|
||||
@Test
|
||||
@IgnorePlatform(Platform.MYSQL)
|
||||
// FIXME: MySql does not the sub query selecting from the delete table
|
||||
public void test() {
|
||||
public void deleteWithSubquery() {
|
||||
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
|
||||
BBookmarkUser u1 = new BBookmarkUser("u1");
|
||||
Ebean.save(u1);
|
||||
|
||||
Query<BBookmarkUser> query = server.find(BBookmarkUser.class)
|
||||
.where().eq("org.name", "NahYeahMaybe")
|
||||
.query();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
query.delete();
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
assertThat(loggedSql).hasSize(1);
|
||||
assertThat(trimSql(loggedSql.get(0), 1)).contains("delete from bbookmark_user where id in (select t0.id from bbookmark_user t0 left join bbookmark_org t1 on t1.id = t0.org_id where t1.name");
|
||||
|
||||
Query<BBookmarkUser> query2 = server.find(BBookmarkUser.class)
|
||||
.where().eq("name", "NotARealFirstName").query();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
query2.delete();
|
||||
|
||||
loggedSql = LoggedSqlCollector.stop();
|
||||
assertThat(loggedSql).hasSize(1);
|
||||
assertThat(loggedSql.get(0)).contains("delete from bbookmark_user where name =");
|
||||
|
||||
|
||||
server.find(BBookmarkUser.class).select("id").where().eq("name", "NotARealFirstName").delete();
|
||||
server.find(BBookmarkUser.class).select("id").where().eq("name", "TwoAlsoNotRealFirstName").query().delete();
|
||||
|
||||
List<BBookmarkUser> list = server.find(BBookmarkUser.class).select("id").where().eq("name", "NotARealFirstName").findList();
|
||||
assertThat(list).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnorePlatform(Platform.MYSQL)
|
||||
// FIXME: MySql does not the sub query selecting from the delete table
|
||||
public void deleteWithSubquery_withEscalation() {
|
||||
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
|
||||
@@ -33,7 +74,7 @@ public class TestDeleteByQuery extends BaseTestCase {
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
assertThat(loggedSql).hasSize(1);
|
||||
assertThat(trimSql(loggedSql.get(0), 1)).contains("delete from contact where id in (select t0.id from contact t0 left join");
|
||||
assertThat(trimSql(loggedSql.get(0), 1)).contains("select t0.id from contact t0 left join contact_group t1 on t1.id = t0.group_id where t1.name = ?");
|
||||
|
||||
Query<Contact> query2 = server.find(Contact.class).where().eq("firstName", "NotARealFirstName").query();
|
||||
|
||||
@@ -42,7 +83,7 @@ public class TestDeleteByQuery extends BaseTestCase {
|
||||
|
||||
loggedSql = LoggedSqlCollector.stop();
|
||||
assertThat(loggedSql).hasSize(1);
|
||||
assertThat(loggedSql.get(0)).contains("delete from contact where first_name =");
|
||||
assertThat(loggedSql.get(0)).contains("select t0.id from contact t0 where t0.first_name = ?");
|
||||
|
||||
|
||||
server.find(Contact.class).select("id").where().eq("firstName", "NotARealFirstName").delete();
|
||||
@@ -57,12 +98,29 @@ public class TestDeleteByQuery extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.find(BBookmarkUser.class).where().eq("id", 7000).delete();
|
||||
Ebean.find(BBookmarkUser.class).setId(7000).delete();
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql.get(0)).contains("delete from bbookmark_user where id = ?");
|
||||
assertThat(sql.get(1)).contains("delete from bbookmark_user where id = ?");
|
||||
|
||||
// and note this is the easiest option
|
||||
Ebean.delete(BBookmarkUser.class, 7000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryByIdDelete_withEscalation() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.find(Contact.class).where().eq("id", 7000).delete();
|
||||
Ebean.find(Contact.class).setId(7000).delete();
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql.get(0)).contains("delete from contact where id = ?");
|
||||
assertThat(sql.get(1)).contains("delete from contact where id = ?");
|
||||
// escalate to fetch ids then delete ... but no rows found
|
||||
assertThat(sql.get(0)).contains("select t0.id from contact t0 where t0.id = ?");
|
||||
assertThat(sql.get(1)).contains("select t0.id from contact t0 where t0.id = ?");
|
||||
|
||||
// and note this is the easiest option
|
||||
Ebean.delete(Contact.class, 7000);
|
||||
@@ -80,11 +138,23 @@ public class TestDeleteByQuery extends BaseTestCase {
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
assertThat(sql.get(0)).contains("delete from o_customer where name = ?");
|
||||
assertThat(sql.get(0)).contains("select t0.id from o_customer t0 where t0.name = ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommit() {
|
||||
public void deleteByPredicate() {
|
||||
|
||||
BBookmarkUser ud = new BBookmarkUser("deleteQueryByPredicate");
|
||||
Ebean.save(ud);
|
||||
|
||||
Ebean.find(BBookmarkUser.class).where().eq("name", "deleteQueryByPredicate").delete();
|
||||
|
||||
BBookmarkUser found = Ebean.find(BBookmarkUser.class, ud.getId());
|
||||
assertThat(found).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteByPredicate_withEscalation() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
@@ -101,4 +171,22 @@ public class TestDeleteByQuery extends BaseTestCase {
|
||||
Contact contactFind = Ebean.find(Contact.class, contact.getId());
|
||||
assertThat(contactFind).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteByPredicateCached() {
|
||||
|
||||
Country country = new Country();
|
||||
country.setCode("XX");
|
||||
country.setName("SecretName");
|
||||
Ebean.save(country);
|
||||
Query<Country> query = Ebean.find(Country.class).where().eq("name", "SecretName").setUseQueryCache(true);
|
||||
|
||||
assertThat(query.findList()).hasSize(1);
|
||||
assertThat(query.findCount()).isEqualTo(1);
|
||||
|
||||
Ebean.find(Country.class).where().eq("name", "SecretName").delete();
|
||||
//Ebean.getDefaultServer().getPluginApi().getBeanType(Country.class).clearQueryCache();
|
||||
assertThat(query.findList()).hasSize(0);
|
||||
assertThat(query.findCount()).isEqualTo(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.tests.merge;
|
||||
|
||||
import io.ebean.annotation.NotNull;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
@@ -12,7 +14,8 @@ public class MContactMessage extends MBase {
|
||||
|
||||
private String notes;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@NotNull
|
||||
@ManyToOne
|
||||
private MContact contact;
|
||||
|
||||
public MContactMessage(String title, String subject) {
|
||||
|
||||
@@ -26,44 +26,26 @@ public class BBookmark {
|
||||
@Column
|
||||
private BBookmarkUser user;
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public Integer getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(final Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bookmarkReference
|
||||
*/
|
||||
public String getBookmarkReference() {
|
||||
return this.bookmarkReference;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bookmarkReference the bookmarkReference to set
|
||||
*/
|
||||
public void setBookmarkReference(final String bookmarkReference) {
|
||||
this.bookmarkReference = bookmarkReference;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the user
|
||||
*/
|
||||
public BBookmarkUser getUser() {
|
||||
return this.user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param user the user to set
|
||||
*/
|
||||
public void setUser(final BBookmarkUser user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.tests.model.basic;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class BBookmarkOrg {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private int id;
|
||||
|
||||
private String name;
|
||||
|
||||
public BBookmarkOrg(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
package org.tests.model.basic;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
/**
|
||||
* represents a user entity. A user contains a username and password.
|
||||
*
|
||||
* @author Chris
|
||||
*/
|
||||
@Entity
|
||||
@@ -17,97 +15,69 @@ public class BBookmarkUser {
|
||||
@GeneratedValue
|
||||
private Integer id;
|
||||
|
||||
@Column
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
private String password;
|
||||
|
||||
@Column
|
||||
private String emailAddress;
|
||||
|
||||
@Column
|
||||
private String country;
|
||||
|
||||
// @Version
|
||||
// private Timestamp lastUpdate;
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
* An optional non-cascading ManyToOne.
|
||||
*/
|
||||
@ManyToOne
|
||||
private BBookmarkOrg org;
|
||||
|
||||
public BBookmarkUser(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(final Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the password
|
||||
*/
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param password the password to set
|
||||
*/
|
||||
public void setPassword(final String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the emailAddress
|
||||
*/
|
||||
public String getEmailAddress() {
|
||||
return this.emailAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param emailAddress the emailAddress to set
|
||||
*/
|
||||
public void setEmailAddress(final String emailAddress) {
|
||||
this.emailAddress = emailAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the country
|
||||
*/
|
||||
public String getCountry() {
|
||||
return this.country;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param country the country to set
|
||||
*/
|
||||
public void setCountry(final String country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
// public Timestamp getLastUpdate() {
|
||||
// return lastUpdate;
|
||||
// }
|
||||
//
|
||||
// public void setLastUpdate(Timestamp lastUpdate) {
|
||||
// this.lastUpdate = lastUpdate;
|
||||
// }
|
||||
public BBookmarkOrg getOrg() {
|
||||
return org;
|
||||
}
|
||||
|
||||
public void setOrg(BBookmarkOrg org) {
|
||||
this.org = org;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.tests.model.basic;
|
||||
|
||||
import io.ebean.annotation.Formula;
|
||||
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.Entity;
|
||||
|
||||
@@ -9,6 +11,9 @@ public class Cat extends Animal {
|
||||
|
||||
String name;
|
||||
|
||||
@Formula(select = "${ta}.species")
|
||||
String catFormula;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -17,4 +22,11 @@ public class Cat extends Animal {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getCatFormula() {
|
||||
return catFormula;
|
||||
}
|
||||
|
||||
public void setCatFormula(String catFormula) {
|
||||
this.catFormula = catFormula;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.tests.model.composite;
|
||||
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinColumns;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
@Entity
|
||||
public class CkeClient {
|
||||
|
||||
@EmbeddedId
|
||||
private CkeClientKey clientPK;
|
||||
|
||||
@JoinColumns({
|
||||
@JoinColumn(name = "username", referencedColumnName = "username"),
|
||||
@JoinColumn(name = "cod_cpny", referencedColumnName = "cod_cpny", insertable = false, updatable = false)
|
||||
})
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
private CkeUser user;
|
||||
|
||||
private String notes;
|
||||
|
||||
public CkeUser getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(CkeUser user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public CkeClientKey getClientPK() {
|
||||
return clientPK;
|
||||
}
|
||||
|
||||
public void setClientPK(CkeClientKey clientPK) {
|
||||
this.clientPK = clientPK;
|
||||
}
|
||||
|
||||
public String getNotes() {
|
||||
return notes;
|
||||
}
|
||||
|
||||
public void setNotes(String notes) {
|
||||
this.notes = notes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.tests.model.composite;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import java.util.Objects;
|
||||
|
||||
@Embeddable
|
||||
public class CkeClientKey {
|
||||
|
||||
@Basic(optional = false)
|
||||
@Column(name = "cod_cpny")
|
||||
private int codCompany;
|
||||
|
||||
@Basic(optional = false)
|
||||
@Column(name = "cod_client")
|
||||
private String codClient;
|
||||
|
||||
public CkeClientKey(int codCompany, String codClient) {
|
||||
this.codCompany = codCompany;
|
||||
this.codClient = codClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
CkeClientKey that = (CkeClientKey) o;
|
||||
return codCompany == that.codCompany &&
|
||||
Objects.equals(codClient, that.codClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(codCompany, codClient);
|
||||
}
|
||||
|
||||
public int getCodCompany() {
|
||||
return codCompany;
|
||||
}
|
||||
|
||||
public void setCodCompany(int codCompany) {
|
||||
this.codCompany = codCompany;
|
||||
}
|
||||
|
||||
public String getCodClient() {
|
||||
return codClient;
|
||||
}
|
||||
|
||||
public void setCodClient(String codClient) {
|
||||
this.codClient = codClient;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.tests.model.composite;
|
||||
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
|
||||
@Entity
|
||||
public class CkeUser {
|
||||
|
||||
@EmbeddedId
|
||||
private CkeUserKey userPK;
|
||||
|
||||
private String name;
|
||||
|
||||
public CkeUserKey getUserPK() {
|
||||
return userPK;
|
||||
}
|
||||
|
||||
public void setUserPK(CkeUserKey userPK) {
|
||||
this.userPK = userPK;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.tests.model.composite;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import java.util.Objects;
|
||||
|
||||
@Embeddable
|
||||
public class CkeUserKey {
|
||||
|
||||
@Basic(optional = false)
|
||||
@Column(name = "cod_cpny")
|
||||
private int codCompany;
|
||||
|
||||
@Basic(optional = false)
|
||||
@Column(name = "username")
|
||||
private String username;
|
||||
|
||||
public CkeUserKey(int codCompany, String username) {
|
||||
this.codCompany = codCompany;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
CkeUserKey that = (CkeUserKey) o;
|
||||
return codCompany == that.codCompany &&
|
||||
Objects.equals(username, that.username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(codCompany, username);
|
||||
}
|
||||
|
||||
public int getCodCompany() {
|
||||
return codCompany;
|
||||
}
|
||||
|
||||
public void setCodCompany(int codCompany) {
|
||||
this.codCompany = codCompany;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.tests.model.composite;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestCompositeKeyUserClient extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
CkeUser user0 = new CkeUser();
|
||||
user0.setUserPK(new CkeUserKey(20, "sally"));
|
||||
user0.setName("sally");
|
||||
Ebean.save(user0);
|
||||
|
||||
CkeUser user1 = new CkeUser();
|
||||
user1.setUserPK(new CkeUserKey(20, "frank"));
|
||||
user1.setName("hello");
|
||||
Ebean.save(user1);
|
||||
|
||||
CkeClient client = new CkeClient();
|
||||
client.setNotes("try it");
|
||||
client.setClientPK(new CkeClientKey(20, "susan"));
|
||||
client.setUser(user1);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.save(client);
|
||||
|
||||
client.setNotes("update it");
|
||||
client.setUser(user0);
|
||||
|
||||
Ebean.save(client);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("insert into cke_client (cod_cpny, cod_client, notes, username) values (?,?,?,?)");
|
||||
assertThat(sql.get(1)).contains("update cke_client set notes=?, username=? where cod_cpny=? and cod_client=?");
|
||||
|
||||
Ebean.delete(client);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.tests.model.lazywithid;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
@Entity
|
||||
public class Looney {
|
||||
@Id
|
||||
public Long id;
|
||||
|
||||
@ManyToOne
|
||||
private Tune tune;
|
||||
|
||||
private String name;
|
||||
|
||||
public Looney(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Tune getTune() {
|
||||
return tune;
|
||||
}
|
||||
|
||||
public void setTune(final Tune tune) {
|
||||
this.tune = tune;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.tests.model.lazywithid;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
|
||||
public class TestColumnIdName extends BaseTestCase {
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
Tune tune = new Tune();
|
||||
tune.getLoonies().add(new Looney("Taz"));
|
||||
Ebean.save(tune);
|
||||
|
||||
final List<Tune> fetchedCollection = Ebean.find(Tune.class).findList();
|
||||
|
||||
assertEquals(1, fetchedCollection.size());
|
||||
assertEquals(1, fetchedCollection.get(0).getLoonies().size());
|
||||
assertEquals("Taz", fetchedCollection.get(0).getLoonies().get(0).getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.tests.model.lazywithid;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import io.ebean.common.BeanList;
|
||||
|
||||
@Entity
|
||||
public class Tune {
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
Long _id;
|
||||
|
||||
String name;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
private List<Looney> loonies = new BeanList<>();
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<Looney> getLoonies() {
|
||||
return loonies;
|
||||
}
|
||||
|
||||
public void setLoonies(final List<Looney> loonies) {
|
||||
this.loonies = loonies;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.tests.model.onetoone;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.tests.model.BaseModel;
|
||||
|
||||
@Entity
|
||||
@Table(name = "oto_user_model")
|
||||
public class OtoUser extends BaseModel {
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToOne(cascade = CascadeType.ALL)
|
||||
private OtoUserOptional userOptional;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setOptional(OtoUserOptional userOptional) {
|
||||
this.userOptional = userOptional;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.tests.model.onetoone;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.tests.model.BaseModel;
|
||||
|
||||
@Entity
|
||||
@Table(name = "oto_user_model_optional")
|
||||
public class OtoUserOptional extends BaseModel {
|
||||
|
||||
private String optional;
|
||||
|
||||
public void setPassword(final String optional) {
|
||||
this.optional = optional;
|
||||
}
|
||||
|
||||
public String getOptional() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,28 +14,8 @@ public class TestInsertManyAndRef extends BaseTestCase {
|
||||
@Test
|
||||
public void testMe() {
|
||||
|
||||
// ResetBasicData.reset();
|
||||
//
|
||||
// Customer u = new Customer();
|
||||
// u.setName("Mr Test");
|
||||
//
|
||||
// final List<Order> bookmarks = new ArrayList<Order>();
|
||||
// final Order b1 = new Order();
|
||||
// b1.setCustomer(u);
|
||||
// b1.setStatus(Status.NEW);
|
||||
//
|
||||
// final Order b2 = new Order();
|
||||
// b2.setStatus(Status.NEW);
|
||||
// b2.setCustomer(u);
|
||||
//
|
||||
// bookmarks.add(b1);
|
||||
// bookmarks.add(b2);
|
||||
//
|
||||
// Ebean.save(bookmarks);
|
||||
|
||||
final BBookmarkUser u = new BBookmarkUser();
|
||||
final BBookmarkUser u = new BBookmarkUser("Mr Test");
|
||||
u.setEmailAddress("test@test.com");
|
||||
u.setName("Mr Test");
|
||||
u.setPassword("password");
|
||||
|
||||
final List<BBookmark> bookmarks = new ArrayList<>();
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.tests.types;
|
||||
|
||||
/**
|
||||
* Encrypted string.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*
|
||||
*/
|
||||
public class EncryptedBinary {
|
||||
|
||||
private final byte[] encryptedData;
|
||||
|
||||
EncryptedBinary(byte[] encryptedData) {
|
||||
this.encryptedData = encryptedData;
|
||||
}
|
||||
|
||||
public byte[] getEncryptedData() {
|
||||
return encryptedData;
|
||||
}
|
||||
|
||||
public byte[] decrypt() {
|
||||
return xor(encryptedData);
|
||||
}
|
||||
|
||||
public static EncryptedBinary encrypt(final byte[] s) {
|
||||
return new EncryptedBinary(xor(s));
|
||||
}
|
||||
|
||||
private static byte[] xor(byte[] s) {
|
||||
byte[] ret = new byte[s.length];
|
||||
for (int i = 0; i < s.length; i++) {
|
||||
ret[i] = (byte) (s[i] ^ i);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.tests.types;
|
||||
|
||||
/**
|
||||
* Encrypted string.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*
|
||||
*/
|
||||
public class EncryptedString {
|
||||
|
||||
private final String encryptedData;
|
||||
|
||||
EncryptedString(String encryptedData) {
|
||||
this.encryptedData = encryptedData;
|
||||
}
|
||||
|
||||
public String getEncryptedData() {
|
||||
return encryptedData;
|
||||
}
|
||||
|
||||
public String decrypt() {
|
||||
return rot13(encryptedData);
|
||||
}
|
||||
|
||||
public static EncryptedString encrypt(final String s) {
|
||||
return new EncryptedString(rot13(s));
|
||||
}
|
||||
|
||||
private static String rot13(String s) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
if (c >= 'a' && c <= 'm') c += 13;
|
||||
else if (c >= 'A' && c <= 'M') c += 13;
|
||||
else if (c >= 'n' && c <= 'z') c -= 13;
|
||||
else if (c >= 'N' && c <= 'Z') c -= 13;
|
||||
sb.append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.tests.types;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Lob;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.tests.model.BaseModel;
|
||||
|
||||
@Entity
|
||||
public class PasswordStoreModel extends BaseModel {
|
||||
private static final long serialVersionUID = 1L;
|
||||
// PasswordStoreModel should have the following column definitions in DDL
|
||||
// enc1 varchar(30),
|
||||
// enc2 varchar(40),
|
||||
// enc3 clob,
|
||||
// enc4 varbinary(30),
|
||||
// enc5 varbinary(40),
|
||||
// enc6 blob,
|
||||
|
||||
@Size(max = 30)
|
||||
private EncryptedString enc1;
|
||||
@Column(length = 40)
|
||||
private EncryptedString enc2;
|
||||
@Lob
|
||||
private EncryptedString enc3;
|
||||
|
||||
@Size(max = 30)
|
||||
private EncryptedBinary enc4;
|
||||
@Column(length = 40)
|
||||
private EncryptedBinary enc5;
|
||||
@Lob
|
||||
private EncryptedBinary enc6;
|
||||
|
||||
public EncryptedString getEnc1() {
|
||||
return enc1;
|
||||
}
|
||||
|
||||
public void setEnc1(EncryptedString enc1) {
|
||||
this.enc1 = enc1;
|
||||
}
|
||||
|
||||
public EncryptedString getEnc2() {
|
||||
return enc2;
|
||||
}
|
||||
|
||||
public void setEnc2(EncryptedString enc2) {
|
||||
this.enc2 = enc2;
|
||||
}
|
||||
|
||||
public EncryptedString getEnc3() {
|
||||
return enc3;
|
||||
}
|
||||
|
||||
public void setEnc3(EncryptedString enc3) {
|
||||
this.enc3 = enc3;
|
||||
}
|
||||
|
||||
public EncryptedBinary getEnc4() {
|
||||
return enc4;
|
||||
}
|
||||
|
||||
public void setEnc4(EncryptedBinary enc4) {
|
||||
this.enc4 = enc4;
|
||||
}
|
||||
|
||||
public EncryptedBinary getEnc5() {
|
||||
return enc5;
|
||||
}
|
||||
|
||||
public void setEnc5(EncryptedBinary enc5) {
|
||||
this.enc5 = enc5;
|
||||
}
|
||||
|
||||
public EncryptedBinary getEnc6() {
|
||||
return enc6;
|
||||
}
|
||||
|
||||
public void setEnc6(EncryptedBinary enc6) {
|
||||
this.enc6 = enc6;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.tests.types;
|
||||
|
||||
import io.ebean.config.ScalarTypeConverter;
|
||||
|
||||
public class ScalarTypeEncryptedBinaryConverter implements ScalarTypeConverter<EncryptedBinary, byte[]> {
|
||||
|
||||
|
||||
@Override
|
||||
public EncryptedBinary getNullValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EncryptedBinary wrapValue(final byte[] scalarType) {
|
||||
return new EncryptedBinary(scalarType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] unwrapValue(final EncryptedBinary beanType) {
|
||||
return beanType.getEncryptedData();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.tests.types;
|
||||
|
||||
import io.ebean.config.ScalarTypeConverter;
|
||||
|
||||
public class ScalarTypeEncryptedStringConverter implements ScalarTypeConverter<EncryptedString, String> {
|
||||
|
||||
@Override
|
||||
public EncryptedString getNullValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EncryptedString wrapValue(final String scalarType) {
|
||||
return new EncryptedString(scalarType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String unwrapValue(final EncryptedString beanType) {
|
||||
return beanType.getEncryptedData();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.tests.types;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestEncryptedString extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void testName() {
|
||||
PasswordStoreModel model = new PasswordStoreModel();
|
||||
|
||||
model.setEnc1(EncryptedString.encrypt("Hello"));
|
||||
model.setEnc2(EncryptedString.encrypt("World"));
|
||||
model.setEnc3(EncryptedString.encrypt("Test"));
|
||||
|
||||
model.setEnc4(EncryptedBinary.encrypt("Hello".getBytes(StandardCharsets.UTF_8)));
|
||||
model.setEnc5(EncryptedBinary.encrypt("World".getBytes(StandardCharsets.UTF_8)));
|
||||
model.setEnc6(EncryptedBinary.encrypt("Test".getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
|
||||
model.save();
|
||||
|
||||
model = Ebean.find(PasswordStoreModel.class, model.getId());
|
||||
|
||||
assertThat(model.getEnc1().getEncryptedData()).isNotEqualTo("Hello");
|
||||
assertThat(model.getEnc2().getEncryptedData()).isNotEqualTo("World");
|
||||
assertThat(model.getEnc3().getEncryptedData()).isNotEqualTo("Test");
|
||||
assertThat(model.getEnc4().getEncryptedData()).isNotEqualTo("Hello".getBytes(StandardCharsets.UTF_8));
|
||||
assertThat(model.getEnc5().getEncryptedData()).isNotEqualTo("World".getBytes(StandardCharsets.UTF_8));
|
||||
assertThat(model.getEnc6().getEncryptedData()).isNotEqualTo("Test".getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
|
||||
assertThat(model.getEnc1().decrypt()).isEqualTo("Hello");
|
||||
assertThat(model.getEnc2().decrypt()).isEqualTo("World");
|
||||
assertThat(model.getEnc3().decrypt()).isEqualTo("Test");
|
||||
assertThat(model.getEnc4().decrypt()).isEqualTo("Hello".getBytes(StandardCharsets.UTF_8));
|
||||
assertThat(model.getEnc5().decrypt()).isEqualTo("World".getBytes(StandardCharsets.UTF_8));
|
||||
assertThat(model.getEnc6().decrypt()).isEqualTo("Test".getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,9 @@ package org.tests.types;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.plugin.BeanType;
|
||||
import io.ebean.plugin.ExpressionPath;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.tests.model.types.SomeNewTypesBean;
|
||||
|
||||
@@ -21,9 +24,7 @@ import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class TestNewTypes extends BaseTestCase {
|
||||
|
||||
@@ -145,4 +146,90 @@ public class TestNewTypes extends BaseTestCase {
|
||||
assertNull(fetched.getPath());
|
||||
assertNull(fetched.getPeriod());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetGetPathNonNull() throws Exception {
|
||||
SomeNewTypesBean refBean = new SomeNewTypesBean();
|
||||
refBean.setLocalDate(LocalDate.now());
|
||||
refBean.setLocalDateTime(LocalDateTime.now());
|
||||
refBean.setOffsetDateTime(OffsetDateTime.now());
|
||||
refBean.setZonedDateTime(ZonedDateTime.now());
|
||||
refBean.setInstant(Instant.now());
|
||||
refBean.setYear(Year.now());
|
||||
refBean.setMonth(Month.APRIL);
|
||||
refBean.setDayOfWeek(DayOfWeek.WEDNESDAY);
|
||||
refBean.setZoneId(ZoneId.systemDefault());
|
||||
refBean.setZoneOffset(ZonedDateTime.now().getOffset());
|
||||
refBean.setYearMonth(YearMonth.of(2014, 9));
|
||||
refBean.setPath(Paths.get(TEMP_PATH));
|
||||
refBean.setPeriod(Period.of(4,3,2));
|
||||
|
||||
testSetGetPath(refBean);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetGetPathNull() throws Exception {
|
||||
SomeNewTypesBean refBean = new SomeNewTypesBean();
|
||||
testSetGetPath(refBean);
|
||||
}
|
||||
private void testSetGetPath(SomeNewTypesBean refBean) {
|
||||
SomeNewTypesBean testBean = new SomeNewTypesBean();
|
||||
BeanType<SomeNewTypesBean> beanType = Ebean.getDefaultServer().getPluginApi().getBeanType(SomeNewTypesBean.class);
|
||||
ExpressionPath localDate = beanType.getExpressionPath("localDate");
|
||||
ExpressionPath localDateTime = beanType.getExpressionPath("localDateTime");
|
||||
ExpressionPath offsetDateTime = beanType.getExpressionPath("offsetDateTime");
|
||||
ExpressionPath zonedDateTime = beanType.getExpressionPath("zonedDateTime");
|
||||
ExpressionPath instant = beanType.getExpressionPath("instant");
|
||||
ExpressionPath year = beanType.getExpressionPath("year");
|
||||
ExpressionPath month = beanType.getExpressionPath("month");
|
||||
ExpressionPath dayOfWeek = beanType.getExpressionPath("dayOfWeek");
|
||||
ExpressionPath zoneId = beanType.getExpressionPath("zoneId");
|
||||
ExpressionPath zoneOffset = beanType.getExpressionPath("zoneOffset");
|
||||
ExpressionPath yearMonth = beanType.getExpressionPath("yearMonth");
|
||||
ExpressionPath path = beanType.getExpressionPath("path");
|
||||
ExpressionPath period = beanType.getExpressionPath("period");
|
||||
|
||||
localDate.pathSet(testBean, refBean.getLocalDate());
|
||||
assertThat(localDate.pathGet(testBean)).isEqualTo(refBean.getLocalDate());
|
||||
|
||||
localDateTime.pathSet(testBean, refBean.getLocalDateTime());
|
||||
assertThat(localDateTime.pathGet(testBean)).isEqualTo(refBean.getLocalDateTime());
|
||||
|
||||
offsetDateTime.pathSet(testBean, refBean.getOffsetDateTime());
|
||||
assertThat(offsetDateTime.pathGet(testBean)).isEqualTo(refBean.getOffsetDateTime());
|
||||
|
||||
zonedDateTime.pathSet(testBean, refBean.getZonedDateTime());
|
||||
assertThat(zonedDateTime.pathGet(testBean)).isEqualTo(refBean.getZonedDateTime());
|
||||
|
||||
instant.pathSet(testBean, refBean.getInstant());
|
||||
assertThat(instant.pathGet(testBean)).isEqualTo(refBean.getInstant());
|
||||
|
||||
year.pathSet(testBean, refBean.getYear());
|
||||
assertThat(year.pathGet(testBean)).isEqualTo(refBean.getYear());
|
||||
|
||||
month.pathSet(testBean, refBean.getMonth());
|
||||
assertThat(month.pathGet(testBean)).isEqualTo(refBean.getMonth());
|
||||
|
||||
dayOfWeek.pathSet(testBean, refBean.getDayOfWeek());
|
||||
assertThat(dayOfWeek.pathGet(testBean)).isEqualTo(refBean.getDayOfWeek());
|
||||
|
||||
zoneId.pathSet(testBean, refBean.getZoneId());
|
||||
assertThat(zoneId.pathGet(testBean)).isEqualTo(refBean.getZoneId());
|
||||
|
||||
zoneOffset.pathSet(testBean, refBean.getZoneOffset());
|
||||
assertThat(zoneOffset.pathGet(testBean)).isEqualTo(refBean.getZoneOffset());
|
||||
|
||||
yearMonth.pathSet(testBean, refBean.getYearMonth());
|
||||
assertThat(yearMonth.pathGet(testBean)).isEqualTo(refBean.getYearMonth());
|
||||
|
||||
path.pathSet(testBean, refBean.getPath());
|
||||
assertThat(path.pathGet(testBean)).isEqualTo(refBean.getPath());
|
||||
|
||||
period.pathSet(testBean, refBean.getPeriod());
|
||||
assertThat(period.pathGet(testBean)).isEqualTo(refBean.getPeriod());
|
||||
|
||||
Ebean.save(refBean);
|
||||
Ebean.save(testBean);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user