[15x] Remove Draftable support

This commit is contained in:
Rob Bygrave
2023-10-10 23:45:08 +13:00
parent 8f89b19128
commit c0ebfbc4e0
82 changed files with 165 additions and 1707 deletions
@@ -1326,104 +1326,6 @@ public interface Database {
*/
DocumentStore docStore();
/**
* Publish a single bean given its type and id returning the resulting live bean.
* <p>
* The values are published from the draft to the live bean.
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
* @param id the id of the entity bean
* @param transaction the transaction the publish process should use (can be null)
*/
@Nullable
<T> T publish(Class<T> beanType, Object id, Transaction transaction);
/**
* Publish a single bean given its type and id returning the resulting live bean.
* This will use the current transaction or create one if required.
* <p>
* The values are published from the draft to the live bean.
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
* @param id the id of the entity bean
*/
@Nullable
<T> T publish(Class<T> beanType, Object id);
/**
* Publish the beans that match the query returning the resulting published beans.
* <p>
* The values are published from the draft beans to the live beans.
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to publish
* @param transaction the transaction the publish process should use (can be null)
*/
<T> List<T> publish(Query<T> query, Transaction transaction);
/**
* Publish the beans that match the query returning the resulting published beans.
* This will use the current transaction or create one if required.
* <p>
* The values are published from the draft beans to the live beans.
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to publish
*/
<T> List<T> publish(Query<T> query);
/**
* Restore the draft bean back to the live state.
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
* @param id the id of the entity bean to restore
* @param transaction the transaction the restore process should use (can be null)
*/
@Nullable
<T> T draftRestore(Class<T> beanType, Object id, Transaction transaction);
/**
* Restore the draft bean back to the live state.
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
* @param id the id of the entity bean to restore
*/
@Nullable
<T> T draftRestore(Class<T> beanType, Object id);
/**
* Restore the draft beans matching the query back to the live state.
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to restore
* @param transaction the transaction the restore process should use (can be null)
*/
<T> List<T> draftRestore(Query<T> query, Transaction transaction);
/**
* Restore the draft beans matching the query back to the live state.
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to restore
*/
<T> List<T> draftRestore(Query<T> query);
/**
* Returns the set of properties/paths that are unknown (do not map to known properties or paths).
* <p>
@@ -106,11 +106,6 @@ public interface ExpressionList<T> {
*/
Query<T> asOf(Timestamp asOf);
/**
* Execute the query against the draft set of tables.
*/
Query<T> asDraft();
/**
* Convert the query to a DTO bean query.
* <p>
@@ -250,11 +250,6 @@ public interface Query<T> extends CancelableQuery {
*/
Query<T> asOf(Timestamp asOf);
/**
* Execute the query against the draft set of tables.
*/
Query<T> asDraft();
/**
* Convert the query to a DTO bean query.
* <p>
@@ -168,11 +168,6 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
*/
SOFT_DELETED(false),
/**
* Query runs against draft tables.
*/
DRAFT(false),
/**
* Query runs against current data (normal).
*/
@@ -375,11 +370,6 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
*/
boolean isAsOfQuery();
/**
* Return true if this is a 'As Draft' query.
*/
boolean isAsDraft();
/**
* Return true if this query includes soft deleted rows.
*/
@@ -178,12 +178,11 @@ final class DefaultBeanLoader {
desc.contextPut(pc, id, bean);
ebi.setPersistenceContext(pc);
}
boolean draft = desc.isDraftInstance(bean);
if (embeddedOwnerIndex == -1) {
if (desc.lazyLoadMany(ebi)) {
return;
}
if (!draft && Mode.LAZYLOAD_BEAN == mode && desc.isBeanCaching()) {
if (Mode.LAZYLOAD_BEAN == mode && desc.isBeanCaching()) {
// lazy loading and the bean cache is active
if (desc.cacheBeanLoad(bean, ebi, id, pc)) {
return;
@@ -192,9 +191,7 @@ final class DefaultBeanLoader {
}
SpiQuery<?> query = server.createQuery(desc.type());
query.setLazyLoadProperty(ebi.lazyLoadProperty());
if (draft) {
query.asDraft();
} else if (mode == SpiQuery.Mode.LAZYLOAD_BEAN && desc.isSoftDelete()) {
if (mode == SpiQuery.Mode.LAZYLOAD_BEAN && desc.isSoftDelete()) {
query.setIncludeSoftDeletes();
}
if (embeddedOwnerIndex > -1) {
@@ -1636,54 +1636,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}, transaction);
}
@Override
public <T> List<T> publish(Query<T> query, @Nullable Transaction transaction) {
return executeInTrans((txn) -> persister.publish(query, txn), transaction);
}
@Nullable
@Override
public <T> T publish(Class<T> beanType, Object id) {
return publish(beanType, id, null);
}
@Override
public <T> List<T> publish(Query<T> query) {
return publish(query, null);
}
@Nullable
@Override
public <T> T publish(Class<T> beanType, Object id, @Nullable Transaction transaction) {
Query<T> query = find(beanType).setId(id);
List<T> liveBeans = publish(query, transaction);
return (liveBeans.size() == 1) ? liveBeans.get(0) : null;
}
@Override
public <T> List<T> draftRestore(Query<T> query, @Nullable Transaction transaction) {
return executeInTrans((txn) -> persister.draftRestore(query, txn), transaction);
}
@Nullable
@Override
public <T> T draftRestore(Class<T> beanType, Object id, @Nullable Transaction transaction) {
Query<T> query = find(beanType).setId(id);
List<T> beans = draftRestore(query, transaction);
return (beans.size() == 1) ? beans.get(0) : null;
}
@Nullable
@Override
public <T> T draftRestore(Class<T> beanType, Object id) {
return draftRestore(beanType, id, null);
}
@Override
public <T> List<T> draftRestore(Query<T> query) {
return draftRestore(query, null);
}
private EntityBean checkEntityBean(Object bean) {
return (EntityBean) Objects.requireNonNull(bean);
}
@@ -120,11 +120,10 @@ public final class InternalConfiguration {
this.dtoBeanManager = new DtoBeanManager(typeManager);
this.beanDescriptorManager = new BeanDescriptorManager(this);
Map<String, String> asOfTableMapping = beanDescriptorManager.deploy();
Map<String, String> draftTableMap = beanDescriptorManager.draftTableMap();
beanDescriptorManager.scheduleBackgroundTrim();
this.dataTimeZone = initDataTimeZone();
this.binder = getBinder(typeManager, databasePlatform, dataTimeZone);
this.cQueryEngine = new CQueryEngine(config, databasePlatform, binder, asOfTableMapping, draftTableMap);
this.cQueryEngine = new CQueryEngine(config, databasePlatform, binder, asOfTableMapping);
}
public boolean isJacksonCorePresent() {
@@ -44,7 +44,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
*/
private final Object parentBean;
private final boolean dirty;
private final boolean publish;
private int flags;
private boolean saveRecurse;
private DocStoreMode docStoreMode;
@@ -153,10 +152,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
}
this.concurrencyMode = beanDescriptor.concurrencyMode(intercept);
this.publish = Flags.isPublish(flags);
if (isMarkDraftDirty(publish)) {
beanDescriptor.setDraftDirty(entityBean, true);
}
this.dirty = intercept.isDirty();
}
@@ -201,13 +196,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
return Flags.isRecurse(flags);
}
/**
* Return true if the draftDirty property should be set to true for this request.
*/
private boolean isMarkDraftDirty(boolean publish) {
return !publish && type != Type.DELETE && beanDescriptor.isDraftable();
}
/**
* Set the transaction from prior persist request.
* Only used when hard deleting draft & associated live beans.
@@ -417,7 +405,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
* Set the cache notify status.
*/
private void setNotifyCache() {
this.notifyCache = beanDescriptor.isCacheNotify(type, publish);
this.notifyCache = beanDescriptor.isCacheNotify(type);
}
/**
@@ -642,28 +630,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
return beanDescriptor.createRef(beanId(), null);
}
/**
* Return true if the bean type is a Draftable.
*/
public boolean isDraftable() {
return beanDescriptor.isDraftable();
}
/**
* Return true if this request is a hard delete of a draftable bean.
* If this is true Ebean is expected to auto-publish and delete the associated live bean.
*/
public boolean isHardDeleteDraft() {
if (type == Type.DELETE && beanDescriptor.isDraftable() && !beanDescriptor.isDraftableElement()) {
// deleting a top level draftable bean
if (beanDescriptor.isLiveInstance(entityBean)) {
throw new PersistenceException("Explicit Delete is not allowed on a 'live' bean - only draft beans");
}
return true;
}
return false;
}
/**
* Return true if this was a hard/permanent delete request (and should cascade as such).
*/
@@ -671,16 +637,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
return (type == Type.DELETE && beanDescriptor.isSoftDelete());
}
/**
* Checks for @Draftable entity beans with @Draft property that the bean is a 'draft'.
* Save or Update is not allowed to execute using 'live' beans - must use publish().
*/
public void checkDraft() {
if (beanDescriptor.isDraftable() && beanDescriptor.isLiveInstance(entityBean)) {
throw new PersistenceException("Save or update is not allowed on a 'live' bean - only draft beans");
}
}
/**
* Return the parent bean for cascading save with unidirectional relationship.
*/
@@ -928,20 +884,19 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
private void logSummaryMessage() {
String draft = (beanDescriptor.isDraftable() && !publish) ? " draft[true]" : "";
String name = beanDescriptor.name();
switch (type) {
case INSERT:
transaction.logSummary("Inserted [{0}] [{1}]{2}", name, (idValue == null ? "" : idValue), draft);
transaction.logSummary("Inserted [{0}] [{1}]", name, (idValue == null ? "" : idValue));
break;
case UPDATE:
transaction.logSummary("Updated [{0}] [{1}]{2}", name, idValue , draft);
transaction.logSummary("Updated [{0}] [{1}]", name, idValue);
break;
case DELETE:
transaction.logSummary("Deleted [{0}] [{1}]{2}", name, idValue , draft);
transaction.logSummary("Deleted [{0}] [{1}]", name, idValue);
break;
case DELETE_SOFT:
transaction.logSummary("SoftDelete [{0}] [{1}]{2}", name, idValue , draft);
transaction.logSummary("SoftDelete [{0}] [{1}]", name, idValue);
break;
default:
break;
@@ -979,9 +934,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
private void postInsert() {
// mark all properties as loaded after an insert to support immediate update
beanDescriptor.setAllLoaded(entityBean);
if (!publish) {
beanDescriptor.setDraft(entityBean);
}
if (transaction.isAutoPersistUpdates() && idValue != null) {
// with getGeneratedKeys off we will not have a idValue
beanDescriptor.contextPut(transaction.persistenceContext(), idValue, entityBean);
@@ -1129,13 +1081,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
return flags;
}
/**
* Return true if this request is a 'publish' action.
*/
public boolean isPublish() {
return publish;
}
/**
* Return the key for an update persist request.
*/
@@ -1152,17 +1097,14 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
key.append('v');
}
}
if (publish) {
key.append('p');
}
return key.toString();
}
/**
* Return the table to update depending if the request is a 'publish' one or normal.
* Return the table to update.
*/
public String updateTable() {
return publish ? beanDescriptor.baseTable() : beanDescriptor.draftTable();
return beanDescriptor.baseTable();
}
/**
@@ -1374,7 +1316,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
* Return the SQL used to fetch the last inserted id value.
*/
public String selectLastInsertedId() {
return beanDescriptor.selectLastInsertedId(publish);
return beanDescriptor.selectLastInsertedId();
}
/**
@@ -83,16 +83,6 @@ public interface Persister {
*/
int executeCallable(CallableSql callable, Transaction t);
/**
* Publish the draft beans matching the given query.
*/
<T> List<T> publish(Query<T> query, Transaction transaction);
/**
* Restore the draft beans back to the matching live beans.
*/
<T> List<T> draftRestore(Query<T> query, Transaction transaction);
/**
* Visit the metrics.
*/
@@ -42,7 +42,6 @@ import io.ebeaninternal.server.query.*;
import io.ebeaninternal.server.querydefn.DefaultOrmQuery;
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
import io.ebeaninternal.server.rawsql.SpiRawSql;
import io.ebeaninternal.util.SortByClause;
import io.ebeaninternal.util.SortByClauseParser;
import io.ebeanservice.docstore.api.DocStoreBeanAdapter;
@@ -103,7 +102,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
* getGeneratedKeys is not supported.
*/
private final String selectLastInsertedId;
private final String selectLastInsertedIdDraft;
private final boolean autoTunable;
private final ConcurrencyMode concurrencyMode;
private final IndexDefinition[] indexDefinitions;
@@ -115,17 +113,12 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
private final TableJoin primaryKeyJoin;
private final BeanProperty softDeleteProperty;
private final boolean softDelete;
private final String draftTable;
private final PartitionMeta partitionMeta;
private final TablespaceMeta tablespaceMeta;
private final String storageEngine;
private final String dbComment;
private final boolean draftable;
private final boolean draftableElement;
private final BeanProperty unmappedJson;
private final BeanProperty tenant;
private final BeanProperty draft;
private final BeanProperty draftDirty;
private final LinkedHashMap<String, BeanProperty> propMap;
/**
* Map of DB column to property path (for nativeSql mapping).
@@ -218,7 +211,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
private final String baseTableAlias;
private final boolean cacheSharableBeans;
private final String docStoreQueueId;
private final BeanDescriptorDraftHelp<T> draftHelp;
private final BeanDescriptorCacheHelp<T> cacheHelp;
private final BeanDescriptorJsonHelp<T> jsonHelp;
private DocStoreBeanAdapter<T> docStoreAdapter;
@@ -253,13 +245,9 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
this.idGeneratedValue = deploy.isIdGeneratedValue();
this.idGenerator = deploy.getIdGenerator();
this.selectLastInsertedId = deploy.getSelectLastInsertedId();
this.selectLastInsertedIdDraft = deploy.getSelectLastInsertedIdDraft();
this.concurrencyMode = deploy.getConcurrencyMode();
this.indexDefinitions = deploy.getIndexDefinitions();
this.draftable = deploy.isDraftable();
this.draftableElement = deploy.isDraftableElement();
this.historySupport = deploy.isHistorySupport();
this.draftTable = deploy.getDraftTable();
this.baseTable = InternString.intern(deploy.getBaseTable());
this.baseTableAsOf = deploy.getBaseTableAsOf();
this.primaryKeyJoin = deploy.getPrimaryKeyJoin();
@@ -281,8 +269,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
this.versionProperty = listHelper.getVersionProperty();
this.unmappedJson = listHelper.getUnmappedJson();
this.tenant = listHelper.getTenant();
this.draft = listHelper.getDraft();
this.draftDirty = listHelper.getDraftDirty();
this.propMap = listHelper.getPropertyMap();
this.propertiesTransient = listHelper.getTransients();
this.propertiesNonTransient = listHelper.getNonTransients();
@@ -311,7 +297,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
this.cacheSharableBeans = noRelationships && deploy.getCacheOptions().isReadOnly();
this.cacheHelp = new BeanDescriptorCacheHelp<>(this, owner.cacheManager(), deploy.getCacheOptions(), cacheSharableBeans, propertiesOneImported);
this.jsonHelp = initJsonHelp();
this.draftHelp = new BeanDescriptorDraftHelp<>(this);
this.docStoreAdapter = owner.createDocStoreBeanAdapter(this, deploy);
this.docStoreQueueId = docStoreAdapter.queueId();
// Check if there are no cascade save associated beans ( subject to change
@@ -473,9 +458,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
* as they are used to get the imported and exported properties.
*/
void initialiseId(BeanDescriptorInitContext initContext) {
if (draftable) {
initContext.addDraft(baseTable, draftTable);
}
if (historySupport) {
// add mapping (used to swap out baseTable for asOf queries)
initContext.addHistory(baseTable, baseTableAsOf);
@@ -494,10 +476,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
* Initialise the exported and imported parts for associated properties.
*/
public void initialiseOther(BeanDescriptorInitContext initContext) {
for (BeanPropertyAssocMany<?> many : propertiesManyToMany) {
// register associated draft table for M2M intersection
many.registerDraftIntersectionTable(initContext);
}
if (historySupport) {
// history support on this bean so check all associated intersection tables
// and if they are not excluded register the associated 'with history' table
@@ -1044,24 +1022,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
docStoreAdapter.deleteById(idValue, txn);
}
public T publish(T draftBean, T liveBean) {
return draftHelp.publish(draftBean, liveBean);
}
/**
* Reset properties on the draft bean based on @DraftDirty and @DraftReset.
*/
public boolean draftReset(T draftBean) {
return draftHelp.draftReset(draftBean);
}
/**
* Return the draft dirty boolean property or null if there is not one assigned to this bean type.
*/
BeanProperty draftDirty() {
return draftDirty;
}
/**
* Prepare the query for multi-tenancy check for document store only use.
*/
@@ -1114,11 +1074,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
/**
* Return true if the persist request needs to notify the cache.
*/
public boolean isCacheNotify(PersistRequest.Type type, boolean publish) {
if (draftable && !publish) {
// no caching when editing draft beans
return false;
}
public boolean isCacheNotify(PersistRequest.Type type) {
return cacheHelp.isCacheNotify(type);
}
@@ -2622,8 +2578,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
@Override
public String baseTable(SpiQuery.TemporalMode mode) {
switch (mode) {
case DRAFT:
return draftTable;
case VERSIONS:
return baseTableVersionsBetween;
case AS_OF:
@@ -2633,13 +2587,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
}
}
/**
* Return the associated draft table.
*/
public String draftTable() {
return draftTable;
}
@Override
public boolean isSoftDelete() {
return softDelete;
@@ -2671,20 +2618,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
}
}
/**
* Return true if this entity type is draftable.
*/
public boolean isDraftable() {
return draftable;
}
/**
* Return true if this entity type is a draftable element (child).
*/
public boolean isDraftableElement() {
return draftableElement;
}
@Override
public Map<String, String> pathMap(String prefix) {
return pathMaps.computeIfAbsent(prefix, s -> {
@@ -2750,28 +2683,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
}
}
/**
* Set the draft to true for this entity bean instance.
* This bean is being loaded via asDraft() query.
*/
@Override
public void setDraft(EntityBean entityBean) {
if (draft != null) {
draft.setValue(entityBean, true);
}
}
/**
* Return true if the bean is considered a 'draft' instance (not 'live').
*/
public boolean isDraftInstance(EntityBean entityBean) {
if (draft != null) {
return Boolean.TRUE == draft.getValue(entityBean);
}
// no draft property - so return false
return false;
}
@Override
public boolean isToManyDirty(EntityBean bean) {
final EntityBeanIntercept ebi = bean._ebean_getIntercept();
@@ -2786,39 +2697,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
return false;
}
/**
* Return true if the bean is draftable and considered a 'live' instance.
*/
public boolean isLiveInstance(EntityBean entityBean) {
if (draft != null) {
return Boolean.FALSE == draft.getValue(entityBean);
}
// no draft property - so return false
return false;
}
/**
* If there is a @DraftDirty property set it's value on the bean.
*/
public void setDraftDirty(EntityBean entityBean, boolean value) {
if (draftDirty != null) {
// check to see if the dirty property has already
// been set and if so do not set the value
if (!entityBean._ebean_getIntercept().isChangedProperty(draftDirty.propertyIndex())) {
draftDirty.setValueIntercept(entityBean, value);
}
}
}
/**
* Optimise the draft query fetching any draftable element relationships.
*/
public void draftQueryOptimise(Query<T> query) {
// use per query PersistenceContext to ensure fresh beans loaded
query.setPersistenceContextScope(PersistenceContextScope.QUERY);
draftHelp.draftQueryOptimise(query);
}
/**
* Return true if this entity bean has history support.
*/
@@ -2864,8 +2742,8 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
* This is only used with Identity columns and getGeneratedKeys is not
* supported.
*/
public String selectLastInsertedId(boolean publish) {
return publish ? selectLastInsertedId : selectLastInsertedIdDraft;
public String selectLastInsertedId() {
return selectLastInsertedId;
}
/**
@@ -1,99 +0,0 @@
package io.ebeaninternal.server.deploy;
import io.ebean.Query;
import io.ebean.bean.EntityBean;
import java.util.ArrayList;
import java.util.List;
/**
* Helper for BeanDescriptor that manages draft entity beans.
*
* @param <T> The entity bean type
*/
final class BeanDescriptorDraftHelp<T> {
private final BeanDescriptor<T> desc;
private final BeanProperty draftDirty;
private final BeanProperty[] resetProperties;
BeanDescriptorDraftHelp(BeanDescriptor<T> desc) {
this.desc = desc;
this.draftDirty = desc.draftDirty();
this.resetProperties = resetProperties();
}
/**
* Return the properties that are reset on draft beans after publish.
*/
private BeanProperty[] resetProperties() {
List<BeanProperty> list = new ArrayList<>();
for (BeanProperty prop : desc.propertiesNonMany()) {
if (prop.isDraftReset()) {
list.add(prop);
}
}
return list.toArray(new BeanProperty[0]);
}
/**
* Set the value of all the 'reset properties' to null on the draft bean.
*/
boolean draftReset(T draftBean) {
EntityBean draftEntityBean = (EntityBean) draftBean;
if (draftDirty != null) {
// set @DraftDirty property to false
draftDirty.setValueIntercept(draftEntityBean, false);
}
// set to null on all @DraftReset properties
for (BeanProperty resetProperty : resetProperties) {
resetProperty.setValueIntercept(draftEntityBean, null);
}
// return true if the bean is dirty (and should be persisted)
return draftEntityBean._ebean_getIntercept().isDirty();
}
/**
* Transfer the values from the draftBean to the liveBean.
* <p>
* This will recursive transfer values to all @DraftableElement properties.
* </p>
*/
@SuppressWarnings("unchecked")
public T publish(T draftBean, T liveBean) {
if (liveBean == null) {
liveBean = (T) desc.createEntityBean();
}
EntityBean draft = (EntityBean) draftBean;
EntityBean live = (EntityBean) liveBean;
BeanProperty idProperty = desc.idProperty();
if (idProperty != null) {
idProperty.publish(draft, live);
}
for (BeanProperty prop : desc.propertiesNonMany()) {
prop.publish(draft, live);
}
for (BeanPropertyAssocMany<?> many : desc.propertiesMany()) {
if (many.targetDescriptor().isDraftable()) {
many.publishMany(draft, live);
}
}
return liveBean;
}
/**
* Fetch draftable element relationships.
*/
void draftQueryOptimise(Query<T> query) {
for (BeanPropertyAssocOne<?> anOne : desc.propertiesOne()) {
if (anOne.targetDescriptor().isDraftableElement()) {
query.fetch(anOne.name());
}
}
for (BeanPropertyAssocMany<?> aMany : desc.propertiesMany()) {
if (aMany.targetDescriptor().isDraftableElement()) {
query.fetch(aMany.name());
}
}
}
}
@@ -5,20 +5,14 @@ import java.util.Map;
class BeanDescriptorInitContext {
private final Map<String, String> withHistoryTables;
private final Map<String, String> draftTables;
private final String asOfViewSuffix;
private String embeddedPrefix;
BeanDescriptorInitContext(Map<String, String> withHistoryTables, Map<String, String> draftTables, String asOfViewSuffix) {
BeanDescriptorInitContext(Map<String, String> withHistoryTables, String asOfViewSuffix) {
this.withHistoryTables = withHistoryTables;
this.draftTables = draftTables;
this.asOfViewSuffix = asOfViewSuffix;
}
void addDraft(String baseTable, String draftTable) {
draftTables.put(baseTable, draftTable);
}
void addHistory(String baseTable, String baseTableAsOf) {
withHistoryTables.put(baseTable, baseTableAsOf);
}
@@ -27,10 +21,6 @@ class BeanDescriptorInitContext {
withHistoryTables.put(intersectionTableName, intersectionTableName + asOfViewSuffix);
}
void addDraftIntersection(String intersectionPublishTable, String intersectionDraftTable) {
draftTables.put(intersectionPublishTable, intersectionDraftTable);
}
public void setEmbeddedPrefix(String embeddedPrefix) {
this.embeddedPrefix = embeddedPrefix;
}
@@ -106,10 +106,6 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
* Map of base tables to 'with history views' used to support 'as of' queries.
*/
private final Map<String, String> asOfTableMap = new HashMap<>();
/**
* Map of base tables to 'draft' tables.
*/
private final Map<String, String> draftTableMap = new HashMap<>();
// temporary collections used during startup and then cleared
private Map<Class<?>, DeployBeanInfo<?>> deployInfoMap = new HashMap<>();
@@ -269,13 +265,6 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
return idBinderFactory.createIdBinder(idProperty);
}
/**
* Return the map of base tables to draft tables.
*/
public Map<String, String> draftTableMap() {
return draftTableMap;
}
/**
* Deploy returning the asOfTableMap (which is required by the SQL builders).
*/
@@ -417,7 +406,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
// now that all the BeanDescriptors are in their map
// we can initialise them which sorts out circular
// dependencies for OneToMany and ManyToOne etc
BeanDescriptorInitContext initContext = new BeanDescriptorInitContext(asOfTableMap, draftTableMap, asOfViewSuffix);
BeanDescriptorInitContext initContext = new BeanDescriptorInitContext(asOfTableMap, asOfViewSuffix);
// PASS 1:
// initialise the ID properties of all the beans
@@ -959,13 +948,6 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
// skip mapping check
return;
}
DeployBeanDescriptor<?> targetDesc = targetDescriptor(prop);
if (targetDesc.isDraftableElement()) {
// automatically turning on orphan removal and CascadeType.ALL
prop.setModifyListenMode(BeanCollection.ModifyListenMode.REMOVALS);
prop.getCascadeInfo().setSaveDelete(true, true);
}
if (prop.hasOrderColumn()) {
makeOrderColumn(prop);
}
@@ -991,6 +973,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
String mappedBy = prop.getMappedBy();
// get the mappedBy property
DeployBeanDescriptor<?> targetDesc = targetDescriptor(prop);
DeployBeanPropertyAssocOne<?> mappedAssocOne = mappedManyToOne(prop, targetDesc, mappedBy);
DeployTableJoin tableJoin = prop.getTableJoin();
if (!tableJoin.hasJoinColumns()) {
@@ -1032,9 +1015,6 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
// get the bean descriptor that holds the mappedBy property
String mappedBy = prop.getMappedBy();
if (mappedBy == null) {
if (targetDescriptor(prop).isDraftable()) {
prop.setIntersectionDraftTable();
}
return;
}
@@ -1059,10 +1039,6 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
DeployTableJoin inverseJoin = new DeployTableJoin();
mappedIntJoin.copyTo(inverseJoin, false, intTableName);
prop.setInverseJoin(inverseJoin);
if (targetDesc.isDraftable()) {
prop.setIntersectionDraftTable();
}
}
private DeployBeanPropertyAssocMany<?> mappedManyToMany(DeployBeanPropertyAssocMany<?> prop, String mappedBy, DeployBeanDescriptor<?> targetDesc) {
@@ -1179,8 +1155,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
if (identityMode.isIdentity()) {
// used when getGeneratedKeys is not supported (SQL Server 2000, SAP Hana)
String selectLastInsertedId = dbIdentity.getSelectLastInsertedId(desc.getBaseTable());
String selectLastInsertedIdDraft = (!desc.isDraftable()) ? selectLastInsertedId : dbIdentity.getSelectLastInsertedId(desc.getDraftTable());
desc.setSelectLastInsertedId(selectLastInsertedId, selectLastInsertedIdDraft);
desc.setSelectLastInsertedId(selectLastInsertedId);
return;
}
@@ -171,10 +171,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
final boolean jsonDeserialize;
private final boolean unmappedJson;
private final boolean tenantId;
private final boolean draft;
private final boolean draftOnly;
private final boolean draftDirty;
private final boolean draftReset;
private final boolean softDelete;
private final String softDeleteDbSet;
private final String softDeleteDbPredicate;
@@ -201,10 +197,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
this.excludedFromHistory = deploy.isExcludedFromHistory();
this.unmappedJson = deploy.isUnmappedJson();
this.tenantId = deploy.isTenantId();
this.draft = deploy.isDraft();
this.draftDirty = deploy.isDraftDirty();
this.draftOnly = deploy.isDraftOnly();
this.draftReset = deploy.isDraftReset();
this.secondaryTable = deploy.isSecondaryTable();
if (secondaryTable) {
this.secondaryTableJoin = new TableJoin(deploy.getSecondaryTableJoin());
@@ -296,10 +288,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
this.aggregation = null;
this.excludedFromHistory = source.excludedFromHistory;
this.tenantId = source.tenantId;
this.draft = source.draft;
this.draftDirty = source.draftDirty;
this.draftOnly = source.draftOnly;
this.draftReset = source.draftReset;
this.softDelete = source.softDelete;
this.softDeleteDbSet = source.softDeleteDbSet;
this.softDeleteDbPredicate = source.softDeleteDbPredicate;
@@ -483,7 +471,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
ctx.appendFormulaSelect(aggregation);
} else if (formula) {
ctx.appendFormulaSelect(sqlFormulaSelect);
} else if (!isTransient && !ignoreDraftOnlyProperty(ctx.isDraftQuery())) {
} else if (!isTransient) {
if (secondaryTableJoin != null) {
ctx.pushTableAlias(ctx.relativePrefix(secondaryTableJoinPrefix));
}
@@ -590,17 +578,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
return local;
}
/**
* Copy/set the property value from the draft bean to the live bean.
*/
public void publish(EntityBean draftBean, EntityBean liveBean) {
if (!version && !draftOnly) {
// set property value from draft to live
Object value = getValueIntercept(draftBean);
setValueIntercept(liveBean, value);
}
}
/**
* Return the DB literal expression to set the deleted state to true.
*/
@@ -1090,16 +1067,8 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
/**
* Return true if this property is loadable from a resultSet.
*/
public boolean isLoadProperty(boolean draftQuery) {
return !ignoreDraftOnlyProperty(draftQuery) && (!isTransient || formula);
}
/**
* Return true if this is a draftOnly property on a non-asDraft query and as such this
* property should not be included in a sql query.
*/
private boolean ignoreDraftOnlyProperty(boolean draftQuery) {
return draftOnly && !draftQuery;
public boolean isLoadProperty() {
return !isTransient || formula;
}
/**
@@ -1248,36 +1217,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
return tenantId;
}
/**
* Return true if this property only exists on the draft table.
*/
public boolean isDraftOnly() {
return draftOnly;
}
/**
* Return true if this property is a boolean flag on a draftable bean
* indicating if the instance is a draft or live bean.
*/
public boolean isDraft() {
return draft;
}
/**
* Return true if this property is a boolean flag only on the draft table
* indicating that when the draft is different from the published row.
*/
public boolean isDraftDirty() {
return draftDirty;
}
/**
* Return true if this property is reset/cleared on publish (on the draft bean).
*/
boolean isDraftReset() {
return draftReset;
}
/**
* Return true if this property is the soft delete property.
*/
@@ -41,8 +41,6 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
* Join for manyToMany intersection table.
*/
private final TableJoin intersectionJoin;
private final String intersectionPublishTable;
private final String intersectionDraftTable;
private final boolean orphanRemoval;
private IntersectionTable intersectionTable;
/**
@@ -102,13 +100,6 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
this.mapKey = deploy.getMapKey();
this.fetchOrderBy = deploy.getFetchOrderBy();
this.intersectionJoin = deploy.createIntersectionTableJoin();
if (intersectionJoin != null) {
this.intersectionPublishTable = intersectionJoin.getTable();
this.intersectionDraftTable = deploy.getIntersectionDraftTable();
} else {
this.intersectionPublishTable = null;
this.intersectionDraftTable = null;
}
this.inverseJoin = deploy.createInverseTableJoin();
this.modifyListenMode = deploy.getModifyListenMode();
this.jsonHelp = descriptor.isJacksonCorePresent() ? new BeanPropertyAssocManyJsonHelp(this) : null;
@@ -375,7 +366,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
}
private IntersectionTable initIntersectionTable() {
IntersectionBuilder row = new IntersectionBuilder(intersectionPublishTable, intersectionDraftTable);
IntersectionBuilder row = new IntersectionBuilder(intersectionJoin.getTable());
for (ExportedProperty exportedProperty : exportedProperties) {
row.addColumn(exportedProperty.getForeignDbColumn());
}
@@ -434,7 +425,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
StringBuilder sb = new StringBuilder(50).append("from "); // use from to stop parsing on table name
SpiQuery<?> query = request.queryRequest().query();
if (hasJoinTable()) {
sb.append(query.isAsDraft() ? intersectionDraftTable : intersectionPublishTable);
sb.append(intersectionJoin.getTable());
} else {
sb.append(targetDescriptor.baseTable(query.temporalMode()));
}
@@ -764,37 +755,21 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
return row;
}
public IntersectionRow buildManyToManyDeleteChildren(EntityBean parentBean, boolean publish) {
String tableName = publish ? intersectionPublishTable : intersectionDraftTable;
public IntersectionRow buildManyToManyDeleteChildren(EntityBean parentBean) {
String tableName = intersectionJoin.getTable();
IntersectionRow row = new IntersectionRow(tableName);
buildExport(row, parentBean);
return row;
}
public IntersectionRow buildManyToManyMapBean(EntityBean parent, EntityBean other, boolean publish) {
String tableName = publish ? intersectionPublishTable : intersectionDraftTable;
public IntersectionRow buildManyToManyMapBean(EntityBean parent, EntityBean other) {
String tableName = intersectionJoin.getTable();
IntersectionRow row = new IntersectionRow(tableName);
buildExport(row, parent);
buildImport(row, other);
return row;
}
/**
* Register the mapping of intersection table to associated draft table.
*/
void registerDraftIntersectionTable(BeanDescriptorInitContext initContext) {
if (hasDraftIntersection()) {
initContext.addDraftIntersection(intersectionPublishTable, intersectionDraftTable);
}
}
/**
* Return true if the relationship is a ManyToMany with the intersection having an associated draft table.
*/
private boolean hasDraftIntersection() {
return intersectionDraftTable != null && !intersectionDraftTable.equals(intersectionPublishTable);
}
/**
* Bind the two side of a many to many to the given SqlUpdate.
*/
@@ -879,55 +854,6 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
jsonHelp.jsonRead(readJson, parentBean);
}
@SuppressWarnings("unchecked")
void publishMany(EntityBean draft, EntityBean live) {
// collections will not be null due to enhancement
BeanCollection<T> draftVal = (BeanCollection<T>) getValueIntercept(draft);
BeanCollection<T> liveVal = (BeanCollection<T>) getValueIntercept(live);
// Organise the existing live beans into map keyed by id
Map<Object, T> liveBeansAsMap = liveBeansAsMap(liveVal);
// publish from each draft to live bean creating new live beans as required
draftVal.size();
Collection<T> actualDetails = draftVal.actualDetails();
for (T bean : actualDetails) {
Object id = targetDescriptor.id(bean);
T liveBean = liveBeansAsMap.remove(id);
if (isManyToMany()) {
if (liveBean == null) {
// add new relationship (Map not allowed here)
liveVal.addBean(targetDescriptor.createReference(id, null));
}
} else {
// recursively publish the OneToMany child bean
T newLive = targetDescriptor.publish(bean, liveBean);
if (liveBean == null) {
// Map not allowed here
liveVal.addBean(newLive);
}
}
}
// anything remaining should be deleted (so remove from modify aware collection)
Collection<T> values = liveBeansAsMap.values();
for (T value : values) {
liveVal.removeBean(value);
}
}
@SuppressWarnings("unchecked")
private Map<Object, T> liveBeansAsMap(BeanCollection<?> liveVal) {
liveVal.size();
Collection<?> liveBeans = liveVal.actualDetails();
Map<Object, T> liveMap = new LinkedHashMap<>();
for (Object liveBean : liveBeans) {
Object id = targetDescriptor.id(liveBean);
liveMap.put(id, (T) liveBean);
}
return liveMap;
}
public boolean isIncludeCascadeSave() {
// Note ManyToMany always included as we always 'save'
// the relationship via insert/delete of intersection table
@@ -79,11 +79,6 @@ public interface DbReadContext {
*/
SpiQuery.Mode queryMode();
/**
* Return true if the underlying query is a 'asDraft' query.
*/
boolean isDraftQuery();
/**
* Return true if this request disables lazy loading.
*/
@@ -124,11 +124,6 @@ public interface DbSqlContext {
*/
int asOfTableCount();
/**
* Return true if the query is a 'asDraft' query.
*/
boolean isDraftQuery();
/**
* Start group by clause.
*/
@@ -8,13 +8,11 @@ import java.util.List;
*/
public final class IntersectionBuilder {
private final String publishTable;
private final String draftTable;
private final String table;
private final List<String> columns = new ArrayList<>();
IntersectionBuilder(String publishTable, String draftTable) {
this.publishTable = publishTable;
this.draftTable = draftTable;
IntersectionBuilder(String table) {
this.table = table;
}
public void addColumn(String column) {
@@ -22,18 +20,9 @@ public final class IntersectionBuilder {
}
public IntersectionTable build() {
String insertSql = insertSql(publishTable);
String deleteSql = deleteSql(publishTable);
String draftInsertSql;
String draftDeleteSql;
if (publishTable.equals(draftTable)) {
draftInsertSql = insertSql;
draftDeleteSql = deleteSql;
} else {
draftInsertSql = insertSql(draftTable);
draftDeleteSql = deleteSql(draftTable);
}
return new IntersectionTable(insertSql, deleteSql, draftInsertSql, draftDeleteSql);
String insertSql = insertSql(table);
String deleteSql = deleteSql(table);
return new IntersectionTable(insertSql, deleteSql);
}
private String insertSql(String tableName) {
@@ -7,28 +7,24 @@ public final class IntersectionTable {
private final String insertSql;
private final String deleteSql;
private final String draftInsertSql;
private final String draftDeleteSql;
IntersectionTable(String insertSql, String deleteSql, String draftInsertSql, String draftDeleteSql) {
IntersectionTable(String insertSql, String deleteSql) {
this.insertSql = insertSql;
this.deleteSql = deleteSql;
this.draftInsertSql = draftInsertSql;
this.draftDeleteSql = draftDeleteSql;
}
/**
* Return a SqlUpdate for inserting into the intersection table.
*/
public SqlUpdate insert(Database server, boolean draft) {
return server.sqlUpdate(draft ? draftInsertSql : insertSql);
public SqlUpdate insert(Database server) {
return server.sqlUpdate(insertSql);
}
/**
* Return a SqlUpdate for deleting from the intersection table.
*/
public SqlUpdate delete(Database server, boolean draft) {
return server.sqlUpdate(draft ? draftDeleteSql : deleteSql);
public SqlUpdate delete(Database server) {
return server.sqlUpdate(deleteSql);
}
}
@@ -63,7 +63,6 @@ public class DeployBeanDescriptor<T> {
* Used with Identity columns but no getGeneratedKeys support.
*/
private String selectLastInsertedId;
private String selectLastInsertedIdDraft;
/**
* The concurrency mode for beans of this type.
*/
@@ -76,11 +75,8 @@ public class DeployBeanDescriptor<T> {
private String baseTable;
private String baseTableAsOf;
private String baseTableVersionsBetween;
private String draftTable;
private String[] dependentTables;
private boolean historySupport;
private boolean draftable;
private boolean draftableElement;
private TableName baseTableFull;
private String[] properties;
/**
@@ -217,23 +213,6 @@ public class DeployBeanDescriptor<T> {
return tablespaceMeta;
}
public void setDraftable() {
draftable = true;
}
public boolean isDraftable() {
return draftable;
}
public void setDraftableElement() {
draftable = true;
draftableElement = true;
}
public boolean isDraftableElement() {
return draftableElement;
}
/**
* Read the top level doc store deployment information.
*/
@@ -560,10 +539,6 @@ public class DeployBeanDescriptor<T> {
postConstructListeners.add(postConstructListener);
}
public String getDraftTable() {
return draftTable;
}
/**
* For view based entity return the dependant tables.
*/
@@ -617,7 +592,6 @@ public class DeployBeanDescriptor<T> {
this.baseTable = baseTableFull == null ? null : baseTableFull.getQualifiedName();
this.baseTableAsOf = baseTable + asOfSuffix;
this.baseTableVersionsBetween = baseTable + versionsBetweenSuffix;
this.draftTable = (draftable) ? baseTable + "_draft" : baseTable;
}
public void sortProperties() {
@@ -691,16 +665,11 @@ public class DeployBeanDescriptor<T> {
return selectLastInsertedId;
}
public String getSelectLastInsertedIdDraft() {
return selectLastInsertedIdDraft;
}
/**
* Set the SQL used to return the last inserted Id.
*/
public void setSelectLastInsertedId(String selectLastInsertedId, String selectLastInsertedIdDraft) {
public void setSelectLastInsertedId(String selectLastInsertedId) {
this.selectLastInsertedId = selectLastInsertedId;
this.selectLastInsertedIdDraft = selectLastInsertedIdDraft;
}
/**
@@ -159,10 +159,6 @@ public class DeployBeanProperty {
private int sortOrder;
private boolean excludedFromHistory;
private boolean tenantId;
private boolean draft;
private boolean draftOnly;
private boolean draftDirty;
private boolean draftReset;
private boolean softDelete;
private boolean unmappedJson;
private String dbComment;
@@ -901,41 +897,6 @@ public class DeployBeanProperty {
this.excludedFromHistory = true;
}
public void setDraft() {
this.draft = true;
this.isTransient = true;
}
public boolean isDraft() {
return draft;
}
public void setDraftOnly() {
this.draftOnly = true;
}
public boolean isDraftOnly() {
return draftOnly;
}
public void setDraftDirty() {
this.draftOnly = true;
this.draftDirty = true;
this.nullable = false;
}
public boolean isDraftDirty() {
return draftDirty;
}
public void setDraftReset() {
this.draftReset = true;
}
public boolean isDraftReset() {
return draftReset;
}
/**
* Primitive boolean check so see if not null default false should be applied.
*/
@@ -38,7 +38,6 @@ public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
private DeployTableJoin inverseJoin;
private String fetchOrderBy;
private String mapKey;
private String intersectionDraftTable;
private DeployOrderColumn orderColumn;
/**
* Effectively the dynamically created target descriptor (that doesn't have a mapped type/class per say).
@@ -191,20 +190,6 @@ public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
}
}
/**
* Return a draft table for intersection between 2 @Draftable entities.
*/
public String getIntersectionDraftTable() {
return (intersectionDraftTable != null) ? intersectionDraftTable : intersectionJoin.getTable();
}
/**
* ManyToMany between 2 @Draftable entities to also need draft intersection table.
*/
public void setIntersectionDraftTable() {
this.intersectionDraftTable = intersectionJoin.getTable() + "_draft";
}
public void setOrderColumn(DeployOrderColumn orderColumn) {
this.orderColumn = orderColumn;
}
@@ -22,8 +22,6 @@ public final class DeployBeanPropertyLists {
private BeanProperty versionProperty;
private BeanProperty unmappedJson;
private BeanProperty draft;
private BeanProperty draftDirty;
private BeanProperty tenant;
private final BeanDescriptor<?> desc;
private final LinkedHashMap<String, BeanProperty> propertyMap;
@@ -173,9 +171,6 @@ public final class DeployBeanPropertyLists {
private void allocateToList(BeanProperty prop) {
if (prop.isTransient()) {
transients.add(prop);
if (prop.isDraft()) {
draft = prop;
}
if (prop.isUnmappedJson()) {
unmappedJson = prop;
}
@@ -226,8 +221,6 @@ public final class DeployBeanPropertyLists {
} else {
CoreLog.internal.log(WARNING, "Multiple @Version properties - property " + prop.fullName() + " not treated as a version property");
}
} else if (prop.isDraftDirty()) {
draftDirty = prop;
}
if (!prop.isAggregation()) {
baseScalar.add(prop);
@@ -324,18 +317,10 @@ public final class DeployBeanPropertyLists {
return getMany2Many();
}
public BeanProperty getDraftDirty() {
return draftDirty;
}
public BeanProperty getUnmappedJson() {
return unmappedJson;
}
public BeanProperty getDraft() {
return draft;
}
public BeanProperty getSoftDeleteProperty() {
for (BeanProperty prop : nonManys) {
if (prop.isSoftDelete()) {
@@ -156,11 +156,11 @@ final class AnnotationClass extends AnnotationParser {
}
Draftable draftable = typeGet(cls, Draftable.class);
if (draftable != null) {
descriptor.setDraftable();
//TODO: Not Supported
}
DraftableElement draftableElement = typeGet(cls, DraftableElement.class);
if (draftableElement != null) {
descriptor.setDraftableElement();
//TODO: Not Supported
}
ReadAudit readAudit = typeGet(cls, ReadAudit.class);
if (readAudit != null) {
@@ -205,16 +205,7 @@ final class AnnotationFields extends AnnotationParser {
prop.setTenantId();
}
if (has(prop, Draft.class)) {
prop.setDraft();
}
if (has(prop, DraftOnly.class)) {
prop.setDraftOnly();
}
if (has(prop, DraftDirty.class)) {
prop.setDraftDirty();
}
if (has(prop, DraftReset.class)) {
prop.setDraftReset();
// TODO: Not Supported
}
if (has(prop, SoftDelete.class)) {
prop.setSoftDelete();
@@ -257,11 +257,6 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return query.asOf(asOf);
}
@Override
public Query<T> asDraft() {
return query.asDraft();
}
@Override
public <D> DtoQuery<D> asDto(Class<D> dtoClass) {
return query.asDto(dtoClass);
@@ -347,11 +347,6 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
return exprList.asOf(asOf);
}
@Override
public Query<T> asDraft() {
return exprList.asDraft();
}
@Override
public <D> DtoQuery<D> asDto(Class<D> dtoClass) {
return exprList.asDto(dtoClass);
@@ -25,7 +25,6 @@ public final class DLoadContext implements LoadContext {
private final Map<String, DLoadBeanContext> beanMap = new HashMap<>();
private final Map<String, DLoadManyContext> manyMap = new HashMap<>();
private final DLoadBeanContext rootBeanContext;
private final boolean asDraft;
private final Timestamp asOf;
private final Boolean readOnly;
private final CacheMode useBeanCache;
@@ -59,7 +58,6 @@ public final class DLoadContext implements LoadContext {
this.origin = initOrigin();
this.defaultBatchSize = 100;
this.useBeanCache = CacheMode.OFF;
this.asDraft = false;
this.asOf = null;
this.readOnly = false;
this.disableLazyLoading = false;
@@ -86,7 +84,6 @@ public final class DLoadContext implements LoadContext {
SpiQuery<?> query = request.query();
this.useDocStore = query.isUseDocStore();
this.asOf = query.getAsOf();
this.asDraft = query.isAsDraft();
this.includeSoftDeletes = query.isIncludeSoftDeletes() && query.mode() == SpiQuery.Mode.NORMAL;
this.readOnly = query.isReadOnly();
this.disableLazyLoading = query.isDisableLazyLoading();
@@ -322,9 +319,6 @@ public final class DLoadContext implements LoadContext {
}
query.setDisableLazyLoading(disableLazyLoading);
query.asOf(asOf);
if (asDraft) {
query.asDraft();
}
if (includeSoftDeletes) {
query.setIncludeSoftDeletes();
}
@@ -143,204 +143,6 @@ public final class DefaultPersister implements Persister {
return executeOrQueue(new PersistRequestUpdateSql(server, updSql, (SpiTransaction) t, persistExecute, true));
}
/**
* Restore draft beans to match live beans given the query.
*/
@Override
public <T> List<T> draftRestore(Query<T> query, Transaction transaction) {
Class<T> beanType = query.getBeanType();
BeanDescriptor<T> desc = server.descriptor(beanType);
DraftHandler<T> draftHandler = new DraftHandler<>(desc, transaction);
query.usingTransaction(transaction);
List<T> liveBeans = draftHandler.fetchSourceBeans((SpiQuery<T>) query, false);
PUB.log(DEBUG, "draftRestore [{0}] count[{1}]", desc.name(), liveBeans.size());
if (liveBeans.isEmpty()) {
return Collections.emptyList();
}
draftHandler.fetchDestinationBeans(liveBeans, true);
BeanManager<T> mgr = beanDescriptorManager.beanManager(beanType);
for (T liveBean : liveBeans) {
T draftBean = draftHandler.publishToDestinationBean(liveBean);
// reset @DraftDirty and @DraftReset properties
draftHandler.resetDraft(draftBean);
PUB.log(TRACE, "draftRestore bean [{0}] id[{1}]", desc.name(), draftHandler.getId());
update(createRequest(draftBean, transaction, null, mgr, Type.UPDATE, Flags.RECURSE));
}
PUB.log(DEBUG, "draftRestore - complete for [{0}]", desc.name());
return draftHandler.getDrafts();
}
/**
* Helper method to return the list of Id values for the list of beans.
*/
private <T> List<Object> getBeanIds(BeanDescriptor<T> desc, List<T> beans) {
List<Object> idList = new ArrayList<>(beans.size());
for (T liveBean : beans) {
idList.add(desc.id(liveBean));
}
return idList;
}
/**
* Publish from draft to live given the query.
*/
@Override
public <T> List<T> publish(Query<T> query, Transaction transaction) {
Class<T> beanType = query.getBeanType();
BeanDescriptor<T> desc = server.descriptor(beanType);
DraftHandler<T> draftHandler = new DraftHandler<>(desc, transaction);
query.usingTransaction(transaction);
List<T> draftBeans = draftHandler.fetchSourceBeans((SpiQuery<T>) query, true);
PUB.log(DEBUG, "publish [{0}] count[{1}]", desc.name(), draftBeans.size());
if (draftBeans.isEmpty()) {
return Collections.emptyList();
}
draftHandler.fetchDestinationBeans(draftBeans, false);
BeanManager<T> mgr = beanDescriptorManager.beanManager(beanType);
List<T> livePublish = new ArrayList<>(draftBeans.size());
for (T draftBean : draftBeans) {
T liveBean = draftHandler.publishToDestinationBean(draftBean);
livePublish.add(liveBean);
// reset @DraftDirty and @DraftReset properties
draftHandler.resetDraft(draftBean);
Type persistType = draftHandler.isInsert() ? Type.INSERT : Type.UPDATE;
PUB.log(TRACE, "publish bean [{0}] id[{1}] type[{2}]", desc.name(), draftHandler.getId(), persistType);
PersistRequestBean<T> request = createRequest(liveBean, transaction, null, mgr, persistType, Flags.PUBLISH_RECURSE);
if (persistType == Type.INSERT) {
insert(request);
} else {
update(request);
}
request.resetDepth();
}
draftHandler.updateDrafts(transaction, mgr);
PUB.log(DEBUG, "publish - complete for [{0}]", desc.name());
return livePublish;
}
/**
* Helper to handle draft beans (properties reset etc).
*/
class DraftHandler<T> {
final BeanDescriptor<T> desc;
final Transaction transaction;
final List<T> draftUpdates = new ArrayList<>();
/**
* Id value of the last published bean.
*/
Object id;
/**
* True if the last published bean is new/insert.
*/
boolean insert;
/**
* The destination beans to publish/restore to mapped by id.
*/
Map<?, T> destBeans;
DraftHandler(BeanDescriptor<T> desc, Transaction transaction) {
this.desc = desc;
this.transaction = transaction;
}
/**
* Return the list of draft beans with changes (to be persisted).
*/
List<T> getDrafts() {
return draftUpdates;
}
/**
* Set the draft dirty state to false and reset any dirtyReset properties.
*/
void resetDraft(T draftBean) {
if (desc.draftReset(draftBean)) {
// draft bean is dirty so collect it for persisting later
draftUpdates.add(draftBean);
}
}
/**
* Save all the draft beans (with various properties reset etc).
*/
void updateDrafts(Transaction transaction, BeanManager<T> mgr) {
if (!draftUpdates.isEmpty()) {
// update the dirty status on the drafts that have been published
PUB.log(DEBUG, "publish - update dirty status on [{0}] drafts", draftUpdates.size());
for (T draftUpdate : draftUpdates) {
update(createRequest(draftUpdate, transaction, null, mgr, Type.UPDATE, Flags.ZERO));
}
}
}
/**
* Fetch the source beans based on the query.
*/
List<T> fetchSourceBeans(SpiQuery<T> query, boolean asDraft) {
desc.draftQueryOptimise(query);
if (asDraft) {
query.asDraft();
}
return server.findList(query);
}
/**
* Fetch the destination beans that will be published to.
*/
void fetchDestinationBeans(List<T> sourceBeans, boolean asDraft) {
List<Object> ids = getBeanIds(desc, sourceBeans);
SpiQuery<T> destQuery = server.createQuery(desc.type());
destQuery.usingTransaction(transaction);
destQuery.where().idIn(ids);
if (asDraft) {
destQuery.asDraft();
}
desc.draftQueryOptimise(destQuery);
this.destBeans = server.findMap(destQuery);
}
/**
* Publish/restore the values from the sourceBean to the matching destination bean.
*/
T publishToDestinationBean(T sourceBean) {
id = desc.id(sourceBean);
T destBean = destBeans.get(id);
insert = (destBean == null);
// apply changes from liveBean to draftBean
return desc.publish(sourceBean, destBean);
}
/**
* Return true if the last publish resulted in an new bean to insert.
*/
boolean isInsert() {
return insert;
}
/**
* Return the Id value of the last published/restored bean.
*/
Object getId() {
return id;
}
}
/**
* Recursively delete the bean. This calls back to the EbeanServer.
*/
@@ -380,7 +182,6 @@ public final class DefaultPersister implements Persister {
@Override
public void update(EntityBean entityBean, Transaction t) {
PersistRequestBean<?> req = createRequest(entityBean, t, PersistRequest.Type.UPDATE);
req.checkDraft();
try {
req.initTransIfRequiredWithBatchCascade();
if (req.isReference()) {
@@ -526,15 +327,8 @@ public final class DefaultPersister implements Persister {
public int delete(EntityBean bean, Transaction t, boolean permanent) {
Type deleteType = permanent ? Type.DELETE_PERMANENT : Type.DELETE;
PersistRequestBean<EntityBean> originalRequest = createDeleteRequest(bean, t, deleteType);
if (originalRequest.isHardDeleteDraft()) {
// a hard delete of a draftable bean so first we need to delete the associated 'live' bean
// due to FK constraint and then after that execute the original delete of the draft bean
return deleteRequest(createDeleteRequest(originalRequest.createReference(), t, Type.DELETE_PERMANENT, Flags.PUBLISH), originalRequest);
} else {
// normal delete or soft delete
return deleteRequest(originalRequest);
}
// normal delete or soft delete
return deleteRequest(originalRequest);
}
/**
@@ -988,8 +782,8 @@ public final class DefaultPersister implements Persister {
}
}
void deleteManyIntersection(EntityBean bean, BeanPropertyAssocMany<?> many, SpiTransaction t, boolean publish, boolean queue) {
SpiSqlUpdate sqlDelete = deleteAllIntersection(bean, many, publish);
void deleteManyIntersection(EntityBean bean, BeanPropertyAssocMany<?> many, SpiTransaction t, boolean queue) {
SpiSqlUpdate sqlDelete = deleteAllIntersection(bean, many);
if (queue) {
addToFlushQueue(sqlDelete, t, BatchControl.DELETE_QUEUE);
} else {
@@ -997,8 +791,8 @@ public final class DefaultPersister implements Persister {
}
}
private SpiSqlUpdate deleteAllIntersection(EntityBean bean, BeanPropertyAssocMany<?> many, boolean publish) {
IntersectionRow intRow = many.buildManyToManyDeleteChildren(bean, publish);
private SpiSqlUpdate deleteAllIntersection(EntityBean bean, BeanPropertyAssocMany<?> many) {
IntersectionRow intRow = many.buildManyToManyDeleteChildren(bean);
return intRow.createDeleteChildren(server);
}
@@ -1047,7 +841,7 @@ public final class DefaultPersister implements Persister {
if (many.hasJoinTable()) {
if (deleteMode.isHard()) {
// delete associated rows from intersection table (but not during soft delete)
deleteManyIntersection(parentBean, many, t, request.isPublish(), false);
deleteManyIntersection(parentBean, many, t, false);
}
} else {
if (ModifyListenMode.REMOVALS == many.modifyListenMode()) {
@@ -1239,7 +1033,7 @@ public final class DefaultPersister implements Persister {
BeanDescriptor<T> desc = mgr.getBeanDescriptor();
EntityBean entityBean = (EntityBean) bean;
PersistRequest.Type type;
if (Flags.isPublishMergeOrNormal(flags)) {
if (Flags.isMergeOrNormal(flags)) {
// just use bean state to determine insert or update
type = entityBean._ebean_getIntercept().isUpdate() ? Type.UPDATE : Type.INSERT;
} else {
@@ -17,11 +17,6 @@ public final class Flags {
*/
public static final int RECURSE = 0x00000002;
/**
* Indicates Publish mode.
*/
public static final int PUBLISH = 0x00000004;
/**
* Indicates Merge mode.
*/
@@ -37,9 +32,9 @@ public final class Flags {
*/
public static final int ZERO = 0;
public static final int PUBLISH_RECURSE = PUBLISH + RECURSE;
// public static final int PUBLISH_RECURSE = PUBLISH + RECURSE;
private static final int PUBLISH_MERGE_NORMAL = PUBLISH + MERGE + NORMAL;
private static final int MERGE_NORMAL = MERGE + NORMAL;
private static final int INSERT_NORMAL = INSERT + NORMAL;
@@ -57,25 +52,18 @@ public final class Flags {
return isSet(state, RECURSE);
}
/**
* Return true if part of a Publish.
*/
public static boolean isPublish(int state) {
return isSet(state, PUBLISH);
}
/**
* Return true if part of a Merge.
*/
public static boolean isMerge(int state) {
return isSet(state, PUBLISH);
return isSet(state, MERGE);
}
/**
* Return true if part of a Merge or Publish or Normal (bean state matches persist).
*/
public static boolean isPublishMergeOrNormal(int state) {
return (state & PUBLISH_MERGE_NORMAL) != 0;
public static boolean isMergeOrNormal(int state) {
return (state & MERGE_NORMAL) != 0;
}
public static boolean isUpdateForce(int state) {
@@ -130,17 +118,6 @@ public final class Flags {
return unset(state, RECURSE);
}
/**
* Set Publish flag.
*/
public static int setPublish(int state) {
return set(state, PUBLISH);
}
public static int unsetPublish(int state) {
return unset(state, PUBLISH);
}
/**
* Set Merge flag.
*/
@@ -54,7 +54,7 @@ final class MergeNodeAssocManyToMany extends MergeNode {
if (!deletions.isEmpty()) {
transaction.flush();
SqlUpdate delete = intersectionTable.delete(server, false);
SqlUpdate delete = intersectionTable.delete(server);
for (EntityBean deletion : deletions) {
many.intersectionBind(delete, parentBean, deletion);
delete.addBatch();
@@ -64,7 +64,7 @@ final class MergeNodeAssocManyToMany extends MergeNode {
if (!additions.isEmpty()) {
transaction.flush();
SqlUpdate insert = intersectionTable.insert(server, false);
SqlUpdate insert = intersectionTable.insert(server);
for (EntityBean addition : additions) {
many.intersectionBind(insert, parentBean, addition);
insert.addBatch();
@@ -23,7 +23,6 @@ import static java.lang.System.Logger.Level.WARNING;
final class SaveManyBeans extends SaveManyBase {
private final boolean cascade;
private final boolean publish;
private final BeanDescriptor<?> targetDescriptor;
private final boolean isMap;
private final boolean saveRecurseSkippable;
@@ -38,7 +37,6 @@ final class SaveManyBeans extends SaveManyBase {
SaveManyBeans(DefaultPersister persister, boolean insertedParent, BeanPropertyAssocMany<?> many, EntityBean parentBean, PersistRequestBean<?> request) {
super(persister, insertedParent, many, parentBean, request);
this.cascade = many.cascadeInfo().isSave();
this.publish = request.isPublish();
this.targetDescriptor = many.targetDescriptor();
this.isMap = many.manyType().isMap();
this.saveRecurseSkippable = many.isSaveRecurseSkippable();
@@ -258,7 +256,7 @@ final class SaveManyBeans extends SaveManyBase {
if (vanillaCollection || forcedUpdate) {
// delete all intersection rows and then treat all
// beans in the collection as additions
persister.deleteManyIntersection(parentBean, many, transaction, publish, queue);
persister.deleteManyIntersection(parentBean, many, transaction, queue);
}
Collection<?> deletions = null;
@@ -296,7 +294,7 @@ final class SaveManyBeans extends SaveManyBase {
EntityBean otherDelete = (EntityBean) other;
// the object from the 'other' side of the ManyToMany
// build a intersection row for 'delete'
IntersectionRow intRow = many.buildManyToManyMapBean(parentBean, otherDelete, publish);
IntersectionRow intRow = many.buildManyToManyMapBean(parentBean, otherDelete);
SpiSqlUpdate sqlDelete = intRow.createDelete(server, DeleteMode.HARD);
persister.executeOrQueue(sqlDelete, transaction, queue, BatchControl.DELETE_QUEUE);
}
@@ -316,7 +314,7 @@ final class SaveManyBeans extends SaveManyBase {
throw new PersistenceException("ManyToMany bean does not have an Id value? " + otherBean);
} else {
// build a intersection row for 'insert'
IntersectionRow intRow = many.buildManyToManyMapBean(parentBean, otherBean, publish);
IntersectionRow intRow = many.buildManyToManyMapBean(parentBean, otherBean);
SpiSqlUpdate sqlInsert = intRow.createInsert(server);
persister.executeOrQueue(sqlInsert, transaction, queue, BatchControl.INSERT_QUEUE);
}
@@ -17,23 +17,12 @@ final class DeleteMeta extends BaseMeta {
private final String sqlVersion;
private final String sqlNone;
private final String sqlDraftVersion;
private final String sqlDraftNone;
DeleteMeta(BeanDescriptor<?> desc, BindableId id, Bindable version, Bindable tenantId) {
super(id, version, tenantId);
String tableName = desc.baseTable();
this.sqlNone = genSql(ConcurrencyMode.NONE, tableName);
this.sqlVersion = genSql(ConcurrencyMode.VERSION, tableName);
if (desc.isDraftable()) {
String draftTableName = desc.draftTable();
this.sqlDraftNone = genSql(ConcurrencyMode.NONE, draftTableName);
this.sqlDraftVersion = genSql(ConcurrencyMode.VERSION, draftTableName);
} else {
this.sqlDraftNone = sqlNone;
this.sqlDraftVersion = sqlVersion;
}
}
/**
@@ -59,13 +48,12 @@ final class DeleteMeta extends BaseMeta {
throw new IllegalStateException("Can not deleteById on " + request.fullName() + " as no @Id property");
}
boolean publish = request.isPublish();
switch (request.concurrencyMode()) {
case NONE:
return publish ? sqlNone : sqlDraftNone;
return sqlNone;
case VERSION:
return publish ? sqlVersion : sqlDraftVersion;
return sqlVersion;
default:
throw new RuntimeException("Invalid mode " + request.concurrencyMode());
@@ -69,7 +69,7 @@ public final class InsertHandler extends DmlHandler {
SpiTransaction t = persistRequest.transaction();
// get the appropriate sql
sql = meta.getSql(withId, persistRequest.isPublish());
sql = meta.getSql(withId);
PreparedStatement pstmt;
if (persistRequest.isBatched()) {
pstmt = pstmtBatch(t, sql, persistRequest, useGeneratedKeys);
@@ -77,7 +77,7 @@ public final class InsertHandler extends DmlHandler {
pstmt = pstmt(t, sql, useGeneratedKeys);
}
dataBind = bind(pstmt);
meta.bind(this, bean, withId, persistRequest.isPublish());
meta.bind(this, bean, withId);
if (persistRequest.isBatched()) {
batchedPstmt.registerInputStreams(dataBind.getInputStreams());
}
@@ -21,12 +21,9 @@ final class InsertMeta {
private final String sqlNullId;
private final String sqlWithId;
private final String sqlDraftNullId;
private final String sqlDraftWithId;
private final BindableId id;
private final Bindable discriminator;
private final BindableList all;
private final BindableList allExcludeDraftOnly;
private final boolean supportsGetGeneratedKeys;
private final boolean concatenatedKey;
/**
@@ -42,13 +39,10 @@ final class InsertMeta {
this.discriminator = discriminator(desc);
this.id = id;
this.all = all;
this.allExcludeDraftOnly = all.excludeDraftOnly();
this.shadowFKey = shadowFKey;
String tableName = desc.baseTable();
String draftTableName = desc.draftTable();
this.sqlWithId = genSql(false, tableName, false);
this.sqlDraftWithId = desc.isDraftable() ? genSql(false, draftTableName, true) : sqlWithId;
this.sqlWithId = genSql(false, tableName);
// only available for single Id property
if (id.isConcatenated()) {
@@ -56,7 +50,6 @@ final class InsertMeta {
this.concatenatedKey = true;
this.identityDbColumns = null;
this.sqlNullId = null;
this.sqlDraftNullId = null;
this.supportsGetGeneratedKeys = false;
this.supportsSelectLastInsertedId = false;
@@ -72,8 +65,7 @@ final class InsertMeta {
this.supportsGetGeneratedKeys = dbPlatform.dbIdentity().isSupportsGetGeneratedKeys();
this.supportsSelectLastInsertedId = desc.supportsSelectLastInsertedId();
}
this.sqlNullId = genSql(true, tableName, false);
this.sqlDraftNullId = desc.isDraftable() ? genSql(true, draftTableName, true) : sqlNullId;
this.sqlNullId = genSql(true, tableName);
}
}
@@ -119,7 +111,7 @@ final class InsertMeta {
/**
* Bind the request based on whether the id value(s) are null.
*/
public void bind(DmlHandler request, EntityBean bean, boolean withId, boolean publish) throws SQLException {
public void bind(DmlHandler request, EntityBean bean, boolean withId) throws SQLException {
if (withId) {
id.dmlBind(request, bean);
}
@@ -129,29 +121,25 @@ final class InsertMeta {
if (discriminator != null) {
discriminator.dmlBind(request, bean);
}
if (publish) {
allExcludeDraftOnly.dmlBind(request, bean);
} else {
all.dmlBind(request, bean);
}
all.dmlBind(request, bean);
}
/**
* get the sql based whether the id value(s) are null.
*/
public String getSql(boolean withId, boolean publish) {
public String getSql(boolean withId) {
if (withId) {
return publish ? sqlWithId : sqlDraftWithId;
return sqlWithId;
} else {
return publish ? sqlNullId : sqlDraftNullId;
return sqlNullId;
}
}
private String genSql(boolean nullId, String table, boolean draftTable) {
private String genSql(boolean nullId, String table) {
GenerateDmlRequest request = new GenerateDmlRequest();
request.setInsertSetMode();
request.append("insert into ").append(table);
if (nullId && noColumnsForInsert(draftTable)) {
if (nullId && noColumnsForInsert()) {
return request.append(defaultValues()).toString();
}
request.append(" (");
@@ -164,11 +152,8 @@ final class InsertMeta {
if (discriminator != null) {
discriminator.dmlAppend(request);
}
if (draftTable) {
all.dmlAppend(request);
} else {
allExcludeDraftOnly.dmlAppend(request);
}
all.dmlAppend(request);
request.append(") values (");
request.append(request.insertBindBuffer());
request.append(")");
@@ -191,10 +176,10 @@ final class InsertMeta {
/**
* Return true if the insert actually contains no columns.
*/
private boolean noColumnsForInsert(boolean draftTable) {
private boolean noColumnsForInsert() {
return shadowFKey == null
&& discriminator == null
&& (draftTable ? all.isEmpty() : allExcludeDraftOnly.isEmpty());
&& all.isEmpty();
}
}
@@ -38,9 +38,4 @@ public interface Bindable {
* when binding a update or delete where clause with ALL concurrency mode.
*/
void dmlBind(BindableRequest request, EntityBean bean) throws SQLException;
/**
* Return true if the underlying property is 'draft only'.
*/
boolean isDraftOnly();
}
@@ -23,11 +23,6 @@ class BindableAssocOne implements Bindable {
this.importedId = assocOne.importedId();
}
@Override
public final boolean isDraftOnly() {
return assocOne.isDraftOnly();
}
@Override
public final void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
if (request.isAddToUpdate(assocOne)) {
@@ -24,11 +24,6 @@ public final class BindableDiscriminator implements Bindable {
this.sqlType = inheritInfo.getDiscriminatorType();
}
@Override
public boolean isDraftOnly() {
return false;
}
@Override
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
throw new PersistenceException("Never called (only for inserts)");
@@ -6,7 +6,6 @@ import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.persist.dml.GenerateDmlRequest;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
/**
@@ -23,11 +22,6 @@ final class BindableEmbedded implements Bindable {
this.items = bindList.toArray(new Bindable[0]);
}
@Override
public boolean isDraftOnly() {
return embProp.isDraftOnly();
}
@Override
public void dmlAppend(GenerateDmlRequest request) {
for (Bindable item : items) {
@@ -23,11 +23,6 @@ final class BindableEncryptedProperty implements Bindable {
this.bindEncryptDataFirst = bindEncryptDataFirst;
}
@Override
public boolean isDraftOnly() {
return prop.isDraftOnly();
}
@Override
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
if (request.isAddToUpdate(prop)) {
@@ -28,11 +28,6 @@ final class BindableIdEmbedded implements BindableId {
this.matches = matches;
}
@Override
public boolean isDraftOnly() {
return false;
}
@Override
public boolean isEmpty() {
return false;
@@ -13,11 +13,6 @@ final class BindableIdEmpty implements BindableId {
return true;
}
@Override
public boolean isDraftOnly() {
return false;
}
@Override
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
// nothing
@@ -35,11 +35,6 @@ final class BindableIdScalar implements BindableId {
return uidProp.dbColumn();
}
@Override
public boolean isDraftOnly() {
return false;
}
/**
* Does nothing for BindableId.
*/
@@ -20,28 +20,10 @@ public final class BindableList implements Bindable {
items = list.toArray(new Bindable[0]);
}
/**
* Return a bindable list that excludes @DraftOnly properties.
*/
public BindableList excludeDraftOnly() {
List<Bindable> copy = new ArrayList<>(items.length);
for (Bindable b : items) {
if (!b.isDraftOnly()) {
copy.add(b);
}
}
return new BindableList(copy);
}
public boolean isEmpty() {
return items.length == 0;
}
@Override
public boolean isDraftOnly() {
return false;
}
public void addAll(List<Bindable> list) {
Collections.addAll(list, items);
}
@@ -19,11 +19,6 @@ class BindableProperty implements Bindable {
this.prop = prop;
}
@Override
public final boolean isDraftOnly() {
return prop.isDraftOnly();
}
@Override
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
if (request.isAddToUpdate(prop)) {
@@ -24,11 +24,6 @@ final class BindablePropertyVersion implements Bindable {
return prop.toString();
}
@Override
public boolean isDraftOnly() {
return prop.isDraftOnly();
}
@Override
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
if (request.isAddToUpdate(prop)) {
@@ -29,11 +29,6 @@ public final class BindableUnidirectional implements Bindable {
this.importedId = unidirectional.importedId();
}
@Override
public boolean isDraftOnly() {
return false;
}
@Override
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
throw new PersistenceException("Never called (for insert only)");
@@ -211,11 +211,6 @@ public final class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfi
return loadContextBean;
}
@Override
public boolean isDraftQuery() {
return query.isAsDraft();
}
@Override
public boolean isDisableLazyLoading() {
return disableLazyLoading;
@@ -48,17 +48,15 @@ final class CQueryBuilder {
private final Binder binder;
private final boolean selectCountWithAlias;
private final CQueryHistorySupport historySupport;
private final CQueryDraftSupport draftSupport;
private final DatabasePlatform dbPlatform;
private final boolean selectCountWithColumnAlias;
/**
* Create the SqlGenSelect.
*/
CQueryBuilder(DatabasePlatform dbPlatform, Binder binder, CQueryHistorySupport historySupport, CQueryDraftSupport draftSupport) {
CQueryBuilder(DatabasePlatform dbPlatform, Binder binder, CQueryHistorySupport historySupport) {
this.dbPlatform = dbPlatform;
this.binder = binder;
this.draftSupport = draftSupport;
this.historySupport = historySupport;
this.columnAliasPrefix = dbPlatform.columnAliasPrefix();
this.sqlLimiter = dbPlatform.sqlLimiter();
@@ -221,13 +219,6 @@ final class CQueryBuilder {
return query.temporalMode().isHistory() ? historySupport : null;
}
/**
* Return the draft support (or null) for a 'asDraft' query.
*/
<T> CQueryDraftSupport draftSupport(SpiQuery<T> query) {
return query.temporalMode() == SpiQuery.TemporalMode.DRAFT ? draftSupport : null;
}
/**
* Build the row count query.
*/
@@ -1,28 +0,0 @@
package io.ebeaninternal.server.query;
import java.util.Map;
/**
* Support 'asDraft' queries.
*/
final class CQueryDraftSupport {
/**
* The mapping of base tables to their matching 'draft' table.
*/
private final Map<String, String> tableMap;
CQueryDraftSupport(Map<String, String> tableMap) {
this.tableMap = tableMap;
}
/**
* Return the draft table associated to the base table.
* <p>
* This returns null for entities that are not draftable and in that case
* the usual base table is used.
*/
String draftTable(String table) {
return tableMap.get(table);
}
}
@@ -38,13 +38,13 @@ public final class CQueryEngine {
private final CQueryHistorySupport historySupport;
private final DatabasePlatform dbPlatform;
public CQueryEngine(DatabaseConfig config, DatabasePlatform dbPlatform, Binder binder, Map<String, String> asOfTableMapping, Map<String, String> draftTableMap) {
public CQueryEngine(DatabaseConfig config, DatabasePlatform dbPlatform, Binder binder, Map<String, String> asOfTableMapping) {
this.dbPlatform = dbPlatform;
this.defaultFetchSizeFindEach = config.getJdbcFetchSizeFindEach();
this.defaultFetchSizeFindList = config.getJdbcFetchSizeFindList();
this.forwardOnlyHintOnFindIterate = dbPlatform.forwardOnlyHintOnFindIterate();
this.historySupport = new CQueryHistorySupport(dbPlatform.historySupport(), asOfTableMapping, config.getAsOfSysPeriod());
this.queryBuilder = new CQueryBuilder(dbPlatform, binder, historySupport, new CQueryDraftSupport(draftTableMap));
this.queryBuilder = new CQueryBuilder(dbPlatform, binder, historySupport);
}
public int forwardOnlyFetchSize() {
@@ -414,9 +414,6 @@ public final class CQueryEngine {
if (query.isAutoTuned()) {
msg.append("tuned[true] ");
}
if (query.isAsDraft()) {
msg.append(" draft[true] ");
}
if (originKey != null) {
msg.append("origin[").append(originKey).append("] ");
}
@@ -458,9 +455,6 @@ public final class CQueryEngine {
if (query.isAutoTuned()) {
msg.append("tuned[true] ");
}
if (query.isAsDraft()) {
msg.append(" draft[true] ");
}
if (originKey != null) {
msg.append("origin[").append(originKey).append("] ");
}
@@ -35,17 +35,15 @@ final class DefaultDbSqlContext implements DbSqlContext {
private String currentPrefix;
private List<BeanProperty> encryptedProps;
private List<SqlTreeJoin> extraJoins;
private final CQueryDraftSupport draftSupport;
private final CQueryHistorySupport historySupport;
private final boolean historyQuery;
private boolean joinSuppressed;
DefaultDbSqlContext(SqlTreeAlias alias, String columnAliasPrefix, CQueryHistorySupport historySupport,
CQueryDraftSupport draftSupport, String fromForUpdate) {
String fromForUpdate) {
this.alias = alias;
this.columnAliasPrefix = columnAliasPrefix;
this.useColumnAlias = columnAliasPrefix != null;
this.draftSupport = draftSupport;
this.historySupport = historySupport;
this.historyQuery = (historySupport != null);
this.fromForUpdate = fromForUpdate;
@@ -131,9 +129,7 @@ final class DefaultDbSqlContext implements DbSqlContext {
tableJoins.add(joinKey);
sb.append(' ').append(type);
boolean addAsOfOnClause = false;
if (draftSupport != null) {
appendTable(table, draftSupport.draftTable(table));
} else if (!historyQuery) {
if (!historyQuery) {
sb.append(' ').append(table).append(' ');
} else {
// check if there is an associated history table and if so
@@ -192,11 +188,6 @@ final class DefaultDbSqlContext implements DbSqlContext {
return asOfTableCount;
}
@Override
public boolean isDraftQuery() {
return draftSupport != null;
}
@Override
public String tableAlias(String prefix) {
return alias.tableAlias(prefix);
@@ -150,11 +150,6 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Override
public Query<T> asDraft() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Override
public <D> DtoQuery<D> asDto(Class<D> dtoClass) {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
@@ -89,11 +89,6 @@ public interface STreeType {
*/
Object contextPutIfAbsent(PersistenceContext persistenceContext, Object id, EntityBean localBean);
/**
* Set draft status on the entity bean.
*/
void setDraft(EntityBean localBean);
/**
* Invoke any post load listeners.
*/
@@ -46,7 +46,7 @@ public final class SqlBeanLoad {
}
public Object load(BeanProperty prop) {
if (!rawSql && !prop.isLoadProperty(ctx.isDraftQuery())) {
if (!rawSql && !prop.isLoadProperty()) {
return null;
}
if ((bean == null)
@@ -101,9 +101,8 @@ public final class SqlTreeBuilder {
this.distinctNoLobs = builder.isPlatformDistinctNoLobs();
String fromForUpdate = builder.fromForUpdate(query);
CQueryHistorySupport historySupport = builder.historySupport(query);
CQueryDraftSupport draftSupport = builder.draftSupport(query);
String colAlias = subQuery ? null : columnAliasPrefix;
this.ctx = new DefaultDbSqlContext(alias, colAlias, historySupport, draftSupport, fromForUpdate);
this.ctx = new DefaultDbSqlContext(alias, colAlias, historySupport, fromForUpdate);
this.common = new SqlTreeCommon(temporalMode, disableLazyLoad, readOnly, includeJoin);
}
@@ -259,9 +259,6 @@ class SqlTreeLoadBean implements SqlTreeLoad {
if (readIdNormal) {
createListProxies();
}
if (temporalMode == SpiQuery.TemporalMode.DRAFT) {
localDesc.setDraft(localBean);
}
localDesc.postLoad(localBean);
EntityBeanIntercept ebi = localBean._ebean_getIntercept();
@@ -336,13 +336,6 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
return this;
}
@Override
public final Query<T> asDraft() {
this.temporalMode = TemporalMode.DRAFT;
this.useBeanCache = CacheMode.OFF;
return this;
}
@Override
public final Query<T> setIncludeSoftDeletes() {
this.temporalMode = TemporalMode.SOFT_DELETED;
@@ -942,11 +935,6 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
return asOf != null;
}
@Override
public final boolean isAsDraft() {
return TemporalMode.DRAFT == temporalMode;
}
@Override
public final boolean isIncludeSoftDeletes() {
return TemporalMode.SOFT_DELETED == temporalMode;
@@ -205,8 +205,6 @@ public class OrmQueryPlanKeyTest extends BaseTest {
public void equals_when_diffTemporalMode() {
CQueryPlanKey key1 = planKey(query());
CQueryPlanKey key2 = planKey(query().asDraft());
assertDifferent(key1, key2);
CQueryPlanKey key3 = planKey(query().asOf(new Timestamp(System.currentTimeMillis())));
assertDifferent(key1, key3);
@@ -140,10 +140,8 @@ public abstract class DbTriggerBasedHistoryDdl extends DbTableBasedHistoryDdl im
protected void createHistoryTableAs(DdlBuffer apply, MTable table) {
apply.append(platformDdl.getCreateTableCommandPrefix()).append(" ").append(historyTableName(table.getName())).append("(").newLine();
for (MColumn column : table.allColumns()) {
if (!column.isDraftOnly()) {
writeColumnDefinition(apply, column.getName(), column.getType());
apply.append(",").newLine();
}
writeColumnDefinition(apply, column.getName(), column.getType());
apply.append(",").newLine();
}
// TODO: We must apply also pending dropped columns. Let's do that in a later step
if (table.hasDroppedColumns()) {
@@ -34,11 +34,9 @@ public class HanaHistoryDdl extends DbTableBasedHistoryDdl implements PlatformHi
// create history table
Collection<MColumn> cols = table.allColumns();
for (MColumn column : cols) {
if (!column.isDraftOnly()) {
writeColumnDefinition(apply, column.getName(), column.getType(), column.getDefaultValue(), column.isNotnull(),
writeColumnDefinition(apply, column.getName(), column.getType(), column.getDefaultValue(), column.isNotnull(),
column.isIdentity() ? platformDdl.identitySuffix : null);
apply.append(",").newLine();
}
apply.append(",").newLine();
}
writeColumnDefinition(apply, systemPeriodStart, "TIMESTAMP", null, false, null);
apply.append(",").newLine();
@@ -93,8 +93,6 @@ public class CurrentModel {
ModelBuildBeanVisitor visitor = new ModelBuildBeanVisitor(context);
VisitAllUsing visit = new VisitAllUsing(visitor, server);
visit.visitAllBeans();
// adjust the foreign keys on the 'draft' tables
context.adjustDraftReferences();
}
return model;
}
@@ -47,8 +47,6 @@ public class MColumn {
*/
private AlterColumn alterColumn;
private boolean draftOnly;
private List<DbMigrationInfo> dbMigrationInfos;
public MColumn(Column column) {
@@ -91,7 +89,6 @@ public class MColumn {
*/
public MColumn copyForDraft() {
MColumn copy = new MColumn(name, type);
copy.draftOnly = draftOnly;
copy.checkConstraint = checkConstraint;
copy.checkConstraintName = checkConstraintName;
copy.defaultValue = defaultValue;
@@ -241,25 +238,11 @@ public class MColumn {
this.comment = comment;
}
/**
* Set the draftOnly status for this column.
*/
public void setDraftOnly(boolean draftOnly) {
this.draftOnly = draftOnly;
}
/**
* Return the draftOnly status for this column.
*/
public boolean isDraftOnly() {
return draftOnly;
}
/**
* Return true if this column should be included in History DB triggers etc.
*/
public boolean isIncludeInHistory() {
return !draftOnly && !historyExclude;
return !historyExclude;
}
public void clearForeignKey() {
@@ -29,12 +29,10 @@ public class MTable {
private static final System.Logger logger = AppLog.getLogger(MTable.class);
private String name;
private MTable draftTable;
/**
* Marked true for draft tables. These need to have their FK references adjusted
* after all the draft tables have been identified.
*/
private boolean draft;
private PartitionMeta partitionMeta;
private TablespaceMeta tablespaceMeta;
private String pkName;
@@ -107,25 +105,6 @@ public class MTable {
this.storageEngine = storageEngine;
}
/**
* Create a copy of this table structure as a 'draft' table.
* <p>
* Note that both tables contain @DraftOnly MColumns and these are filtered out
* later when creating the CreateTable object.
*/
public MTable createDraftTable() {
draftTable = new MTable(name + "_draft", this.tablespaceMeta, this.storageEngine);
draftTable.draft = true;
draftTable.whenCreatedColumn = whenCreatedColumn;
// compoundKeys
// compoundUniqueConstraints
draftTable.identityMode = identityMode;
for (MColumn col : allColumns()) {
draftTable.addColumn(col.copyForDraft());
}
return draftTable;
}
/**
* Construct for migration.
*/
@@ -142,7 +121,6 @@ public class MTable {
this.tablespaceMeta = null;
}
this.withHistory = Boolean.TRUE.equals(createTable.isWithHistory());
this.draft = Boolean.TRUE.equals(createTable.isDraft());
this.identityMode = fromCreateTable(createTable);
List<Column> cols = createTable.getColumn();
for (Column column : cols) {
@@ -220,14 +198,9 @@ public class MTable {
if (withHistory) {
createTable.setWithHistory(Boolean.TRUE);
}
if (draft) {
createTable.setDraft(Boolean.TRUE);
}
for (MColumn column : allColumns()) {
// filter out draftOnly columns from the base table
if (draft || !column.isDraftOnly()) {
createTable.getColumn().add(column.createColumn());
}
createTable.getColumn().add(column.createColumn());
}
for (MCompoundForeignKey compoundKey : compoundKeys) {
createTable.getForeignKey().add(compoundKey.createForeignKey());
@@ -282,10 +255,7 @@ public class MTable {
for (MColumn newColumn : newColumnMap.values()) {
MColumn localColumn = getColumn(newColumn.getName());
if (localColumn == null) {
// can ignore if draftOnly column and non-draft table
if (!newColumn.isDraftOnly() || draft) {
diffNewColumn(newColumn, newTable);
}
diffNewColumn(newColumn, newTable);
} else {
localColumn.compare(modelDiff, this, newColumn);
}
@@ -296,10 +266,6 @@ public class MTable {
MColumn newColumn = newColumnMap.get(existingColumn.getName());
if (newColumn == null) {
diffDropColumn(modelDiff, existingColumn);
} else if (newColumn.isDraftOnly() && !draft) {
// effectively a drop column (draft only column on a non-draft table)
logger.log(TRACE, "... drop column {0} from table {1} as now draftOnly", newColumn.getName(), name);
diffDropColumn(modelDiff, existingColumn);
}
}
@@ -425,13 +391,6 @@ public class MTable {
return pos == -1 ? null : name.substring(0, pos);
}
/**
* Return true if this table is a 'Draft' table.
*/
public boolean isDraft() {
return draft;
}
/**
* Return true if this table is partitioned.
*/
@@ -685,42 +644,6 @@ public class MTable {
return false;
}
/**
* Adjust the references (FK) if it should relate to a draft table.
*/
public void adjustReferences(ModelContainer modelContainer) {
Collection<MColumn> cols = allColumns();
for (MColumn col : cols) {
String references = col.getReferences();
if (references != null) {
String baseTable = extractBaseTable(references);
MTable refBaseTable = modelContainer.getTable(baseTable);
if (refBaseTable.draftTable != null) {
// change references to another associated 'draft' table
String newReferences = deriveReferences(references, refBaseTable.draftTable.getName());
col.setReferences(newReferences);
}
}
}
}
/**
* Return the base table name from references (table.column).
*/
private String extractBaseTable(String references) {
int lastDot = references.lastIndexOf('.');
return references.substring(0, lastDot);
}
/**
* Return the new references using the given draftTableName.
* (The referenced column is the same as before).
*/
private String deriveReferences(String references, String draftTableName) {
int lastDot = references.lastIndexOf('.');
return draftTableName + "." + references.substring(lastDot + 1);
}
/**
* This method adds information which columns are nullable or not to the compound indices.
*/
@@ -58,17 +58,6 @@ public class ModelContainer {
return partitionedTables;
}
/**
* Adjust the FK references on all the draft tables.
*/
public void adjustDraftReferences() {
for (MTable table : this.tables.values()) {
if (table.isDraft()) {
table.adjustReferences(this);
}
}
}
/**
* Return the map of all the tables.
*/
@@ -59,14 +59,6 @@ public class ModelBuildContext {
return new DefaultConstraintMaxLength(databasePlatform.maxConstraintNameLength());
}
/**
* Adjust the foreign key references on any draft tables (that reference other draft tables).
* This is called as a 'second pass' after all the draft tables have been identified.
*/
public void adjustDraftReferences() {
model.adjustDraftReferences();
}
public String normaliseTable(String baseTable) {
return constraintNaming.normaliseTable(baseTable);
}
@@ -170,51 +162,6 @@ public class ModelBuildContext {
return dbTypeMap.get(dbType);
}
/**
* Create the draft table for a given table.
*/
public void createDraft(MTable table, boolean draftable) {
MTable draftTable = table.createDraftTable();
draftTable.setPkName(primaryKeyName(draftTable.getName()));
if (draftable) {
// Add a FK from @Draftable live table back to it's draft table)
List<MColumn> pkCols = table.primaryKeyColumns();
if (pkCols.size() == 1) {
// only doing this for single column PK at this stage
MColumn pk = pkCols.get(0);
pk.setReferences(draftTable.getName() + "." + pk.getName());
pk.setForeignKeyName(foreignKeyConstraintName(table.getName(), pk.getName(), 0));
}
}
int fkCount = 0;
int ixCount = 0;
int uqCount = 0;
Collection<MColumn> cols = draftTable.allColumns();
for (MColumn col : cols) {
if (col.getForeignKeyName() != null) {
// Note that we adjust the 'references' table later in a second pass
// after we know all the tables that are 'draftable'
//col.setReferences(refTable + "." + refColumn);
col.setForeignKeyName(foreignKeyConstraintName(draftTable.getName(), col.getName(), ++fkCount));
String[] indexCols = {col.getName()};
col.setForeignKeyIndex(foreignKeyIndexName(draftTable.getName(), indexCols, ++ixCount));
}
// adjust the unique constraint names
if (col.getUnique() != null) {
col.setUnique(uniqueConstraintName(draftTable.getName(), col.getName(), ++uqCount));
}
if (col.getUniqueOneToOne() != null) {
col.setUniqueOneToOne(uniqueConstraintName(draftTable.getName(), col.getName(), ++uqCount));
}
}
addTable(draftTable);
}
/**
* Return a builder to add foreign keys.
*/
@@ -38,11 +38,6 @@ class ModelBuildIntersectionTable {
}
buildFkConstraints();
if (manyProp.targetDescriptor().isDraftable()) {
ctx.createDraft(intersectionTable, false);
}
return intersectionTable;
}
@@ -114,22 +114,9 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
}
}
addDraftTable();
table.updateCompoundIndices();
}
/**
* Create a 'draft' table that is mostly the same as the base table.
* It has @DraftOnly columns and adjusted primary and foreign keys.
*/
private void addDraftTable() {
if (beanDescriptor.isDraftable() || beanDescriptor.isDraftableElement()) {
// create a 'Draft' table which looks very similar (change PK, FK etc)
ctx.createDraft(table, !beanDescriptor.isDraftableElement());
}
}
@Override
public void visitMany(BeanPropertyAssocMany<?> p) {
if (p.createJoinTable()) {
@@ -251,7 +238,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
MColumn col = table.addColumnScalar(p.dbColumn(), ctx.getColumnDefn(p, false));
//MColumn col = new MColumn(p.dbColumn(), ctx.getColumnDefn(p, false));
col.setComment(p.dbComment());
col.setDraftOnly(p.isDraftOnly());
col.setHistoryExclude(p.isExcludedFromHistory());
if (p.isId() || p.isImportedPrimaryKey()) {
col.setPrimaryKey(true);
@@ -523,14 +523,6 @@ public abstract class TQRootBean<T, R> {
return root;
}
/**
* Execute the query against the draft set of tables.
*/
public R asDraft() {
query.asDraft();
return root;
}
/**
* Execute the query including soft deleted rows.
*/
@@ -78,7 +78,7 @@ public class PlatformNoGeneratedKeysTest {
assertThat(d0.getId()).isNotNull();
server.publish(BasicDraftableBean.class, d0.getId());
//server.publish(BasicDraftableBean.class, d0.getId());
BasicDraftableBean one = server.find(BasicDraftableBean.class, d0.getId());
@@ -476,46 +476,6 @@ public class TDSpiEbeanServer extends TDSpiServer implements SpiEbeanServer {
public void register(TransactionCallback transactionCallback) throws PersistenceException {
}
@Override
public <T> T publish(Class<T> beanType, Object id) {
return null;
}
@Override
public <T> List<T> publish(Query<T> query) {
return null;
}
@Override
public <T> T publish(Class<T> beanType, Object id, Transaction transaction) {
return null;
}
@Override
public <T> List<T> publish(Query<T> query, Transaction transaction) {
return null;
}
@Override
public <T> T draftRestore(Class<T> beanType, Object id, Transaction transaction) {
return null;
}
@Override
public <T> List<T> draftRestore(Query<T> query, Transaction transaction) {
return null;
}
@Override
public <T> T draftRestore(Class<T> beanType, Object id) {
return null;
}
@Override
public <T> List<T> draftRestore(Query<T> query) {
return null;
}
@Override
public Transaction createTransaction() {
return null;
@@ -508,46 +508,6 @@ public class TDSpiServer implements SpiServer {
return null;
}
@Override
public <T> T publish(Class<T> beanType, Object id, Transaction transaction) {
return null;
}
@Override
public <T> T publish(Class<T> beanType, Object id) {
return null;
}
@Override
public <T> List<T> publish(Query<T> query, Transaction transaction) {
return null;
}
@Override
public <T> List<T> publish(Query<T> query) {
return null;
}
@Override
public <T> T draftRestore(Class<T> beanType, Object id, Transaction transaction) {
return null;
}
@Override
public <T> T draftRestore(Class<T> beanType, Object id) {
return null;
}
@Override
public <T> List<T> draftRestore(Query<T> query, Transaction transaction) {
return null;
}
@Override
public <T> List<T> draftRestore(Query<T> query) {
return null;
}
@Override
public <T> Set<String> validateQuery(Query<T> query) {
return null;
@@ -14,19 +14,11 @@ public class FlagsTest {
int state = 0;
state = Flags.setPublish(state);
assertThat(Flags.isSet(state, Flags.PUBLISH)).isTrue();
state = Flags.setMerge(state);
state = Flags.setInsert(state);
assertThat(Flags.isSet(state, Flags.PUBLISH)).isTrue();
assertThat(Flags.isSet(state, Flags.MERGE)).isTrue();
assertThat(Flags.isSet(state, Flags.INSERT)).isTrue();
state = Flags.unsetPublish(state);
assertThat(Flags.isSet(state, Flags.PUBLISH)).isFalse();
assertThat(Flags.isSet(state, Flags.MERGE)).isTrue();
assertThat(Flags.isSet(state, Flags.INSERT)).isTrue();
}
@Test
@@ -72,15 +64,11 @@ public class FlagsTest {
@Test
public void isPublishOrMerge() {
assertThat(Flags.isPublishMergeOrNormal(0)).isFalse();
assertThat(Flags.isPublishMergeOrNormal(Flags.INSERT)).isFalse();
assertThat(Flags.isPublishMergeOrNormal(Flags.RECURSE)).isFalse();
assertThat(Flags.isMergeOrNormal(0)).isFalse();
assertThat(Flags.isMergeOrNormal(Flags.INSERT)).isFalse();
assertThat(Flags.isMergeOrNormal(Flags.RECURSE)).isFalse();
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.isPublishMergeOrNormal(mergePublish)).isTrue();
assertThat(Flags.isMergeOrNormal(Flags.MERGE)).isTrue();
assertThat(Flags.isMergeOrNormal(Flags.NORMAL)).isTrue();
}
}
@@ -10,14 +10,11 @@ import jakarta.persistence.OneToMany;
import java.util.List;
@Entity
@Draftable
public class DefaultsModel {
@Id
Integer id;
@Draft
boolean draft;
@OneToMany(cascade = CascadeType.ALL)
List<ReferencedDefaultsModel> relatedModels;
@@ -37,12 +34,4 @@ public class DefaultsModel {
public void setRelatedModels(final List<ReferencedDefaultsModel> relatedModels) {
this.relatedModels = relatedModels;
}
public boolean isDraft() {
return draft;
}
public void setDraft(final boolean draft) {
this.draft = draft;
}
}
@@ -27,13 +27,13 @@ public class TestDefaults extends BaseTestCase {
assertThat(current).isNotEmpty();
if (isMySql() || isMariaDB() || isOracle()) {
assertThat(current.get(0)).contains("insert into defaults_model_draft values (default);");
assertThat(current.get(0)).contains("insert into defaults_model values (default);");
} else if (isDb2()) {
assertThat(current.get(0)).contains("insert into defaults_model_draft (id) values (default)");
assertThat(current.get(0)).contains("insert into defaults_model (id) values (default)");
} else if (isSqlServer()) {
assertThat(current.get(0)).contains("insert into defaults_model_draft (id) values (?)");
assertThat(current.get(0)).contains("insert into defaults_model (id) values (?)");
} else {
assertThat(current.get(0)).contains("insert into defaults_model_draft default values;");
assertThat(current.get(0)).contains("insert into defaults_model default values;");
}
}
@@ -24,7 +24,7 @@ public class DocLinkTest extends BaseTestCase {
Link link1 = new Link("something");
link1.save();
DB.getDefault().publish(Link.class, link1.getId());
//DB.getDefault().publish(Link.class, link1.getId());
Link link = DB.find(Link.class)
.setId(link1.getId())
@@ -50,7 +50,7 @@ public class DocLinkTest extends BaseTestCase {
assertThat(link1.isDraft()).isFalse();
link1.save();
assertThat(link1.isDraft()).isTrue();
//assertThat(link1.isDraft()).isTrue();
// perform stateless update
Link linkUpdate = new Link();
@@ -73,7 +73,7 @@ public class DocLinkTest extends BaseTestCase {
assertThat(link1.isDraft()).isFalse();
link1.save();
assertThat(link1.isDraft()).isTrue();
//assertThat(link1.isDraft()).isTrue();
link1.setComment("some change");
link1.save();
@@ -86,74 +86,36 @@ public class DocLinkTest extends BaseTestCase {
Link link1 = new Link("Ld2");
link1.save();
DB.getDefault().publish(Link.class, link1.getId());
//DB.getDefault().publish(Link.class, link1.getId());
Link link = DB.find(Link.class).setId(link1.getId()).asDraft().findOne();
Link link = DB.find(Link.class).setId(link1.getId()).findOne(); //.asDraft()
DB.deletePermanent(link);
}
@Test
public void testDeleteLivePermanent_throwsException() {
Link link1 = new Link("Ld2");
link1.save();
Link live = DB.getDefault().publish(Link.class, link1.getId());
try {
DB.deletePermanent(live);
fail("never get here");
} catch (PersistenceException e) {
// assert nice message when trying to delete live bean
assertThat(e.getMessage()).contains("Explicit Delete is not allowed on a 'live' bean - only draft beans");
}
}
@Test
public void testDelete_whenPublished() {
Link link1 = new Link("Ld2");
link1.save();
Database server = DB.getDefault();
server.publish(Link.class, link1.getId());
//server.publish(Link.class, link1.getId());
link1 = DB.find(Link.class).setId(link1.getId()).asDraft().findOne();
assertThat(link1.isDraft()).isTrue();
link1 = DB.find(Link.class).setId(link1.getId()).findOne(); //.asDraft()
// assertThat(link1.isDraft()).isTrue();
// this is a soft delete (no automatic publish here, only updates draft)
link1.delete();
Link live = DB.find(Link.class).setId(link1.getId()).findOne();
assertThat(live).isNotNull();
assertThat(live.isDraft()).isFalse();
assertThat(live.isDeleted()).isFalse(); // soft delete state not published yet
// this is a permanent delete (effectively has automatic publish)
server.deletePermanent(link1);
live = DB.find(Link.class).setId(link1.getId()).findOne();
assertThat(live).isNull();
}
@Test
public void testUpdateLive_throwsException() {
Link link1 = new Link("forUpdateLive");
link1.save();
Link live = DB.getDefault().publish(Link.class, link1.getId());
live.setComment("foo");
// Expect a nice
try {
live.save();
fail("Never get here");
} catch (PersistenceException e) {
// we want to assert the message is nice and meaningful (and not a optimistic locking exception etc)
assertThat(e.getMessage()).contains("Save or update is not allowed on a 'live' bean - only draft beans");
}
// //assertThat(live.isDraft()).isFalse();
// assertThat(live.isDeleted()).isFalse(); // soft delete state not published yet
//
// // this is a permanent delete (effectively has automatic publish)
// server.deletePermanent(link1);
//
// live = DB.find(Link.class).setId(link1.getId()).findOne();
// assertThat(live).isNull();
}
@Test
@@ -166,19 +128,19 @@ public class DocLinkTest extends BaseTestCase {
link1.setWhenPublish(when);
link1.save();
Link draft1 = DB.find(Link.class).setId(link1.getId()).asDraft().findOne();
assertThat(draft1.isDirty()).isTrue();
Link draft1 = DB.find(Link.class).setId(link1.getId()).findOne(); // .asDraft()
//assertThat(draft1.isDirty()).isTrue();
Database server = DB.getDefault();
Link linkLive = server.publish(Link.class, link1.getId(), null);
Link linkLive = draft1;//server.publish(Link.class, link1.getId(), null);
assertThat(linkLive.getComment()).isEqualTo(comment);
assertThat(linkLive.getWhenPublish()).isEqualToIgnoringMillis(when);
Link draft1b = DB.find(Link.class).setId(link1.getId()).asDraft().findOne();
assertThat(draft1b.isDirty()).isFalse();
assertThat(draft1b.getComment()).isNull();
assertThat(draft1b.getWhenPublish()).isNull();
// Link draft1b = DB.find(Link.class).setId(link1.getId()).findOne(); // .asDraft()
// assertThat(draft1b.isDirty()).isFalse();
// assertThat(draft1b.getComment()).isNull();
// assertThat(draft1b.getWhenPublish()).isNull();
}
@Test
@@ -194,9 +156,9 @@ public class DocLinkTest extends BaseTestCase {
link3.save();
Database server = DB.getDefault();
server.publish(Link.class, link1.getId(), null);
server.publish(Link.class, link2.getId(), null);
server.publish(Link.class, link3.getId(), null);
// server.publish(Link.class, link1.getId(), null);
// server.publish(Link.class, link2.getId(), null);
// server.publish(Link.class, link3.getId(), null);
Doc doc1 = new Doc("DocOne");
doc1.getLinks().add(link1);
@@ -205,12 +167,12 @@ public class DocLinkTest extends BaseTestCase {
Doc draftDoc1 = server.find(Doc.class)
.setId(doc1.getId())
.asDraft()
//.asDraft()
.findOne();
assertThat(draftDoc1.getLinks()).hasSize(2);
Doc liveDoc1 = server.publish(Doc.class, doc1.getId(), null);
Doc liveDoc1 = doc1; // server.publish(Doc.class, doc1.getId(), null);
assertThat(liveDoc1.getLinks()).hasSize(2);
assertThat(liveDoc1.getLinks()).extracting("id").contains(link1.getId(), link2.getId());
@@ -223,7 +185,7 @@ public class DocLinkTest extends BaseTestCase {
draftDoc1.save();
// publish with insert and delete of Links M2M relationship
Doc liveDoc2 = server.publish(Doc.class, doc1.getId(), null);
Doc liveDoc2 = draftDoc1;// server.publish(Doc.class, doc1.getId(), null);
assertThat(liveDoc2.getLinks()).hasSize(2);
assertThat(liveDoc2.getLinks()).extracting("id").contains(remaining.getId(), link3.getId());
@@ -241,25 +203,25 @@ public class DocLinkTest extends BaseTestCase {
Database server = DB.getDefault();
Link live = server.publish(Link.class, link1.getId(), null);
Link live = link1;//server.publish(Link.class, link1.getId(), null);
assertThat(live.isDraft()).isFalse();
Link draftLink = DB.find(Link.class)
.setId(link1.getId())
.asDraft()
//.asDraft()
.findOne();
draftLink.setLocation("secondLocation");
draftLink.save();
server.draftRestore(Link.class, link1.getId(), null);
// server.draftRestore(Link.class, link1.getId(), null);
draftLink = DB.find(Link.class)
.setId(link1.getId())
.asDraft()
//.asDraft()
.findOne();
assertThat(draftLink.getLocation()).isEqualTo("firstLocation");
assertThat(draftLink.getLocation()).isEqualTo("secondLocation");//"firstLocation");
}
@Test
@@ -272,11 +234,11 @@ public class DocLinkTest extends BaseTestCase {
Database server = DB.getDefault();
server.publish(Link.class, link1.getId(), null);
//server.publish(Link.class, link1.getId(), null);
Link draftLink = DB.find(Link.class)
.setId(link1.getId())
.asDraft()
//.asDraft()
.findOne();
draftLink.setLocation("secondLocation");
@@ -284,11 +246,11 @@ public class DocLinkTest extends BaseTestCase {
draftLink.save();
Query<Link> query = server.find(Link.class).where().eq("id", link1.getId()).query();
List<Link> links = server.draftRestore(query);
List<Link> links = query.findList();//server.draftRestore(query);
assertThat(links).hasSize(1);
assertThat(links.get(0).getLocation()).isEqualTo("firstLocation");
assertThat(links.get(0).isDirty()).isEqualTo(false);
assertThat(links.get(0).getComment()).isNull();
assertThat(links.get(0).getLocation()).isEqualTo("secondLocation");//"firstLocation");
//assertThat(links.get(0).isDirty()).isEqualTo(false);
// assertThat(links.get(0).getComment()).isNull();
}
}
@@ -34,7 +34,7 @@ public class LinkQueryPublishTest {
ids.add(link3.getId());
PagedList<Link> pagedList =
server.find(Link.class).asDraft()
server.find(Link.class)//.asDraft()
.where().idIn(ids)
.setMaxRows(10)
.findPagedList();
@@ -48,7 +48,7 @@ public class LinkQueryPublishTest {
.order().asc("id");
List<Link> pubList = server.publish(pubQuery);
List<Link> pubList = pubQuery.findList(); // server.publish(pubQuery);
assertThat(pubList).hasSize(3);
assertThat(pubList).extracting("id").contains(link1.getId(), link2.getId(), link3.getId());
@@ -37,25 +37,18 @@ public class OrganisationTest {
Database server = DB.getDefault();
Document draftDoc = server.find(Document.class)
.asDraft()
//.asDraft()
.setId(doc.getId())
.findOne();
assertNotNull(draftDoc);
Document liveDoc = server.find(Document.class)
.setId(doc.getId())
.findOne();
assertNull(liveDoc);
server.publish(Document.class, doc.getId(), null);
//server.publish(Document.class, doc.getId(), null);
doc.setTitle("Mod1");
doc.save();
server.publish(Document.class, doc.getId(), null);
//server.publish(Document.class, doc.getId(), null);
}
@@ -77,9 +70,9 @@ public class OrganisationTest {
Database server = DB.getDefault();
server.publish(Document.class, doc.getId(), null);
//server.publish(Document.class, doc.getId(), null);
Document fetchDoc = DB.find(Document.class).setId(doc.getId()).asDraft().findOne();
Document fetchDoc = DB.find(Document.class).setId(doc.getId()).findOne(); //.asDraft()
List<DocumentMedia> media = fetchDoc.getMedia();
assertThat(media.size()).isEqualTo(2);
@@ -97,7 +90,7 @@ public class OrganisationTest {
// publish will perform an insert, update and delete on child DocumentMedia
// during the publish below with media1 being deleted
Document liveBean = server.publish(Document.class, doc.getId(), null);
Document liveBean = doc;//server.publish(Document.class, doc.getId(), null);
assertThat(liveBean.getBody()).isEqualTo("Body2");
assertThat(liveBean.getMedia().size()).isEqualTo(2);
assertThat(liveBean.getMedia()).extracting("name").contains("media2", "media3");
@@ -16,8 +16,10 @@ public class TestInsertCheckUnique extends BaseTestCase {
@BeforeEach
public void clearDb() {
DB.find(Document.class).asDraft().where().contains("title", "UniqueKey").delete();
DB.find(Document.class).asDraft().where().isNull("title").delete();
DB.find(Document.class)//.asDraft()
.where().contains("title", "UniqueKey").delete();
DB.find(Document.class)//.asDraft()
.where().isNull("title").delete();
}
@Test
@@ -35,10 +37,6 @@ public class TestInsertCheckUnique extends BaseTestCase {
doc2.setTitle("AUniqueKey_duplicateCheck");
doc2.setBody("clashes with doc1");
assertThat(DB.checkUniqueness(doc2)).isEmpty();
DB.getDefault().publish(doc1.getClass(), doc1.getId());
assertThat(DB.checkUniqueness(doc2).toString()).contains("title");
}
}
@@ -59,12 +57,11 @@ public class TestInsertCheckUnique extends BaseTestCase {
assertThat(DB.checkUniqueness(doc2)).isEmpty();
DB.getDefault().publish(doc1.getClass(), doc1.getId());
assertThat(DB.checkUniqueness(doc2)).isEmpty();
//DB.getDefault().publish(doc1.getClass(), doc1.getId());
//assertThat(DB.checkUniqueness(doc2)).isEmpty();
doc2.save();
DB.getDefault().publish(doc2.getClass(), doc2.getId());
//DB.getDefault().publish(doc2.getClass(), doc2.getId());
}
}
@@ -77,7 +74,7 @@ public class TestInsertCheckUnique extends BaseTestCase {
doc1.setBody("one");
doc1.save();
DB.getDefault().publish(doc1.getClass(), doc1.getId());
//DB.getDefault().publish(doc1.getClass(), doc1.getId());
Document doc2 = new Document();
doc2.setTitle("One flew over the cuckoo's nest");
@@ -21,7 +21,9 @@ public class TestInsertDuplicateKey extends BaseTestCase {
@BeforeEach
public void clearDb() {
server().find(Document.class).asDraft().where().contains("title", "UniqueKey").delete();
server().find(Document.class)
//.asDraft()
.where().contains("title", "UniqueKey").delete();
}
@Test
@@ -64,7 +66,7 @@ public class TestInsertDuplicateKey extends BaseTestCase {
List<Document> found = DB.getDefault()
.find(Document.class)
.asDraft()
//.asDraft()
.where().startsWith("body", "insertTheBatch_duplicateKey_catchAndContinue")
.findList();
@@ -35,12 +35,8 @@ public class Document extends BaseDomain {
@ManyToOne
Organisation organisation;
/**
* Relationship to draftable elements.
*/
//@PrivateOwned
@OneToMany(mappedBy = "document")//, cascade = CascadeType.ALL)
List<DocumentMedia> media;
@OneToMany(mappedBy = "document", cascade = CascadeType.ALL)
List<DocumentMedia> media;
public String getTitle() {
return title;
@@ -96,7 +92,7 @@ public class Document extends BaseDomain {
}
public Document asDraft(Long id) {
return query().asDraft().setId(id).findOne();
return query().setId(id).findOne(); //.asDraft()
}
}
}
@@ -34,7 +34,6 @@ public class TestTransactionTryResources extends BaseTestCase {
Document document = Document.find.asDraft(doc.getId());
assertThat(document).isNotNull();
assertThat(document.isDraft()).isTrue();
// cleanup
DB.delete(document);
@@ -69,7 +68,6 @@ public class TestTransactionTryResources extends BaseTestCase {
List<Document> docs = Document.find.query()
.where().startsWith("body", "tryWithResources_catch")
.asDraft()
.findList();
assertThat(docs).hasSize(1);