Skip to content

Commit

Permalink
[Blazebit#681] Allow multiple non-cascading parents for updatable ent…
Browse files Browse the repository at this point in the history
…ity views
  • Loading branch information
beikov committed Nov 18, 2018
1 parent 792febe commit ba786a5
Show file tree
Hide file tree
Showing 70 changed files with 1,546 additions and 518 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1111,7 +1111,8 @@ private JoinNode renderJoinNode(StringBuilder sb, JoinAliasInfo joinBase, JoinNo

sb.append(node.getAliasInfo().getAlias());
renderedJoins.add(node);
boolean onClause = valuesNode != null || node.getOnPredicate() != null && !node.getOnPredicate().getChildren().isEmpty() || onCondition != null;
boolean realOnClause = node.getOnPredicate() != null && !node.getOnPredicate().getChildren().isEmpty() || onCondition != null;
boolean onClause = valuesNode != null || realOnClause;

if (onClause) {
sb.append(joinRestrictionKeyword);
Expand All @@ -1125,7 +1126,9 @@ private JoinNode renderJoinNode(StringBuilder sb, JoinAliasInfo joinBase, JoinNo
if (valuesNode != null) {
if (!externalRepresentation) {
renderValuesClausePredicate(sb, valuesNode, valuesNode.getAlias(), externalRepresentation);
sb.append(" AND ");
if (realOnClause) {
sb.append(" AND ");
}
}
valuesNode = null;
}
Expand Down Expand Up @@ -2185,26 +2188,34 @@ private boolean isSingleValuedAssociationId(JoinResult joinResult, List<PathElem
return false;
}

String elementCollectionPath = null;
String attributePath = joinResult.joinFields(maybeSingularAssociationName);
String fullAttributePath = attributePath;
if (maybeSingularAssociation instanceof MapKeyAttribute<?, ?>) {
// Skip the foreign join column check for map keys
// They aren't allowed as join sources in the JPA providers yet so we can only render them directly
} else if (baseType instanceof EmbeddableType<?>) {
// Get the base type. This is important if the path is "deeper" i.e. when having embeddables
JoinNode node = parent;
baseType = node.getNodeType();
while (baseType instanceof EmbeddableType<?>) {
if (baseType instanceof EmbeddableType<?>) {
if (node.getParentTreeNode() == null) {
attributePath = node.getValuesLikeAttribute() + "." + attributePath;
fullAttributePath = node.getValuesLikeAttribute() + "." + fullAttributePath;
elementCollectionPath = node.isValueClazzAttributeSingular() ? null : node.getValuesLikeAttribute();
baseType = node.getValueType();
break;
} else {
if (node.getParentTreeNode().getAttribute().isCollection()) {
elementCollectionPath = node.getParentTreeNode().getRelationName();
} else {
attributePath = node.getParentTreeNode().getRelationName() + "." + attributePath;
}
fullAttributePath = node.getParentTreeNode().getRelationName() + "." + fullAttributePath;
node = node.getParent();
baseType = node.getNodeType();
}
attributePath = node.getParentTreeNode().getRelationName() + "." + attributePath;
node = node.getParent();
baseType = node.getNodeType();
}

if (mainQuery.jpaProvider.isForeignJoinColumn((EntityType<?>) baseType, attributePath)) {
if (mainQuery.jpaProvider.isForeignJoinColumn((EntityType<?>) baseType, fullAttributePath)) {
return false;
}
} else if (mainQuery.jpaProvider.isForeignJoinColumn((EntityType<?>) baseType, maybeSingularAssociation.getName())) {
Expand All @@ -2213,10 +2224,18 @@ private boolean isSingleValuedAssociationId(JoinResult joinResult, List<PathElem

PathElementExpression maybeSingularAssociationIdExpression = pathElements.get(maybeSingularAssociationIdIndex);
ExtendedManagedType<?> managedType = metamodel.getManagedType(ExtendedManagedType.class, JpaMetamodelUtils.getTypeName(baseType));
ExtendedAttribute<?, ?> associationAttribute = managedType.getOwnedSingularAttributes().get(attributePath);
return managedType.getOwnedSingularAttributes().containsKey(attributePath + "." + maybeSingularAssociationIdExpression)
&& associationAttribute != null
&& (contains(metamodel.getManagedType(ExtendedManagedType.class, associationAttribute.getElementClass()).getIdAttributes(), maybeSingularAssociationIdExpression) || mainQuery.jpaProvider.supportsSingleValuedAssociationNaturalIdExpressions());
if (elementCollectionPath == null) {
ExtendedAttribute<?, ?> associationAttribute = managedType.getOwnedSingularAttributes().get(fullAttributePath);
return managedType.getOwnedSingularAttributes().containsKey(fullAttributePath + "." + maybeSingularAssociationIdExpression)
&& associationAttribute != null
&& (contains(metamodel.getManagedType(ExtendedManagedType.class, associationAttribute.getElementClass()).getIdAttributes(), maybeSingularAssociationIdExpression) || mainQuery.jpaProvider.supportsSingleValuedAssociationNaturalIdExpressions());
} else {
// We assume that associations within element collections are always owned
ExtendedAttribute<?, ?> associationAttribute = managedType.getAttributes().get(fullAttributePath);
return managedType.getAttributes().containsKey(fullAttributePath + "." + maybeSingularAssociationIdExpression)
&& associationAttribute != null
&& (contains(metamodel.getManagedType(ExtendedManagedType.class, associationAttribute.getElementClass()).getIdAttributes(), maybeSingularAssociationIdExpression) || mainQuery.jpaProvider.supportsSingleValuedAssociationNaturalIdExpressions());
}
}

private static boolean contains(Set<? extends Attribute<?, ?>> attributes, PathElementExpression expression) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ protected StringBuilder applySqlTransformations(String sqlQuery) {
int subselectIndex = sb.indexOf(subselectTableExpr, 0);
if (subselectIndex == -1) {
// this is probably a VALUES clause for an entity type
int syntheticPredicateStart = sb.indexOf(syntheticPredicate, SqlUtils.indexOfWhere(sb));
int syntheticPredicateStart = sb.indexOf(syntheticPredicate, SqlUtils.indexOfFrom(sb));
int end = syntheticPredicateStart + syntheticPredicate.length();
if (sb.indexOf(andSeparator, end) == end) {
sb.replace(syntheticPredicateStart, end + andSeparator.length(), "");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ public void setWrappedByteArray(Byte[] wrappedByteArray) {
this.wrappedByteArray = wrappedByteArray;
}

@OneToMany(mappedBy = "partnerDocument")
@OneToMany(mappedBy = "partnerDocument", cascade = CascadeType.PERSIST)
public Set<Person> getPartners() {
return partners;
}
Expand Down Expand Up @@ -260,8 +260,8 @@ public Map<Integer, Person> getContacts() {
return contacts;
}

public void setContacts(Map<Integer, Person> localized) {
this.contacts = localized;
public void setContacts(Map<Integer, Person> contacts) {
this.contacts = contacts;
}

@OneToMany
Expand All @@ -271,8 +271,8 @@ public Map<Integer, Person> getContacts2() {
return contacts2;
}

public void setContacts2(Map<Integer, Person> localized) {
this.contacts2 = localized;
public void setContacts2(Map<Integer, Person> contacts2) {
this.contacts2 = contacts2;
}

@OneToMany
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@
public final class DirtyStateViewAttributeAccessor extends ViewAttributeAccessor implements InitialValueAttributeAccessor {

private final int dirtyStateIndex;
private final boolean updatableOnly;
private final BasicUserType<Object> userType;

@SuppressWarnings({ "rawtypes", "unchecked" })
public DirtyStateViewAttributeAccessor(EntityViewManagerImpl evm, MethodAttribute<?, ?> attribute) {
super(evm, attribute, false);
this.dirtyStateIndex = ((AbstractMethodAttribute<?, ?>) attribute).getDirtyStateIndex();
this.updatableOnly = ((AbstractMethodAttribute<?, ?>) attribute).isUpdatableOnly() && !attribute.isCorrelated();
if (attribute instanceof SingularAttribute<?, ?>) {
SingularAttribute<?, ?> singularAttribute = (SingularAttribute<?, ?>) attribute;
if (singularAttribute.getType() instanceof BasicType<?>) {
Expand Down Expand Up @@ -82,7 +84,9 @@ public void setValue(Object view, Object value) {
super.setValue(view, value);
if (view instanceof MutableStateTrackable) {
MutableStateTrackable mutableStateTrackable = (MutableStateTrackable) view;
if (value instanceof DirtyTracker) {
if (updatableOnly && value instanceof MutableStateTrackable) {
((MutableStateTrackable) value).$$_addReadOnlyParent(mutableStateTrackable, dirtyStateIndex);
} else if (value instanceof DirtyTracker) {
((DirtyTracker) value).$$_setParent(mutableStateTrackable, dirtyStateIndex);
}
mutableStateTrackable.$$_getMutableState()[dirtyStateIndex] = value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,17 @@
public class ListCollectionInstantiator extends AbstractCollectionInstantiator {

private final Set<Class<?>> allowedSubtypes;
private final Set<Class<?>> parentRequiringSubtypes;
private final boolean updatable;
private final boolean indexed;
private final boolean optimize;
private final boolean forceUnique;
private final Comparator<Object> comparator;

public ListCollectionInstantiator(PluralObjectFactory<Collection<?>> collectionFactory, Set<Class<?>> allowedSubtypes, boolean updatable, boolean indexed, boolean optimize, boolean forceUnique, Comparator<?> comparator) {
public ListCollectionInstantiator(PluralObjectFactory<Collection<?>> collectionFactory, Set<Class<?>> allowedSubtypes, Set<Class<?>> parentRequiringSubtypes, boolean updatable, boolean indexed, boolean optimize, boolean forceUnique, Comparator<?> comparator) {
super(collectionFactory);
this.allowedSubtypes = allowedSubtypes;
this.parentRequiringSubtypes = parentRequiringSubtypes;
this.updatable = updatable;
this.indexed = indexed;
this.optimize = optimize;
Expand Down Expand Up @@ -90,6 +92,6 @@ public List<?> createCollection(int size) {

@Override
public RecordingList<?> createRecordingCollection(int size) {
return new RecordingList(createCollection(size), indexed, allowedSubtypes, updatable, optimize);
return new RecordingList(createCollection(size), indexed, allowedSubtypes, parentRequiringSubtypes, updatable, optimize);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,16 @@
public class OrderedCollectionInstantiator extends AbstractCollectionInstantiator {

private final Set<Class<?>> allowedSubtypes;
private final Set<Class<?>> parentRequiringSubtypes;
private final boolean updatable;
private final boolean optimize;
private final boolean forceUnique;
private final Comparator<Object> comparator;

public OrderedCollectionInstantiator(PluralObjectFactory<Collection<?>> collectionFactory, Set<Class<?>> allowedSubtypes, boolean updatable, boolean optimize, boolean forceUnique, Comparator<?> comparator) {
public OrderedCollectionInstantiator(PluralObjectFactory<Collection<?>> collectionFactory, Set<Class<?>> allowedSubtypes, Set<Class<?>> parentRequiringSubtypes, boolean updatable, boolean optimize, boolean forceUnique, Comparator<?> comparator) {
super(collectionFactory);
this.allowedSubtypes = allowedSubtypes;
this.parentRequiringSubtypes = parentRequiringSubtypes;
this.updatable = updatable;
this.optimize = optimize;
this.forceUnique = forceUnique;
Expand Down Expand Up @@ -87,6 +89,6 @@ public Collection<?> createCollection(int size) {

@Override
public RecordingCollection<Collection<?>, ?> createRecordingCollection(int size) {
return new RecordingCollection(createCollection(size), false, true, allowedSubtypes, updatable, optimize);
return new RecordingCollection(createCollection(size), false, true, allowedSubtypes, parentRequiringSubtypes, updatable, optimize);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@
public class OrderedMapInstantiator extends AbstractMapInstantiator<Map<?, ?>, RecordingMap<Map<?, ?>, ?, ?>> {

private final Set<Class<?>> allowedSubtypes;
private final Set<Class<?>> parentRequiringSubtypes;
private final boolean updatable;
private final boolean optimize;

public OrderedMapInstantiator(PluralObjectFactory<Map<?, ?>> collectionFactory, Set<Class<?>> allowedSubtypes, boolean updatable, boolean optimize) {
public OrderedMapInstantiator(PluralObjectFactory<Map<?, ?>> collectionFactory, Set<Class<?>> allowedSubtypes, Set<Class<?>> parentRequiringSubtypes, boolean updatable, boolean optimize) {
super(collectionFactory);
this.allowedSubtypes = allowedSubtypes;
this.parentRequiringSubtypes = parentRequiringSubtypes;
this.updatable = updatable;
this.optimize = optimize;
}
Expand All @@ -45,6 +47,6 @@ public OrderedMapInstantiator(PluralObjectFactory<Map<?, ?>> collectionFactory,

@Override
public RecordingMap<Map<?, ?>, ?, ?> createRecordingCollection(int size) {
return new RecordingMap(createCollection(size), true, allowedSubtypes, updatable, optimize);
return new RecordingMap(createCollection(size), true, allowedSubtypes, parentRequiringSubtypes, updatable, optimize);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@
public class OrderedSetCollectionInstantiator extends AbstractCollectionInstantiator {

private final Set<Class<?>> allowedSubtypes;
private final Set<Class<?>> parentRequiringSubtypes;
private final boolean updatable;
private final boolean optimize;

public OrderedSetCollectionInstantiator(PluralObjectFactory<Collection<?>> collectionFactory, Set<Class<?>> allowedSubtypes, boolean updatable, boolean optimize) {
public OrderedSetCollectionInstantiator(PluralObjectFactory<Collection<?>> collectionFactory, Set<Class<?>> allowedSubtypes, Set<Class<?>> parentRequiringSubtypes, boolean updatable, boolean optimize) {
super(collectionFactory);
this.allowedSubtypes = allowedSubtypes;
this.parentRequiringSubtypes = parentRequiringSubtypes;
this.updatable = updatable;
this.optimize = optimize;
}
Expand All @@ -50,6 +52,6 @@ public Set<?> createCollection(int size) {

@Override
public RecordingSet<Set<?>, ?> createRecordingCollection(int size) {
return new RecordingSet(createCollection(size), true, allowedSubtypes, updatable, optimize);
return new RecordingSet(createCollection(size), true, allowedSubtypes, parentRequiringSubtypes, updatable, optimize);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class RecordingCollection<C extends Collection<E>, E> implements Collecti

protected final C delegate;
protected final Set<Class<?>> allowedSubtypes;
protected final Set<Class<?>> parentRequiringSubtypes;
protected final boolean updatable;
protected final boolean indexed;
private final boolean ordered;
Expand All @@ -60,19 +61,21 @@ public class RecordingCollection<C extends Collection<E>, E> implements Collecti
// We remember the iterator so we can do a proper hash based collection replacement
private transient RecordingReplacingIterator<E> currentIterator;

protected RecordingCollection(C delegate, boolean indexed, boolean ordered, Set<Class<?>> allowedSubtypes, boolean updatable, boolean optimize, boolean hashBased) {
protected RecordingCollection(C delegate, boolean indexed, boolean ordered, Set<Class<?>> allowedSubtypes, Set<Class<?>> parentRequiringSubtypes, boolean updatable, boolean optimize, boolean hashBased) {
this.delegate = delegate;
this.allowedSubtypes = allowedSubtypes;
this.parentRequiringSubtypes = parentRequiringSubtypes;
this.updatable = updatable;
this.indexed = indexed;
this.ordered = ordered;
this.optimize = optimize;
this.hashBased = hashBased;
}

public RecordingCollection(C delegate, boolean indexed, boolean ordered, Set<Class<?>> allowedSubtypes, boolean updatable, boolean optimize) {
public RecordingCollection(C delegate, boolean indexed, boolean ordered, Set<Class<?>> allowedSubtypes, Set<Class<?>> parentRequiringSubtypes, boolean updatable, boolean optimize) {
this.delegate = delegate;
this.allowedSubtypes = allowedSubtypes;
this.parentRequiringSubtypes = parentRequiringSubtypes;
this.updatable = updatable;
this.indexed = indexed;
this.ordered = ordered;
Expand Down Expand Up @@ -169,6 +172,25 @@ public RecordingCollection(C delegate, boolean indexed, boolean ordered, Set<Cla
return parent != null;
}

@Override
public void $$_replaceAttribute(Object oldObject, int attributeIndex, Object newObject) {
if (ordered) {
List<E> newCollection = new ArrayList<>(delegate.size());
for (E e : delegate) {
if (e == oldObject) {
newCollection.add((E) newObject);
} else {
newCollection.add(e);
}
}
delegate.clear();
delegate.addAll(newCollection);
} else {
delegate.remove(oldObject);
delegate.add((E) newObject);
}
}

public void $$_unsetParent() {
this.parentIndex = 0;
this.parent = null;
Expand Down Expand Up @@ -490,11 +512,14 @@ protected void checkType(Object e, String action) {
if (!allowedSubtypes.contains(c)) {
throw new IllegalArgumentException(action + " instances of type [" + c.getName() + "] is not allowed!");
}
if (parentRequiringSubtypes.contains(c) && !((DirtyTracker) e).$$_hasParent()) {
throw new IllegalArgumentException(action + " instances of type [" + c.getName() + "] is not allowed until they are assigned to an attribute that cascades the type!");
}
}
}

protected void checkType(Collection<?> collection, String action) {
if (collection != null && !allowedSubtypes.isEmpty()) {
if (collection != null && !collection.isEmpty() && !allowedSubtypes.isEmpty()) {
for (Object e : collection) {
Class<?> c;
if (e instanceof EntityViewProxy) {
Expand All @@ -506,6 +531,9 @@ protected void checkType(Collection<?> collection, String action) {
if (!allowedSubtypes.contains(c)) {
throw new IllegalArgumentException(action + " instances of type [" + c.getName() + "] is not allowed!");
}
if (parentRequiringSubtypes.contains(c) && !((DirtyTracker) e).$$_hasParent()) {
throw new IllegalArgumentException(action + " instances of type [" + c.getName() + "] is not allowed until they are assigned to an attribute that cascades the type!");
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
*/
public class RecordingList<E> extends RecordingCollection<List<E>, E> implements List<E> {

public RecordingList(List<E> delegate, boolean indexed, Set<Class<?>> allowedSubtypes, boolean updatable, boolean optimize) {
super(delegate, indexed, indexed, allowedSubtypes, updatable, optimize);
public RecordingList(List<E> delegate, boolean indexed, Set<Class<?>> allowedSubtypes, Set<Class<?>> parentRequiringSubtypes, boolean updatable, boolean optimize) {
super(delegate, indexed, indexed, allowedSubtypes, parentRequiringSubtypes, updatable, optimize);
}

@Override
Expand Down
Loading

0 comments on commit ba786a5

Please sign in to comment.