Skip to content

Commit

Permalink
Blazebit#414 - Implemented query flushing
Browse files Browse the repository at this point in the history
  • Loading branch information
beikov committed Jul 27, 2017
1 parent 36a9e35 commit 73bf10c
Show file tree
Hide file tree
Showing 374 changed files with 2,596 additions and 8,466 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,14 @@ public interface JpaProvider {
*/
public boolean supportsForeignAssociationInOnClause();

/**
* Indicates whether an embeddable can be set via an update queries SET clause.
* Although the JPA spec mandates this, it doesn't seem to be asserted so some providers don't support it.
*
* @return true if supported, else false
*/
public boolean supportsUpdateSetEmbeddable();


/**
* Indicates if the provider supports the use of transient entity objects as parameters.
Expand Down Expand Up @@ -340,7 +348,6 @@ public interface JpaProvider {
* The possible locations of a constraint.
*
* @author Christian Beikov
* @since 1.2.0
*/
public static enum ConstraintType {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,16 @@ e.g. `com.blazebit.persistence.view.batch_correlation_values.subProperty`
| Type | boolean
| Default | true
| Applicable | Always
|====================
|====================

==== UPDATER_EAGER_LOADING

// TODO: document

==== UPDATER_FLUSH_MODE

// TODO: document

==== UPDATER_FLUSH_STRATEGY

// TODO: document
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
public final class ConfigurationProperties {

/**
* We added a flag to make it possible to use the generated proxies with serialization.
* A boolean flag to make it possible to use the generated proxies with serialization.
* When deserializing an instance the class might not have been loaded yet, so we can force loading
* proxy classes on startup to avoid this problem.
* By default the eager loading of proxies is disabled to have a better startup performance.
Expand All @@ -34,23 +34,23 @@ public final class ConfigurationProperties {
*/
public static final String PROXY_EAGER_LOADING = "com.blazebit.persistence.view.proxy.eager_loading";
/**
* We added a flag to make it possible to prepare all view template caches on startup.
* A boolean flag to make it possible to prepare all view template caches on startup.
* By default the eager loading of the view templates is disabled to have a better startup performance.
* Valid values for this property are <code>true</code> or <code>false</code>.
*
* @since 1.2.0
*/
public static final String TEMPLATE_EAGER_LOADING = "com.blazebit.persistence.view.eager_loading";
/**
* We added a flag to make it possible to disable unsafe proxy generation.
* A boolean flag to make it possible to disable unsafe proxy generation.
* By default the unsafe proxies are allowed to be able to make use of the features.
* Valid values for this property are <code>true</code> or <code>false</code>.
*
* @since 1.0.6
*/
public static final String PROXY_UNSAFE_ALLOWED = "com.blazebit.persistence.view.proxy.unsafe_allowed";
/**
* We added a flag to make it possible to disable the expression validation.
* A boolean flag to make it possible to disable the expression validation.
* By default the expression validation is enabled, but since the validation is not bullet proof, it can be disabled.
* Valid values for this property are <code>true</code> or <code>false</code>.
*
Expand Down Expand Up @@ -79,13 +79,37 @@ public final class ConfigurationProperties {
*/
public static final String EXPECT_BATCH_CORRELATION_VALUES = "com.blazebit.persistence.view.batch_correlation_values";
/**
* We added a flag to make it possible to prepare the entity view updater cache on startup.
* A boolean flag to make it possible to prepare the entity view updater cache on startup.
* By default the eager loading of entity view updates is disabled to have a better startup performance.
* Valid values for this property are <code>true</code> or <code>false</code>.
*
* @since 1.2.0
*/
public static final String UPDATER_EAGER_LOADING = "com.blazebit.persistence.view.updater.eager_loading";
/**
* An override for the flush mode of updatable entity views.
* By default, the property is not set. This has the effect, that the flush modes configured for the respective updatable entity views are used.
* Valid values for this property are <code>partial</code>, <code>lazy</code> or <code>full</code>.
*
* To specify an override for a specific entity view, append the fully qualified entity view class name after the "flush_mode" like
* e.g. <code>com.blazebit.persistence.view.updater.flush_mode.com.mypackage.views.MyView</code>
*
* @since 1.2.0
* @see com.blazebit.persistence.view.FlushMode
*/
public static final String UPDATER_FLUSH_MODE = "com.blazebit.persistence.view.updater.flush_mode";
/**
* An override for the flush strategy of updatable entity views.
* By default, the property is not set. This has the effect, that the flush strategies configured for the respective updatable entity views are used.
* Valid values for this property are <code>auto</code>, <code>entity</code> or <code>query</code>.
*
* To specify an override for a specific entity view, append the fully qualified entity view class name after the "flush_strategy" like
* e.g. <code>com.blazebit.persistence.view.updater.flush_strategy.com.mypackage.views.MyView</code>
*
* @since 1.2.0
* @see com.blazebit.persistence.view.FlushStrategy
*/
public static final String UPDATER_FLUSH_STRATEGY = "com.blazebit.persistence.view.updater.flush_strategy";

private ConfigurationProperties() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ public EntityViewManagerImpl(EntityViewConfigurationImpl config, CriteriaBuilder
ExpressionFactory expressionFactory = cbf.getService(ExpressionFactory.class);

MetamodelBuildingContext context = new MetamodelBuildingContextImpl(
config.getProperties(),
new DefaultBasicUserTypeRegistry(config.getUserTypeRegistry(), cbf),
cbf.getService(EntityMetamodel.class),
jpaProvider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.blazebit.persistence.view.metamodel.FlatViewType;
import com.blazebit.persistence.view.metamodel.Type;

import javax.persistence.Query;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
Expand Down Expand Up @@ -127,6 +128,11 @@ public <T extends DirtyAttributeFlusher<T, E, V>, E, V> DirtyAttributeFlusher<T,
return null;
}

@Override
public Query createUpdateQuery(UpdateContext context, Object view, DirtyAttributeFlusher<?, ?, ?> nestedGraphNode) {
return null;
}

protected Object persist(UpdateContext context, Object entity, Object view) {
if (persistAllowed) {
Class<?> viewTypeClass = getViewTypeClass(view);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.blazebit.persistence.view.impl.update.flush.DirtyAttributeFlusher;
import com.blazebit.persistence.view.metamodel.Type;

import javax.persistence.Query;
import java.util.Set;

/**
Expand Down Expand Up @@ -107,4 +108,15 @@ public ViewAttributeAccessor getViewIdAccessor() {
public EntityAttributeAccessor getEntityIdAccessor() {
return idAccessor == null ? null : ReadOnlyEntityIdAccessor.INSTANCE;
}

@Override
public Query createUpdateQuery(UpdateContext context, Object view, DirtyAttributeFlusher<?, ?, ?> nestedGraphNode) {
Class<?> viewTypeClass = getViewTypeClass(view);
EntityViewUpdater updater = updateUpdater.get(viewTypeClass);
if (updater == null) {
return null;
}

return updater.createUpdateQuery(context, (MutableStateTrackable) view, nestedGraphNode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import com.blazebit.persistence.view.impl.update.flush.DirtyAttributeFlusher;
import com.blazebit.persistence.view.impl.update.flush.FetchGraphNode;

import javax.persistence.Query;

/**
*
* @author Christian Beikov
Expand All @@ -37,4 +39,5 @@ public interface ViewToEntityMapper {

public EntityAttributeAccessor getEntityIdAccessor();

public Query createUpdateQuery(UpdateContext context, Object view, DirtyAttributeFlusher<?, ?, ?> nestedGraphNode);
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ public ManagedViewTypeImpl(ViewMapping viewMapping, MetamodelBuildingContext con
CreatableEntityView creatableEntityView = AnnotationUtils.findAnnotation(getJavaType(), CreatableEntityView.class);
if (updatableEntityView != null) {
this.updatable = true;
this.flushMode = updatableEntityView.mode();
this.flushStrategy = updatableEntityView.strategy();
this.flushMode = context.getFlushMode(javaType, updatableEntityView.mode());
this.flushStrategy = context.getFlushStrategy(javaType, updatableEntityView.strategy());
} else {
this.updatable = false;
this.flushMode = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import com.blazebit.persistence.impl.expression.ExpressionFactory;
import com.blazebit.persistence.spi.JpaProvider;
import com.blazebit.persistence.spi.JpqlFunction;
import com.blazebit.persistence.view.FlushMode;
import com.blazebit.persistence.view.FlushStrategy;
import com.blazebit.persistence.view.impl.proxy.ProxyFactory;
import com.blazebit.persistence.view.metamodel.Type;

Expand Down Expand Up @@ -49,6 +51,10 @@ public interface MetamodelBuildingContext {

public ProxyFactory getProxyFactory();

public FlushMode getFlushMode(Class<?> clazz, FlushMode defaultValue);

public FlushStrategy getFlushStrategy(Class<?> clazz, FlushStrategy defaultValue);

public void addError(String error);

public boolean hasErrors();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import com.blazebit.persistence.impl.expression.MacroFunction;
import com.blazebit.persistence.spi.JpaProvider;
import com.blazebit.persistence.spi.JpqlFunction;
import com.blazebit.persistence.view.FlushMode;
import com.blazebit.persistence.view.FlushStrategy;
import com.blazebit.persistence.view.impl.ConfigurationProperties;
import com.blazebit.persistence.view.impl.JpqlMacroAdapter;
import com.blazebit.persistence.view.impl.MacroConfigurationExpressionFactory;
import com.blazebit.persistence.view.impl.macro.DefaultViewRootJpqlMacro;
Expand All @@ -35,6 +38,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
Expand All @@ -54,7 +58,12 @@ public class MetamodelBuildingContextImpl implements MetamodelBuildingContext {
private final Set<Class<?>> entityViewClasses;
private final Set<String> errors;

public MetamodelBuildingContextImpl(BasicUserTypeRegistry basicUserTypeRegistry, EntityMetamodel entityMetamodel, JpaProvider jpaProvider, Map<String, JpqlFunction> jpqlFunctions, ExpressionFactory expressionFactory, ProxyFactory proxyFactory, Set<Class<?>> entityViewClasses, Set<String> errors) {
private final FlushMode flushModeOverride;
private final Map<String, FlushMode> flushModeOverrides;
private final FlushStrategy flushStrategyOverride;
private final Map<String, FlushStrategy> flushStrategyOverrides;

public MetamodelBuildingContextImpl(Properties properties, BasicUserTypeRegistry basicUserTypeRegistry, EntityMetamodel entityMetamodel, JpaProvider jpaProvider, Map<String, JpqlFunction> jpqlFunctions, ExpressionFactory expressionFactory, ProxyFactory proxyFactory, Set<Class<?>> entityViewClasses, Set<String> errors) {
this.basicUserTypeRegistry = basicUserTypeRegistry;
this.entityMetamodel = entityMetamodel;
this.jpaProvider = jpaProvider;
Expand All @@ -63,6 +72,80 @@ public MetamodelBuildingContextImpl(BasicUserTypeRegistry basicUserTypeRegistry,
this.proxyFactory = proxyFactory;
this.entityViewClasses = entityViewClasses;
this.errors = errors;
this.flushModeOverride = getFlushMode(properties.getProperty(ConfigurationProperties.UPDATER_FLUSH_MODE), "global property '" + ConfigurationProperties.UPDATER_FLUSH_MODE + "'");
this.flushModeOverrides = getFlushModeOverrides(properties);
this.flushStrategyOverride = getFlushStrategy(properties.getProperty(ConfigurationProperties.UPDATER_FLUSH_STRATEGY), "global property '" + ConfigurationProperties.UPDATER_FLUSH_STRATEGY + "'");
this.flushStrategyOverrides = getFlushStrategyOverrides(properties);
}

private FlushMode getFlushMode(String property, String location) {
if (property == null || property.isEmpty()) {
return null;
}

if ("partial".equals(property)) {
return FlushMode.PARTIAL;
} else if ("lazy".equals(property)) {
return FlushMode.LAZY;
} else if ("full".equals(property)) {
return FlushMode.FULL;
}

throw new IllegalArgumentException("Invalid flush mode defined for " + location + ": " + property);
}

private Map<String, FlushMode> getFlushModeOverrides(Properties properties) {
String prefix = ConfigurationProperties.UPDATER_FLUSH_MODE + ".";
Map<String, FlushMode> flushModes = new HashMap<>();
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
String key = (String) entry.getKey();
if (key.startsWith(prefix) && entry.getValue() != null) {
Object value = entry.getValue();
FlushMode mode;
if (value instanceof FlushMode) {
mode = (FlushMode) value;
} else {
mode = getFlushMode(entry.getValue().toString(), "property '" + key + "'");
}
flushModes.put(key.substring(prefix.length()), mode);
}
}
return flushModes;
}

private FlushStrategy getFlushStrategy(String property, String location) {
if (property == null || property.isEmpty()) {
return null;
}

if ("auto".equals(property)) {
return FlushStrategy.AUTO;
} else if ("query".equals(property)) {
return FlushStrategy.QUERY;
} else if ("entity".equals(property)) {
return FlushStrategy.ENTITY;
}

throw new IllegalArgumentException("Invalid flush strategy defined for " + location + ": " + property);
}

private Map<String, FlushStrategy> getFlushStrategyOverrides(Properties properties) {
String prefix = ConfigurationProperties.UPDATER_FLUSH_STRATEGY + ".";
Map<String, FlushStrategy> flushStrategies = new HashMap<>();
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
String key = (String) entry.getKey();
if (key.startsWith(prefix) && entry.getValue() != null) {
Object value = entry.getValue();
FlushStrategy strategy;
if (value instanceof FlushStrategy) {
strategy = (FlushStrategy) value;
} else {
strategy = getFlushStrategy(entry.getValue().toString(), "property '" + key + "'");
}
flushStrategies.put(key.substring(prefix.length()), strategy);
}
}
return flushStrategies;
}

@Override
Expand Down Expand Up @@ -120,6 +203,32 @@ public ProxyFactory getProxyFactory() {
return proxyFactory;
}

@Override
public FlushMode getFlushMode(Class<?> clazz, FlushMode defaultValue) {
if (flushModeOverride != null) {
return flushModeOverride;
}
FlushMode mode = flushModeOverrides.get(clazz.getName());
if (mode != null) {
return mode;
} else {
return defaultValue;
}
}

@Override
public FlushStrategy getFlushStrategy(Class<?> clazz, FlushStrategy defaultValue) {
if (flushStrategyOverride != null) {
return flushStrategyOverride;
}
FlushStrategy mode = flushStrategyOverrides.get(clazz.getName());
if (mode != null) {
return mode;
} else {
return defaultValue;
}
}

@Override
public void addError(String error) {
errors.add(error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ public static ViewMapping initializeViewMappings(Class<?> entityViewRootClass, C
}

EntityView entityView = AnnotationUtils.findAnnotation(entityViewClass, EntityView.class);
if (entityView == null) {
context.addError("No entity view annotation found on type: " + entityViewClass.getName());
return null;
}
Class<?> entityClass = entityView.value();
ManagedType<?> managedType = context.getEntityMetamodel().managedType(entityClass);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,8 @@ private CtMethod addGetter(CtClass cc, CtField field, String methodName, Class<?
return addGetter(cc, field, methodName, Descriptor.toJvmName(returnType.getName()), false);
} else {
try {
return addGetter(cc, field, methodName, Descriptor.of(returnType.getName()), !returnType.isPrimitive() && field.getType().isPrimitive());

return addGetter(cc, field, methodName, Descriptor.of(returnType.getName()), !returnType.isPrimitive() && field != null && field.getType().isPrimitive());
} catch (NotFoundException e) {
throw new CannotCompileException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import com.blazebit.persistence.view.impl.update.flush.DirtyAttributeFlusher;
import com.blazebit.persistence.view.impl.update.flush.FetchGraphNode;

import javax.persistence.Query;

/**
*
* @author Christian Beikov
Expand All @@ -37,5 +39,6 @@ public interface EntityViewUpdater {
public Object executeUpdate(UpdateContext context, Object entity, MutableStateTrackable updatableProxy);

public Object executePersist(UpdateContext context, MutableStateTrackable updatableProxy);


public Query createUpdateQuery(UpdateContext context, MutableStateTrackable view, DirtyAttributeFlusher<?, ?, ?> nestedGraphNode);
}
Loading

0 comments on commit 73bf10c

Please sign in to comment.