com.sap.cds.util.NestedStructsResolver Maven / Gradle / Ivy
/************************************************************************
* © 2022-2023 SAP SE or an SAP affiliate company. All rights reserved. *
************************************************************************/
package com.sap.cds.util;
import static com.sap.cds.util.CdsModelUtils.element;
import static com.sap.cds.util.CqnStatementUtils.elementRef;
import static com.sap.cds.util.CqnStatementUtils.elementsOf;
import static com.sap.cds.util.CqnStatementUtils.structureOf;
import static java.util.stream.Collectors.toList;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.sap.cds.impl.builder.model.ExpandBuilder;
import com.sap.cds.ql.CQL;
import com.sap.cds.ql.Select;
import com.sap.cds.ql.cqn.CqnExpand;
import com.sap.cds.ql.cqn.CqnReference;
import com.sap.cds.ql.cqn.CqnReference.Segment;
import com.sap.cds.ql.cqn.CqnSelectListItem;
import com.sap.cds.ql.cqn.CqnSelectListValue;
import com.sap.cds.ql.cqn.CqnStructuredTypeRef;
import com.sap.cds.ql.impl.ExpressionVisitor;
import com.sap.cds.ql.impl.LeanModifier;
import com.sap.cds.reflect.CdsAssociationType;
import com.sap.cds.reflect.CdsElement;
import com.sap.cds.reflect.CdsEntity;
import com.sap.cds.reflect.CdsStructuredType;
public class NestedStructsResolver {
public static void resolveNestedStructs(Select> select, CdsStructuredType structType, boolean includeAssocs) {
List resolvedItems = select.items().stream()
.flatMap(i -> resolveStructElements(structType, null, i, includeAssocs)).collect(Collectors.toList());
select.columns(resolvedItems);
}
private static Stream resolveStructElements(CdsStructuredType parentStructType,
CqnSelectListValue parentSLV, CqnSelectListItem sli, boolean includeAssocs) {
if (sli.isExpand()) {
CqnExpand expand = sli.asExpand();
if (!expand.ref().firstSegment().equals("*")) {
CdsElement element = element(parentStructType, expand.ref().segments());
if (element.getType().isAssociation()) {
CdsStructuredType innerStructType = element.getType().as(CdsAssociationType.class).getTarget();
ExpandBuilder> expandCopy = (ExpandBuilder>) ExpressionVisitor.copy(expand, new LeanModifier() {
});
expandCopy.items(expand.items().stream()
.flatMap(i -> resolveStructElements(innerStructType, null, i, includeAssocs))
.collect(toList()));
return Stream.of(expandCopy);
} else if (element.getType().isStructured()) {
CdsStructuredType innerStructType = element.getType();
CqnSelectListValue slv = joinToSLV(parentSLV, expand.ref());
return expand.items().stream()
.flatMap(i -> resolveStructElements(innerStructType, slv, i, includeAssocs));
}
}
} else if (sli.isRef()) {
CdsElement element = element(parentStructType, sli.asRef());
CqnSelectListValue slv = joinToSLV(parentSLV, sli.asValue());
if (element.getType().isStructured()) {
return structureOf(element, includeAssocs).map(e -> joinToSLV(slv, e.subList(1, e.size())));
} else {
return Stream.of(slv);
}
} else if (sli.isStar() && !(parentStructType instanceof CdsEntity)) {
return elementsOf(parentStructType, includeAssocs).map(e -> joinToSLV(parentSLV, e));
}
return Stream.of(sli);
}
private static CqnSelectListItem joinToSLV(CqnSelectListValue parentRef, List path) {
return joinToSLV(parentRef, elementRef(path));
}
private static CqnSelectListValue joinToSLV(CqnSelectListValue parentRef, CqnSelectListValue ref) {
if (parentRef == null) {
return ref;
}
return joinToSLV(parentRef.asRef(), parentRef.alias(), ref.asRef(), ref.alias());
}
private static CqnSelectListValue joinToSLV(CqnSelectListValue parentRef, CqnStructuredTypeRef ref) {
if (parentRef == null) {
return joinToSLV(null, null, ref, ref.alias()); // converts structured type ref to element ref
}
return joinToSLV(parentRef.asRef(), parentRef.alias(), ref, ref.alias());
}
private static CqnSelectListValue joinToSLV(CqnReference parentRef, Optional parentAlias, CqnReference ref,
Optional alias) {
List segments = new ArrayList<>();
List aliases = new ArrayList<>();
if (parentRef != null) {
segments.addAll(parentRef.segments());
aliases.add(alias(parentRef, parentAlias));
}
segments.addAll(ref.segments());
aliases.add(alias(ref, alias));
return CQL.get(segments).as(String.join(".", aliases));
}
private static String alias(CqnReference ref, Optional alias) {
return alias.orElse(ref.path());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy