mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d4886d808 | ||
|
|
d11bb2c4e5 | ||
|
|
663b1bb4aa | ||
|
|
f3d26e32ec | ||
|
|
5f83584315 | ||
|
|
d28e3ee456 | ||
|
|
e1b7161b22 | ||
|
|
f63a3cb926 | ||
|
|
29c5a17202 | ||
|
|
340b100a1a | ||
|
|
80975acfbf | ||
|
|
95dab97b1b | ||
|
|
ce10dd79f9 | ||
|
|
3f12739e71 | ||
|
|
cd1ae20015 | ||
|
|
6d1e3a08e1 | ||
|
|
94e6fe90e5 | ||
|
|
9bbe99657a | ||
|
|
0faf9f54ea |
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>11.20.2</version>
|
||||
<version>11.22.2</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.20.2</tag>
|
||||
<tag>ebean-11.22.2</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
@@ -135,7 +135,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>11.8.2</version>
|
||||
<version>11.9.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -52,7 +52,7 @@ public class DatabasePlatform {
|
||||
/**
|
||||
* The behaviour used when ending a read only transaction at read committed isolation level.
|
||||
*/
|
||||
protected OnQueryOnly onQueryOnly = OnQueryOnly.ROLLBACK;
|
||||
protected OnQueryOnly onQueryOnly = OnQueryOnly.COMMIT;
|
||||
|
||||
/**
|
||||
* The open quote used by quoted identifiers.
|
||||
|
||||
@@ -184,13 +184,12 @@ public class ModelContainer {
|
||||
/**
|
||||
* Unset the withHistory flag on the associated base table.
|
||||
*/
|
||||
private void applyChange(DropHistoryTable change) {
|
||||
protected void applyChange(DropHistoryTable change) {
|
||||
|
||||
MTable table = tables.get(change.getBaseTable());
|
||||
if (table == null) {
|
||||
throw new IllegalStateException("Table [" + change.getBaseTable() + "] does not exist in model?");
|
||||
if (table != null) {
|
||||
table.setWithHistory(false);
|
||||
}
|
||||
table.setWithHistory(false);
|
||||
}
|
||||
|
||||
private void applyChange(AddUniqueConstraint change) {
|
||||
@@ -241,19 +240,14 @@ public class ModelContainer {
|
||||
if (tables.containsKey(tableName)) {
|
||||
throw new IllegalStateException("Table [" + tableName + "] already exists in model?");
|
||||
}
|
||||
MTable table = new MTable(createTable);
|
||||
tables.put(tableName, table);
|
||||
tables.put(tableName, new MTable(createTable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a DropTable change to the model.
|
||||
*/
|
||||
protected void applyChange(DropTable dropTable) {
|
||||
String tableName = dropTable.getName();
|
||||
if (!tables.containsKey(tableName)) {
|
||||
throw new IllegalStateException("Table [" + tableName + "] does not exists in model?");
|
||||
}
|
||||
tables.remove(tableName);
|
||||
tables.remove(dropTable.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,22 +258,16 @@ public class ModelContainer {
|
||||
if (indexes.containsKey(indexName)) {
|
||||
throw new IllegalStateException("Index [" + indexName + "] already exists in model?");
|
||||
}
|
||||
MIndex index = new MIndex(createIndex);
|
||||
indexes.put(createIndex.getIndexName(), index);
|
||||
indexes.put(createIndex.getIndexName(), new MIndex(createIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a DropTable change to the model.
|
||||
*/
|
||||
protected void applyChange(DropIndex dropIndex) {
|
||||
String name = dropIndex.getIndexName();
|
||||
if (!indexes.containsKey(name)) {
|
||||
throw new IllegalStateException("Index [" + name + "] does not exist in model?");
|
||||
}
|
||||
indexes.remove(name);
|
||||
indexes.remove(dropIndex.getIndexName());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Apply a AddColumn change to the model.
|
||||
*/
|
||||
|
||||
@@ -31,6 +31,7 @@ import io.ebeanservice.docstore.api.DocStoreUpdate;
|
||||
import io.ebeanservice.docstore.api.DocStoreUpdateContext;
|
||||
import io.ebeanservice.docstore.api.DocStoreUpdates;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.IOException;
|
||||
@@ -854,12 +855,11 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
*/
|
||||
@Override
|
||||
public final void checkRowCount(int rowCount) {
|
||||
if (ConcurrencyMode.VERSION == concurrencyMode && rowCount != 1) {
|
||||
// fix for oracle.
|
||||
// see: https://stackoverflow.com/questions/19022175/executebatch-method-return-array-of-value-2-in-java
|
||||
if (rowCount != Statement.SUCCESS_NO_INFO) {
|
||||
String m = Message.msg("persist.conc2", String.valueOf(rowCount));
|
||||
throw new OptimisticLockException(m, null, bean);
|
||||
if (rowCount != 1 && rowCount != Statement.SUCCESS_NO_INFO) {
|
||||
if (ConcurrencyMode.VERSION == concurrencyMode) {
|
||||
throw new OptimisticLockException(Message.msg("persist.conc2", String.valueOf(rowCount)), null, bean);
|
||||
} else if (rowCount == 0 && type == Type.UPDATE) {
|
||||
throw new EntityNotFoundException("No rows updated");
|
||||
}
|
||||
}
|
||||
switch (type) {
|
||||
@@ -1307,14 +1307,22 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
* Set the request flags indicating this is an insert.
|
||||
*/
|
||||
public void flagInsert() {
|
||||
flags = Flags.setInsert(flags);
|
||||
if (intercept.isNew()) {
|
||||
flags = Flags.setInsertNormal(flags);
|
||||
} else {
|
||||
flags = Flags.setInsert(flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset the request insert flag indicating this is an update.
|
||||
*/
|
||||
public void flagUpdate() {
|
||||
flags = Flags.unsetInsert(flags);
|
||||
if (intercept.isLoaded()) {
|
||||
flags = Flags.setUpdateNormal(flags);
|
||||
} else {
|
||||
flags = Flags.setUpdate(flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -456,8 +456,7 @@ public final class DefaultPersister implements Persister {
|
||||
void saveRecurse(EntityBean bean, Transaction t, Object parentBean, int flags) {
|
||||
|
||||
// determine insert or update taking into account stateless updates
|
||||
PersistRequestBean<?> request = createRequestRecurse(bean, t, parentBean, flags);
|
||||
saveRecurse(request);
|
||||
saveRecurse(createRequestRecurse(bean, t, parentBean, flags));
|
||||
}
|
||||
|
||||
private void saveRecurse(PersistRequestBean<?> request) {
|
||||
@@ -1229,8 +1228,8 @@ public final class DefaultPersister implements Persister {
|
||||
BeanDescriptor<T> desc = mgr.getBeanDescriptor();
|
||||
EntityBean entityBean = (EntityBean) bean;
|
||||
PersistRequest.Type type;
|
||||
if (Flags.isPublishOrMerge(flags)) {
|
||||
// insert if it is a new bean (as publish created it)
|
||||
if (Flags.isPublishMergeOrNormal(flags)) {
|
||||
// just use bean state to determine insert or update
|
||||
type = entityBean._ebean_getIntercept().isUpdate() ? Type.UPDATE : Type.INSERT;
|
||||
} else {
|
||||
// determine Insert or Update based on bean state and insert flag
|
||||
|
||||
@@ -5,7 +5,7 @@ package io.ebeaninternal.server.persist;
|
||||
* <p>
|
||||
* Allows passing of flag state when recursively persisting.
|
||||
*/
|
||||
public class Flags {
|
||||
public final class Flags {
|
||||
|
||||
/**
|
||||
* Indicates the bean is being inserted.
|
||||
@@ -27,6 +27,11 @@ public class Flags {
|
||||
*/
|
||||
public static final int MERGE = 0x00000008;
|
||||
|
||||
/**
|
||||
* Indicates Normal insert or update (not forced).
|
||||
*/
|
||||
public static final int NORMAL = 0x00000010;
|
||||
|
||||
/**
|
||||
* No flags set.
|
||||
*/
|
||||
@@ -34,7 +39,9 @@ public class Flags {
|
||||
|
||||
public static final int PUBLISH_RECURSE = PUBLISH + RECURSE;
|
||||
|
||||
private static final int PUBLISH_MERGE = PUBLISH + MERGE;
|
||||
private static final int PUBLISH_MERGE_NORMAL = PUBLISH + MERGE + NORMAL;
|
||||
|
||||
private static final int INSERT_NORMAL = INSERT + NORMAL;
|
||||
|
||||
/**
|
||||
* Return true if the bean is being inserted.
|
||||
@@ -65,10 +72,10 @@ public class Flags {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if part of a Merge or Publish.
|
||||
* Return true if part of a Merge or Publish or Normal (bean state matches persist).
|
||||
*/
|
||||
public static boolean isPublishOrMerge(long state) {
|
||||
return (state & PUBLISH_MERGE) != 0;
|
||||
public static boolean isPublishMergeOrNormal(int state) {
|
||||
return (state & PUBLISH_MERGE_NORMAL) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,54 +89,70 @@ public class Flags {
|
||||
* Set Insert flag.
|
||||
*/
|
||||
public static int setInsert(int state) {
|
||||
return set(state, INSERT, true);
|
||||
return set(state, INSERT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert flag and normal in that bean is in NEW state (for insert).
|
||||
*/
|
||||
public static int setInsertNormal(int state) {
|
||||
return set(state, INSERT_NORMAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parent was not inserted.
|
||||
*/
|
||||
public static int unsetInsert(int state) {
|
||||
return set(state, INSERT, false);
|
||||
public static int setUpdate(int state) {
|
||||
return unset(state, INSERT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not Insert and normal in that bean is in LOADED state (for update).
|
||||
*/
|
||||
public static int setUpdateNormal(int state) {
|
||||
state &= ~INSERT;
|
||||
state |= NORMAL;
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Recurse flag.
|
||||
*/
|
||||
public static int setRecurse(int state) {
|
||||
return set(state, RECURSE, true);
|
||||
return set(state, RECURSE);
|
||||
}
|
||||
|
||||
public static int unsetRecuse(int state) {
|
||||
return set(state, RECURSE, false);
|
||||
return unset(state, RECURSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Publish flag.
|
||||
*/
|
||||
public static int setPublish(int state) {
|
||||
return set(state, PUBLISH, true);
|
||||
return set(state, PUBLISH);
|
||||
}
|
||||
|
||||
public static int unsetPublish(int state) {
|
||||
return set(state, PUBLISH, false);
|
||||
return unset(state, PUBLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Merge flag.
|
||||
*/
|
||||
public static int setMerge(int state) {
|
||||
return set(state, MERGE, true);
|
||||
return set(state, MERGE);
|
||||
}
|
||||
|
||||
public static int unsetMerge(int state) {
|
||||
return set(state, MERGE, false);
|
||||
return unset(state, MERGE);
|
||||
}
|
||||
|
||||
private static int set(int state, int flag, boolean setFlag) {
|
||||
if (setFlag) {
|
||||
return (state |= flag);
|
||||
} else {
|
||||
return state &= ~flag;
|
||||
}
|
||||
private static int set(int state, int flag) {
|
||||
return (state |= flag);
|
||||
}
|
||||
|
||||
private static int unset(int state, int flag) {
|
||||
return state &= ~flag;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import io.ebeaninternal.server.lib.util.Str;
|
||||
import io.ebeaninternal.server.persist.BatchedPstmt;
|
||||
import io.ebeaninternal.server.persist.BatchedPstmtHolder;
|
||||
import io.ebeaninternal.server.persist.dmlbind.BindableRequest;
|
||||
import io.ebeaninternal.server.transaction.TransactionManager;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -301,7 +301,7 @@ public class TransactionManager implements SpiTransactionManager {
|
||||
}
|
||||
|
||||
// default to rollback if not defined on the platform
|
||||
return dbPlatformOnQueryOnly == null ? OnQueryOnly.ROLLBACK : dbPlatformOnQueryOnly;
|
||||
return dbPlatformOnQueryOnly == null ? OnQueryOnly.COMMIT : dbPlatformOnQueryOnly;
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
|
||||
@@ -112,14 +112,14 @@ interface ArrayElementConverter<T> {
|
||||
|
||||
@Override
|
||||
public Object toElement(Object rawValue) {
|
||||
return scalarType.parse(rawValue.toString());
|
||||
return scalarType.toBeanType(rawValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toDbArray(Object[] objects) {
|
||||
Object[] dbArray = new Object[objects.length];
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
dbArray[i] = scalarType.format(objects[i]);
|
||||
dbArray[i] = scalarType.toJdbcType(objects[i]);
|
||||
}
|
||||
return dbArray;
|
||||
}
|
||||
|
||||
@@ -351,7 +351,7 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
if (type.equals(List.class)) {
|
||||
if (arrayTypeListFactory != null) {
|
||||
if (isEnumType(valueType)) {
|
||||
return arrayTypeListFactory.typeForEnum(createEnumScalarType(asEnumClass(valueType), EnumType.STRING));
|
||||
return arrayTypeListFactory.typeForEnum(createEnumScalarType(asEnumClass(valueType), null));
|
||||
}
|
||||
return arrayTypeListFactory.typeFor(valueType);
|
||||
}
|
||||
@@ -360,7 +360,7 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
} else if (type.equals(Set.class)) {
|
||||
if (arrayTypeSetFactory != null) {
|
||||
if (isEnumType(valueType)) {
|
||||
return arrayTypeSetFactory.typeForEnum(createEnumScalarType(asEnumClass(valueType), EnumType.STRING));
|
||||
return arrayTypeSetFactory.typeForEnum(createEnumScalarType(asEnumClass(valueType), null));
|
||||
}
|
||||
return arrayTypeSetFactory.typeFor(valueType);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,19 @@ public class ScalarTypeArrayList extends ScalarTypeJsonCollection<List> implemen
|
||||
|
||||
@Override
|
||||
public ScalarTypeArrayList typeForEnum(ScalarType<?> scalarType) {
|
||||
return new ScalarTypeArrayList("varchar", DocPropertyType.TEXT, new ArrayElementConverter.EnumConverter(scalarType));
|
||||
final String arrayType;
|
||||
switch (scalarType.getJdbcType()) {
|
||||
case Types.INTEGER:
|
||||
arrayType = "integer";
|
||||
break;
|
||||
case Types.VARCHAR:
|
||||
arrayType = "varchar";
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("JdbcType [" + scalarType.getJdbcType() + "] not supported for @DbArray mapping on set.");
|
||||
}
|
||||
|
||||
return new ScalarTypeArrayList(arrayType, scalarType.getDocType(), new ArrayElementConverter.EnumConverter(scalarType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,13 +54,24 @@ public class ScalarTypeArraySet<T> extends ScalarTypeJsonCollection<Set<T>> impl
|
||||
if (valueType.equals(String.class)) {
|
||||
return STRING;
|
||||
}
|
||||
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping on set");
|
||||
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping on list");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public ScalarTypeArraySet typeForEnum(ScalarType<?> scalarType) {
|
||||
return new ScalarTypeArraySet("varchar", DocPropertyType.TEXT, new ArrayElementConverter.EnumConverter(scalarType));
|
||||
final String arrayType;
|
||||
switch (scalarType.getJdbcType()) {
|
||||
case Types.INTEGER:
|
||||
arrayType = "integer";
|
||||
break;
|
||||
case Types.VARCHAR:
|
||||
arrayType = "varchar";
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("JdbcType [" + scalarType.getJdbcType() + "] not supported for @DbArray mapping on set.");
|
||||
}
|
||||
return new ScalarTypeArraySet(arrayType, scalarType.getDocType(), new ArrayElementConverter.EnumConverter(scalarType));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,9 +79,9 @@ public class ScalarTypeArraySet<T> extends ScalarTypeJsonCollection<Set<T>> impl
|
||||
|
||||
private final ArrayElementConverter<T> converter;
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public ScalarTypeArraySet(String arrayType, DocPropertyType docPropertyType, ArrayElementConverter<T> converter) {
|
||||
super((Class)Set.class, Types.ARRAY, docPropertyType);
|
||||
super((Class) Set.class, Types.ARRAY, docPropertyType);
|
||||
this.arrayType = arrayType;
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* H2 database support for DB ARRAY.
|
||||
*/
|
||||
@@ -48,13 +49,13 @@ class ScalarTypeArraySetH2<T> extends ScalarTypeArraySet<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public ScalarTypeArraySetH2 typeForEnum(ScalarType<?> scalarType) {
|
||||
return new ScalarTypeArraySetH2("varchar", DocPropertyType.TEXT, new ArrayElementConverter.EnumConverter(scalarType));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private ScalarTypeArraySetH2(String arrayType, DocPropertyType docPropertyType, ArrayElementConverter converter) {
|
||||
super(arrayType, docPropertyType, converter);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package io.ebeaninternal.dbmigration.model;
|
||||
|
||||
|
||||
import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
|
||||
import io.ebeaninternal.dbmigration.migration.DropIndex;
|
||||
import io.ebeaninternal.dbmigration.migration.DropTable;
|
||||
import io.ebeaninternal.dbmigration.migration.Migration;
|
||||
import io.ebeaninternal.dbmigration.migrationreader.MigrationXmlReader;
|
||||
import org.junit.Test;
|
||||
@@ -79,6 +82,31 @@ public class ModelContainerTest {
|
||||
assertThat(container.getPendingDrops()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void apply_dropTable_when_notInModel_then_ok() {
|
||||
|
||||
ModelContainer container = new ModelContainer();
|
||||
container.apply(mig("5.0__dropTable.model.xml"), ver("5.0"));
|
||||
assertThat(container.getTables()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void apply_drop_when_notInModel_then_ok() {
|
||||
|
||||
ModelContainer container = new ModelContainer();
|
||||
DropTable dropTable = new DropTable();
|
||||
dropTable.setName("DoesNotExist");
|
||||
container.applyChange(dropTable);
|
||||
|
||||
DropIndex dropIndex = new DropIndex();
|
||||
dropIndex.setIndexName("DoesNotExist");
|
||||
container.applyChange(dropIndex);
|
||||
|
||||
DropHistoryTable dropHistoryTable = new DropHistoryTable();
|
||||
dropHistoryTable.setBaseTable("DoesNotExist");
|
||||
container.applyChange(dropHistoryTable);
|
||||
}
|
||||
|
||||
private ModelContainer container_2_1() {
|
||||
ModelContainer container = new ModelContainer();
|
||||
container.apply(mig("2.0.model.xml"), ver("2.0"));
|
||||
|
||||
@@ -26,19 +26,60 @@ public class FlagsTest {
|
||||
assertThat(Flags.isSet(state, Flags.PUBLISH)).isFalse();
|
||||
assertThat(Flags.isSet(state, Flags.MERGE)).isTrue();
|
||||
assertThat(Flags.isSet(state, Flags.INSERT)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insert() {
|
||||
|
||||
int state = 0;
|
||||
|
||||
state = Flags.setInsert(state);
|
||||
assertThat(Flags.isSet(state, Flags.INSERT)).isTrue();
|
||||
assertThat(Flags.isSet(state, Flags.NORMAL)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insertNormal() {
|
||||
|
||||
int state = 0;
|
||||
|
||||
state = Flags.setInsertNormal(state);
|
||||
assertThat(Flags.isSet(state, Flags.INSERT)).isTrue();
|
||||
assertThat(Flags.isSet(state, Flags.NORMAL)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void update() {
|
||||
|
||||
int state = 0;
|
||||
|
||||
state = Flags.setUpdate(state);
|
||||
assertThat(Flags.isSet(state, Flags.INSERT)).isFalse();
|
||||
assertThat(Flags.isSet(state, Flags.NORMAL)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateNormal() {
|
||||
|
||||
int state = 0;
|
||||
|
||||
state = Flags.setUpdateNormal(state);
|
||||
assertThat(Flags.isSet(state, Flags.INSERT)).isFalse();
|
||||
assertThat(Flags.isSet(state, Flags.NORMAL)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPublishOrMerge() {
|
||||
|
||||
assertThat(Flags.isPublishOrMerge(0)).isFalse();
|
||||
assertThat(Flags.isPublishOrMerge(Flags.INSERT)).isFalse();
|
||||
assertThat(Flags.isPublishMergeOrNormal(0)).isFalse();
|
||||
assertThat(Flags.isPublishMergeOrNormal(Flags.INSERT)).isFalse();
|
||||
assertThat(Flags.isPublishMergeOrNormal(Flags.RECURSE)).isFalse();
|
||||
|
||||
assertThat(Flags.isPublishOrMerge(Flags.PUBLISH)).isTrue();
|
||||
assertThat(Flags.isPublishOrMerge(Flags.MERGE)).isTrue();
|
||||
assertThat(Flags.isPublishMergeOrNormal(Flags.PUBLISH)).isTrue();
|
||||
assertThat(Flags.isPublishMergeOrNormal(Flags.MERGE)).isTrue();
|
||||
assertThat(Flags.isPublishMergeOrNormal(Flags.NORMAL)).isTrue();
|
||||
|
||||
int mergePublish = Flags.setMerge(Flags.setPublish(0));
|
||||
assertThat(Flags.isPublishOrMerge(mergePublish)).isTrue();
|
||||
assertThat(Flags.isPublishMergeOrNormal(mergePublish)).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ public class EArrayBean {
|
||||
ONE, TWO, THREE
|
||||
}
|
||||
|
||||
IntEnum foo;
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@@ -38,12 +40,26 @@ public class EArrayBean {
|
||||
@DbArray
|
||||
List<Status> statuses;
|
||||
|
||||
@DbArray
|
||||
List<VarcharEnum> vcEnums = new ArrayList<>();
|
||||
|
||||
@DbArray
|
||||
List<IntEnum> intEnums = new ArrayList<>();
|
||||
|
||||
@DbArray
|
||||
Set<Status> status2;
|
||||
|
||||
@Version
|
||||
Long version;
|
||||
|
||||
public IntEnum getFoo() {
|
||||
return foo;
|
||||
}
|
||||
|
||||
public void setFoo(final IntEnum foo) {
|
||||
this.foo = foo;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
@@ -100,6 +116,21 @@ public class EArrayBean {
|
||||
this.statuses = statuses;
|
||||
}
|
||||
|
||||
public List<VarcharEnum> getVcEnums() {
|
||||
return vcEnums;
|
||||
}
|
||||
|
||||
public void setVcEnums(final List<VarcharEnum> vcEnums) {
|
||||
this.vcEnums = vcEnums;
|
||||
}
|
||||
|
||||
public List<IntEnum> getIntEnums() {
|
||||
return intEnums;
|
||||
}
|
||||
|
||||
public void setIntEnums(final List<IntEnum> intEnums) {
|
||||
this.intEnums = intEnums;
|
||||
}
|
||||
|
||||
public Set<Status> getStatus2() {
|
||||
return status2;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.tests.model.array;
|
||||
|
||||
import io.ebean.annotation.DbEnumType;
|
||||
import io.ebean.annotation.DbEnumValue;
|
||||
|
||||
public enum IntEnum {
|
||||
ZERO, ONE, TWO;
|
||||
|
||||
@DbEnumValue(storage = DbEnumType.INTEGER)
|
||||
public int dbValue() {
|
||||
return 100 + ordinal();
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,22 @@
|
||||
package org.tests.model.array;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.Query;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.SqlRow;
|
||||
|
||||
public class TestDbArray_basic extends BaseTestCase {
|
||||
|
||||
@@ -22,7 +25,7 @@ public class TestDbArray_basic extends BaseTestCase {
|
||||
private EArrayBean found;
|
||||
|
||||
@Test
|
||||
public void insert() {
|
||||
public void insert() throws SQLException {
|
||||
|
||||
bean.setName("some stuff");
|
||||
|
||||
@@ -44,6 +47,10 @@ public class TestDbArray_basic extends BaseTestCase {
|
||||
bean.setStatuses(new ArrayList<>());
|
||||
bean.getStatuses().add(EArrayBean.Status.ONE);
|
||||
bean.getStatuses().add(EArrayBean.Status.THREE);
|
||||
bean.getVcEnums().add(VarcharEnum.ONE);
|
||||
bean.getVcEnums().add(VarcharEnum.TWO);
|
||||
bean.getIntEnums().add(IntEnum.ZERO);
|
||||
bean.getIntEnums().add(IntEnum.TWO);
|
||||
|
||||
bean.setStatus2(new LinkedHashSet<>());
|
||||
bean.getStatus2().add(EArrayBean.Status.TWO);
|
||||
@@ -64,16 +71,23 @@ public class TestDbArray_basic extends BaseTestCase {
|
||||
.arrayIsNotEmpty("phoneNumbers")
|
||||
.arrayContains("statuses", EArrayBean.Status.ONE)
|
||||
.arrayContains("status2", EArrayBean.Status.TWO)
|
||||
.arrayContains("vcEnums", VarcharEnum.TWO)
|
||||
.arrayContains("intEnums", IntEnum.ZERO)
|
||||
.query();
|
||||
|
||||
List<EArrayBean> list = query.findList();
|
||||
|
||||
List<EArrayBean.Status> statuses = list.get(0).getStatuses();
|
||||
Set<EArrayBean.Status> status2 = list.get(0).getStatus2();
|
||||
List<IntEnum> intEnums = list.get(0).getIntEnums();
|
||||
List<VarcharEnum> varcharEnums = list.get(0).getVcEnums();
|
||||
|
||||
assertThat(statuses).contains(EArrayBean.Status.ONE, EArrayBean.Status.THREE);
|
||||
assertThat(status2).contains(EArrayBean.Status.ONE, EArrayBean.Status.TWO);
|
||||
|
||||
assertThat(intEnums).containsExactly(IntEnum.ZERO, IntEnum.TWO);
|
||||
assertThat(varcharEnums).containsExactly(VarcharEnum.ONE, VarcharEnum.TWO);
|
||||
|
||||
assertThat(query.getGeneratedSql()).contains(" t0.other_ids @> array[?,?]::bigint[] ");
|
||||
assertThat(query.getGeneratedSql()).contains(" t0.uids @> array[?] ");
|
||||
assertThat(query.getGeneratedSql()).contains(" t0.phone_numbers @> array[?] ");
|
||||
@@ -87,6 +101,15 @@ public class TestDbArray_basic extends BaseTestCase {
|
||||
.query();
|
||||
query.findList();
|
||||
|
||||
|
||||
final SqlRow row = Ebean.createSqlQuery("select * from earray_bean").findOne();
|
||||
|
||||
final String[] vcs = (String[]) ((java.sql.Array) row.get("vc_enums")).getArray();
|
||||
assertThat(vcs).containsExactly("xXxONE", "xXxTWO");
|
||||
|
||||
final Integer[] ints = (Integer[]) ((java.sql.Array) row.get("int_enums")).getArray();
|
||||
assertThat(ints).containsExactly(100, 102);
|
||||
|
||||
assertThat(query.getGeneratedSql()).contains(" coalesce(cardinality(t0.other_ids),0) = 0");
|
||||
assertThat(query.getGeneratedSql()).contains(" not (t0.uids @> array[?])");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.tests.model.array;
|
||||
|
||||
import io.ebean.annotation.DbEnumType;
|
||||
import io.ebean.annotation.DbEnumValue;
|
||||
|
||||
public enum VarcharEnum {
|
||||
ZERO, ONE, TWO;
|
||||
|
||||
@DbEnumValue(storage = DbEnumType.VARCHAR)
|
||||
public String dbValue() {
|
||||
return "xXx" + name();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.tests.model.draftable;
|
||||
|
||||
import io.ebean.Finder;
|
||||
import io.ebean.annotation.Draft;
|
||||
import io.ebean.annotation.DraftOnly;
|
||||
import io.ebean.annotation.Draftable;
|
||||
|
||||
@@ -25,6 +26,9 @@ public class Document extends BaseDomain {
|
||||
|
||||
String body;
|
||||
|
||||
@Draft
|
||||
boolean draft;
|
||||
|
||||
@DraftOnly
|
||||
Timestamp whenPublish;
|
||||
|
||||
@@ -54,6 +58,14 @@ public class Document extends BaseDomain {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public boolean isDraft() {
|
||||
return draft;
|
||||
}
|
||||
|
||||
public void setDraft(boolean draft) {
|
||||
this.draft = draft;
|
||||
}
|
||||
|
||||
public Organisation getOrganisation() {
|
||||
return organisation;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.tests.model.onetoone;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class OtoAone {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private String description;
|
||||
|
||||
public OtoAone(String id, String description){
|
||||
this.id = id;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.tests.model.onetoone;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
@Entity
|
||||
public class OtoAtwo {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private String description;
|
||||
|
||||
@OneToOne(orphanRemoval=true, cascade = CascadeType.ALL)
|
||||
private OtoAone aone;
|
||||
|
||||
public OtoAtwo(String id, String description){
|
||||
this.id = id;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public OtoAone getAone() {
|
||||
return aone;
|
||||
}
|
||||
|
||||
public void setAone(OtoAone aone) {
|
||||
this.aone = aone;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.tests.model.onetoone;
|
||||
|
||||
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 TestOneToOneOrphanStringId extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void test_updateInsert() {
|
||||
|
||||
OtoAtwo b = new OtoAtwo("b1", "b test");
|
||||
Ebean.save(b);
|
||||
|
||||
OtoAone a = new OtoAone("a1", "a test");
|
||||
b.setAone(a);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.save(b);
|
||||
|
||||
List<String> update = LoggedSqlCollector.current();
|
||||
assertThat(update).hasSize(2);
|
||||
assertThat(update.get(0)).contains("insert into oto_aone");
|
||||
assertThat(update.get(1)).contains("update oto_atwo set aone_id=? where id=?");
|
||||
|
||||
Ebean.delete(b);
|
||||
|
||||
List<String> deletes = LoggedSqlCollector.stop();
|
||||
assertThat(deletes).hasSize(2);
|
||||
assertThat(deletes.get(0)).contains("delete from oto_atwo");
|
||||
assertThat(deletes.get(1)).contains("delete from oto_aone");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_cascade() {
|
||||
|
||||
OtoAone a = new OtoAone("a2", "a test");
|
||||
OtoAtwo b = new OtoAtwo("b2", "b test");
|
||||
|
||||
b.setAone(a);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.save(b);
|
||||
|
||||
List<String> inserts = LoggedSqlCollector.current();
|
||||
assertThat(inserts).hasSize(2);
|
||||
assertThat(inserts.get(0)).contains("insert into oto_aone");
|
||||
assertThat(inserts.get(1)).contains("insert into oto_atwo");
|
||||
|
||||
Ebean.delete(b);
|
||||
|
||||
List<String> deletes = LoggedSqlCollector.stop();
|
||||
assertThat(deletes).hasSize(2);
|
||||
assertThat(deletes.get(0)).contains("delete from oto_atwo");
|
||||
assertThat(deletes.get(1)).contains("delete from oto_aone");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.tests.model.orphanremoval;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Version;
|
||||
|
||||
@Entity
|
||||
public class OrpDetail {
|
||||
|
||||
@Id
|
||||
String id;
|
||||
|
||||
String detail;
|
||||
|
||||
@ManyToOne
|
||||
OrpMaster master;
|
||||
|
||||
@Version
|
||||
long version;
|
||||
|
||||
public OrpDetail(String id, String detail) {
|
||||
this.id = id;
|
||||
this.detail = detail;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public OrpMaster getMaster() {
|
||||
return master;
|
||||
}
|
||||
|
||||
public void setMaster(OrpMaster master) {
|
||||
this.master = master;
|
||||
}
|
||||
|
||||
public String getDetail() {
|
||||
return detail;
|
||||
}
|
||||
|
||||
public void setDetail(String detail) {
|
||||
this.detail = detail;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(long version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.tests.model.orphanremoval;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Version;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
public class OrpMaster {
|
||||
|
||||
@Id
|
||||
String id;
|
||||
|
||||
String name;
|
||||
|
||||
@OneToMany(orphanRemoval = true, cascade = CascadeType.ALL)
|
||||
List<OrpDetail> details;
|
||||
|
||||
@Version
|
||||
long version;
|
||||
|
||||
public OrpMaster(String id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<OrpDetail> getDetails() {
|
||||
return details;
|
||||
}
|
||||
|
||||
public void setDetails(List<OrpDetail> details) {
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(long version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.tests.model.orphanremoval;
|
||||
|
||||
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 TestOrphanRemoveO2M extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void clear_expect_deletes() {
|
||||
|
||||
OrpMaster master = new OrpMaster("m","master");
|
||||
master.getDetails().add(new OrpDetail("d1", "d1"));
|
||||
master.getDetails().add(new OrpDetail("d2", "d2"));
|
||||
|
||||
Ebean.save(master);
|
||||
|
||||
master.getDetails().clear();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
Ebean.save(master);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
|
||||
assertThat(Ebean.find(OrpDetail.class, "d1")).isNull();
|
||||
assertThat(Ebean.find(OrpDetail.class, "d2")).isNull();
|
||||
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("delete from orp_detail where id=?");
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ public class TestTransactionTryResources extends BaseTestCase {
|
||||
|
||||
Document document = Document.find.asDraft(doc.getId());
|
||||
assertThat(document).isNotNull();
|
||||
assertThat(document.isDraft()).isTrue();
|
||||
|
||||
// cleanup
|
||||
Ebean.delete(document);
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.tests.model.basic.EBasic.Status;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -70,6 +71,28 @@ public class TestStatelessUpdate extends TransactionalTestCase {
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = EntityNotFoundException.class)
|
||||
public void update_NoRowsUpdated_expect_EntityNotFoundException() {
|
||||
|
||||
EBasic basic = new EBasic();
|
||||
basic.setId(999999999);
|
||||
basic.setName("something");
|
||||
basic.setStatus(Status.ACTIVE);
|
||||
|
||||
Ebean.update(basic);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete_NoRowsDeleted_expect_false() {
|
||||
|
||||
EBasic basic = new EBasic();
|
||||
basic.setId(999999999);
|
||||
basic.setName("something");
|
||||
basic.setStatus(Status.ACTIVE);
|
||||
|
||||
assertThat(Ebean.delete(basic)).isFalse();
|
||||
}
|
||||
|
||||
/**
|
||||
* I am expecting that Ebean detects there aren't any changes and don't execute any query.
|
||||
* Currently a {@link javax.persistence.PersistenceException} with message 'Invalid value "null" for parameter "SQL"' is thrown.
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
|
||||
<changeSet type="apply">
|
||||
<dropTable name="some_table"/>
|
||||
</changeSet>
|
||||
</migration>
|
||||
Reference in New Issue
Block a user