use of com.blazebit.persistence.view.impl.objectbuilder.transformer.IndexedTupleListTransformer in project blaze-persistence by Blazebit.
the class ViewTypeObjectBuilderTemplate method applyMapping.
@SuppressWarnings("unchecked")
private void applyMapping(AbstractAttribute<?, ?> attribute, String parentAttributePath, TupleElementMapperBuilder mapperBuilder, Set<Feature> features, TupleIdDescriptor tupleIdDescriptor, ViewJpqlMacro viewJpqlMacro, EmbeddingViewJpqlMacro embeddingViewJpqlMacro, ExpressionFactory ef) {
String attributePath = getAttributePath(parentAttributePath, attribute, false);
int batchSize = attribute.getBatchSize();
if (batchSize == -1) {
batchSize = attribute.getDeclaringType().getDefaultBatchSize();
}
if (attribute.isSubquery()) {
applySubqueryMapping((SubqueryAttribute<? super T, ?>) attribute, attributePath, mapperBuilder, embeddingViewJpqlMacro);
} else {
if (attribute.isCollection()) {
PluralAttribute<? super T, ?, ?> pluralAttribute = (PluralAttribute<? super T, ?, ?>) attribute;
TypeConverter<Object, Object> keyConverter = null;
TypeConverter<Object, Object> valueConverter = (TypeConverter<Object, Object>) pluralAttribute.getElementType().getConverter();
boolean listKey = pluralAttribute.isIndexed() && pluralAttribute instanceof ListAttribute<?, ?>;
boolean mapKey = pluralAttribute.isIndexed() && pluralAttribute instanceof MapAttribute<?, ?, ?>;
int startIndex = tupleOffset + mapperBuilder.mapperIndex();
int valueStartIndex = startIndex + 1;
if (pluralAttribute.getFetchStrategy() == FetchStrategy.JOIN) {
if (listKey) {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
features.add(Feature.INDEXED_COLLECTIONS);
applyIndexCollectionFunctionMapping(IntegerBasicUserType.INSTANCE, mappingAttribute, attributePath, mapperBuilder, embeddingViewJpqlMacro);
} else if (mapKey) {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
features.add(Feature.INDEXED_COLLECTIONS);
MapAttribute<?, ?, ?> mapAttribute = (MapAttribute<?, ?, ?>) pluralAttribute;
keyConverter = (TypeConverter<Object, Object>) mapAttribute.getKeyType().getConverter();
if (mapAttribute.isKeySubview()) {
features.add(Feature.SUBVIEWS);
ManagedViewTypeImpl<Object[]> managedViewType = (ManagedViewTypeImpl<Object[]>) mapAttribute.getKeyType();
applySubviewMapping(mappingAttribute, attributePath, tupleIdDescriptor, managedViewType, mapperBuilder, viewJpqlMacro, embeddingViewJpqlMacro, ef, true, true);
valueStartIndex = tupleOffset + mapperBuilder.mapperIndex();
} else {
applyIndexCollectionFunctionMapping(TypeUtils.forType(mapAttribute.getKeyType()), mappingAttribute, attributePath, mapperBuilder, embeddingViewJpqlMacro);
}
}
}
boolean dirtyTracking = pluralAttribute instanceof MethodAttribute<?, ?> && attribute.needsDirtyTracker();
if (pluralAttribute.isSubview()) {
features.add(Feature.SUBVIEWS);
TupleIdDescriptor newTupleIdDescriptor;
if ((listKey || mapKey) && pluralAttribute.getFetchStrategy() == FetchStrategy.JOIN && !pluralAttribute.isCorrelated()) {
newTupleIdDescriptor = new TupleIdDescriptor(tupleIdDescriptor);
newTupleIdDescriptor.addIdPosition(startIndex);
} else {
newTupleIdDescriptor = tupleIdDescriptor;
}
if (pluralAttribute.isCorrelated() || (pluralAttribute.getFetchStrategy() != FetchStrategy.JOIN || attribute.getLimitExpression() != null) && pluralAttribute.getFetchStrategy() != FetchStrategy.MULTISET) {
ManagedViewTypeImplementor<Object> managedViewType = (ManagedViewTypeImplementor<Object>) pluralAttribute.getElementType();
if (attribute.getFetchStrategy() == FetchStrategy.MULTISET) {
boolean updatableObjectCache = managedViewType.isUpdatable() || managedViewType.isCreatable();
boolean nullIfEmpty = managedViewType instanceof ViewType<?>;
ViewTypeObjectBuilderTemplate<Object[]>[] templates = applyCorrelatedSubviewMapping(attribute, attributePath, tupleIdDescriptor, (ManagedViewTypeImplementor<Object[]>) (ManagedViewTypeImplementor<?>) managedViewType, mapperBuilder, features, viewJpqlMacro, embeddingViewJpqlMacro, ef, batchSize, false);
ViewTypeObjectBuilderTemplate<Object[]> subviewTemplate = templates[0];
ViewTypeObjectBuilderTemplate<Object[]> indexTemplate = templates[1];
SubviewTupleTransformerFactory indexTransformerFactory = null;
BasicUserTypeStringSupport<?> indexBasicTypeSupport = null;
if (indexTemplate != null) {
boolean updatableKeyObjectCache = indexTemplate.viewType.isUpdatable() || indexTemplate.viewType.isCreatable();
indexTransformerFactory = new SubviewTupleTransformerFactory(attributePath, indexTemplate, updatableKeyObjectCache, true);
} else if (mapKey) {
indexBasicTypeSupport = TypeUtils.forType(((MapAttribute<?, ?, ?>) attribute).getKeyType());
} else if (listKey) {
indexBasicTypeSupport = IntegerBasicUserType.INSTANCE;
}
mapperBuilder.addTupleTransformerFactory(new CollectionMultisetTupleTransformerFactory(startIndex, null, attributePath, getMultisetResultAlias(attributePath), valueConverter, attribute.getContainerAccumulator(), dirtyTracking, subviewTemplate, indexTemplate, managedViewType.hasSelectOrSubselectFetchedAttributes(), new SubviewTupleTransformerFactory(attributePath, subviewTemplate, updatableObjectCache, nullIfEmpty), indexTransformerFactory, null, indexBasicTypeSupport));
} else {
applyCorrelatedSubviewMapping(attribute, attributePath, newTupleIdDescriptor, (ManagedViewTypeImplementor<Object[]>) (ManagedViewTypeImplementor<?>) managedViewType, mapperBuilder, features, viewJpqlMacro, embeddingViewJpqlMacro, ef, batchSize, dirtyTracking);
}
} else {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
ManagedViewTypeImplementor<Object[]> managedViewType = (ManagedViewTypeImplementor<Object[]>) pluralAttribute.getElementType();
boolean nullIfEmpty = managedViewType instanceof ViewType<?> || !listKey && !mapKey;
if (pluralAttribute.getFetchStrategy() == FetchStrategy.MULTISET) {
boolean updatableObjectCache = managedViewType.isUpdatable() || managedViewType.isCreatable();
String mapping = mapperBuilder.getMapping(mappingAttribute);
ViewTypeObjectBuilderTemplate<Object[]>[] templates = applySubviewMapping(mappingAttribute, attributePath, newTupleIdDescriptor, managedViewType, mapperBuilder, viewJpqlMacro, embeddingViewJpqlMacro, ef, false, nullIfEmpty);
ViewTypeObjectBuilderTemplate<Object[]> subviewTemplate = templates[0];
ViewTypeObjectBuilderTemplate<Object[]> indexTemplate = templates[1];
SubviewTupleTransformerFactory indexTransformerFactory = null;
BasicUserTypeStringSupport<?> indexBasicTypeSupport = null;
if (indexTemplate != null) {
boolean updatableKeyObjectCache = indexTemplate.viewType.isUpdatable() || indexTemplate.viewType.isCreatable();
indexTransformerFactory = new SubviewTupleTransformerFactory(attributePath, indexTemplate, updatableKeyObjectCache, true);
} else if (mapKey) {
indexBasicTypeSupport = TypeUtils.forType(((MapAttribute<?, ?, ?>) attribute).getKeyType());
} else if (listKey) {
indexBasicTypeSupport = IntegerBasicUserType.INSTANCE;
}
mapperBuilder.addTupleTransformerFactory(new CollectionMultisetTupleTransformerFactory(startIndex, mapping, attributePath, getMultisetResultAlias(attributePath), valueConverter, attribute.getContainerAccumulator(), dirtyTracking, subviewTemplate, indexTemplate, managedViewType.hasSelectOrSubselectFetchedAttributes(), new SubviewTupleTransformerFactory(attributePath, subviewTemplate, updatableObjectCache, nullIfEmpty), indexTransformerFactory, null, indexBasicTypeSupport));
} else {
// Obviously, we produce null if the object type is identifiable i.e. a ViewType and it is empty = null id
// Additionally, we also consider empty embeddables as null when we have a non-indexed collection so we can filter out these elements
applySubviewMapping(mappingAttribute, attributePath, newTupleIdDescriptor, managedViewType, mapperBuilder, viewJpqlMacro, embeddingViewJpqlMacro, ef, false, nullIfEmpty);
}
}
} else if (mapKey) {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
applyCollectionFunctionMapping(TypeUtils.forType(getType(mappingAttribute)), mappingAttribute, attributePath, mapperBuilder, mappingAttribute.getFetches(), embeddingViewJpqlMacro);
} else {
// TODO: Multiset basic fetching?
if (pluralAttribute.isCorrelated() || attribute.getFetchStrategy() == FetchStrategy.JOIN && !attribute.getOrderByItems().isEmpty() || pluralAttribute.getFetchStrategy() != FetchStrategy.JOIN && pluralAttribute.getFetchStrategy() != FetchStrategy.MULTISET) {
applyBasicCorrelatedMapping(attribute, attributePath, mapperBuilder, features, ef, batchSize, dirtyTracking, embeddingViewJpqlMacro);
} else {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
applyBasicMapping(mappingAttribute, attributePath, mapperBuilder, embeddingViewJpqlMacro);
}
}
if (pluralAttribute.getFetchStrategy() == FetchStrategy.JOIN) {
if (listKey) {
if (pluralAttribute.isSorted()) {
throw new IllegalArgumentException("The list attribute '" + pluralAttribute + "' can not be sorted!");
} else {
mapperBuilder.addTupleListTransformer(new IndexedTupleListTransformer(tupleIdDescriptor.createIdPositions(), startIndex, valueStartIndex, attribute.getContainerAccumulator(), dirtyTracking, null, valueConverter));
}
} else if (mapKey) {
mapperBuilder.addTupleListTransformer(new IndexedTupleListTransformer(tupleIdDescriptor.createIdPositions(), startIndex, valueStartIndex, attribute.getContainerAccumulator(), dirtyTracking, keyConverter, valueConverter));
} else {
switch(pluralAttribute.getCollectionType()) {
case COLLECTION:
if (pluralAttribute.isSorted()) {
throw new IllegalArgumentException("The collection attribute '" + pluralAttribute + "' can not be sorted!");
}
break;
case LIST:
if (pluralAttribute.isSorted()) {
throw new IllegalArgumentException("The list attribute '" + pluralAttribute + "' can not be sorted!");
}
break;
case SET:
break;
case MAP:
throw new IllegalArgumentException("Ignoring the index on the attribute '" + pluralAttribute + "' is not possible!");
default:
throw new IllegalArgumentException("Unknown collection type: " + pluralAttribute.getCollectionType());
}
mapperBuilder.addTupleListTransformer(new NonIndexedTupleListTransformer(tupleIdDescriptor.createIdPositions(), startIndex, attribute.getCollectionInstantiator(), dirtyTracking, valueConverter));
}
}
} else if (attribute.isQueryParameter()) {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
features.add(Feature.PARAMETERS);
applyQueryParameterMapping(mappingAttribute, mapperBuilder);
} else if (attribute.isSubview()) {
features.add(Feature.SUBVIEWS);
boolean nullIfEmpty = !((SingularAttribute<?, ?>) attribute).isCreateEmptyFlatView();
if (attribute.isCorrelated() || attribute.getFetchStrategy() == FetchStrategy.JOIN && !attribute.getOrderByItems().isEmpty() || attribute.getFetchStrategy() != FetchStrategy.JOIN && attribute.getFetchStrategy() != FetchStrategy.MULTISET) {
ManagedViewTypeImplementor<Object> managedViewType = (ManagedViewTypeImplementor<Object>) ((SingularAttribute<?, ?>) attribute).getType();
if (attribute.getFetchStrategy() == FetchStrategy.MULTISET) {
int startIndex = tupleOffset + mapperBuilder.mapperIndex();
boolean updatableObjectCache = managedViewType.isUpdatable() || managedViewType.isCreatable();
ViewTypeObjectBuilderTemplate<Object[]> subviewTemplate = applyCorrelatedSubviewMapping(attribute, attributePath, tupleIdDescriptor, (ManagedViewTypeImplementor<Object[]>) (ManagedViewTypeImplementor<?>) managedViewType, mapperBuilder, features, viewJpqlMacro, embeddingViewJpqlMacro, ef, batchSize, false)[0];
TypeConverter<Object, Object> elementConverter = (TypeConverter<Object, Object>) (TypeConverter<?, ?>) managedViewType.getConverter();
mapperBuilder.addTupleTransformerFactory(new SingularMultisetTupleTransformerFactory(startIndex, null, attributePath, getMultisetResultAlias(attributePath), elementConverter, subviewTemplate, managedViewType.hasSelectOrSubselectFetchedAttributes(), new SubviewTupleTransformerFactory(attributePath, subviewTemplate, updatableObjectCache, nullIfEmpty)));
} else {
applyCorrelatedSubviewMapping(attribute, attributePath, tupleIdDescriptor, (ManagedViewTypeImplementor<Object[]>) (ManagedViewTypeImplementor<?>) managedViewType, mapperBuilder, features, viewJpqlMacro, embeddingViewJpqlMacro, ef, batchSize, false);
}
} else {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
ManagedViewTypeImplementor<Object[]> managedViewType = (ManagedViewTypeImplementor<Object[]>) ((SingularAttribute<?, ?>) attribute).getType();
if (attribute.getFetchStrategy() == FetchStrategy.MULTISET) {
int startIndex = tupleOffset + mapperBuilder.mapperIndex();
boolean updatableObjectCache = managedViewType.isUpdatable() || managedViewType.isCreatable();
String mapping = mapperBuilder.getMapping(mappingAttribute);
ViewTypeObjectBuilderTemplate<Object[]> subviewTemplate = applySubviewMapping(mappingAttribute, attributePath, tupleIdDescriptor, managedViewType, mapperBuilder, viewJpqlMacro, embeddingViewJpqlMacro, ef, false, nullIfEmpty)[0];
TypeConverter<Object, Object> elementConverter = (TypeConverter<Object, Object>) (TypeConverter<?, ?>) managedViewType.getConverter();
mapperBuilder.addTupleTransformerFactory(new SingularMultisetTupleTransformerFactory(startIndex, mapping, attributePath, getMultisetResultAlias(attributePath), elementConverter, subviewTemplate, managedViewType.hasSelectOrSubselectFetchedAttributes(), new SubviewTupleTransformerFactory(attributePath, subviewTemplate, updatableObjectCache, nullIfEmpty)));
} else {
applySubviewMapping(mappingAttribute, attributePath, tupleIdDescriptor, managedViewType, mapperBuilder, viewJpqlMacro, embeddingViewJpqlMacro, ef, false, nullIfEmpty);
}
}
} else {
if (attribute.isCorrelated() || attribute.getFetchStrategy() == FetchStrategy.JOIN && !attribute.getOrderByItems().isEmpty() || attribute.getFetchStrategy() != FetchStrategy.JOIN && attribute.getFetchStrategy() != FetchStrategy.MULTISET) {
applyBasicCorrelatedMapping(attribute, attributePath, mapperBuilder, features, ef, batchSize, false, embeddingViewJpqlMacro);
} else {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
applyBasicMapping(mappingAttribute, attributePath, mapperBuilder, embeddingViewJpqlMacro);
}
}
}
}
Aggregations