Search in sources :

Example 1 with CollectionMultisetTupleTransformerFactory

use of com.blazebit.persistence.view.impl.objectbuilder.transformer.CollectionMultisetTupleTransformerFactory 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);
            }
        }
    }
}
Also used : MappingAttribute(com.blazebit.persistence.view.metamodel.MappingAttribute) NonIndexedTupleListTransformer(com.blazebit.persistence.view.impl.objectbuilder.transformer.NonIndexedTupleListTransformer) IndexedTupleListTransformer(com.blazebit.persistence.view.impl.objectbuilder.transformer.IndexedTupleListTransformer) NonIndexedTupleListTransformer(com.blazebit.persistence.view.impl.objectbuilder.transformer.NonIndexedTupleListTransformer) ManagedViewTypeImpl(com.blazebit.persistence.view.impl.metamodel.ManagedViewTypeImpl) SubviewTupleTransformerFactory(com.blazebit.persistence.view.impl.objectbuilder.transformer.SubviewTupleTransformerFactory) CollectionMultisetTupleTransformerFactory(com.blazebit.persistence.view.impl.objectbuilder.transformer.CollectionMultisetTupleTransformerFactory) PluralAttribute(com.blazebit.persistence.view.metamodel.PluralAttribute) ManagedViewTypeImplementor(com.blazebit.persistence.view.impl.metamodel.ManagedViewTypeImplementor) TypeConverter(com.blazebit.persistence.view.spi.type.TypeConverter) MapAttribute(com.blazebit.persistence.view.metamodel.MapAttribute) SingularMultisetTupleTransformerFactory(com.blazebit.persistence.view.impl.objectbuilder.transformer.SingularMultisetTupleTransformerFactory) ManagedViewType(com.blazebit.persistence.view.metamodel.ManagedViewType) ViewType(com.blazebit.persistence.view.metamodel.ViewType)

Aggregations

ManagedViewTypeImpl (com.blazebit.persistence.view.impl.metamodel.ManagedViewTypeImpl)1 ManagedViewTypeImplementor (com.blazebit.persistence.view.impl.metamodel.ManagedViewTypeImplementor)1 CollectionMultisetTupleTransformerFactory (com.blazebit.persistence.view.impl.objectbuilder.transformer.CollectionMultisetTupleTransformerFactory)1 IndexedTupleListTransformer (com.blazebit.persistence.view.impl.objectbuilder.transformer.IndexedTupleListTransformer)1 NonIndexedTupleListTransformer (com.blazebit.persistence.view.impl.objectbuilder.transformer.NonIndexedTupleListTransformer)1 SingularMultisetTupleTransformerFactory (com.blazebit.persistence.view.impl.objectbuilder.transformer.SingularMultisetTupleTransformerFactory)1 SubviewTupleTransformerFactory (com.blazebit.persistence.view.impl.objectbuilder.transformer.SubviewTupleTransformerFactory)1 ManagedViewType (com.blazebit.persistence.view.metamodel.ManagedViewType)1 MapAttribute (com.blazebit.persistence.view.metamodel.MapAttribute)1 MappingAttribute (com.blazebit.persistence.view.metamodel.MappingAttribute)1 PluralAttribute (com.blazebit.persistence.view.metamodel.PluralAttribute)1 ViewType (com.blazebit.persistence.view.metamodel.ViewType)1 TypeConverter (com.blazebit.persistence.view.spi.type.TypeConverter)1