All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sap.cds.util.NestedStructsResolver Maven / Gradle / Ivy

There is a newer version: 3.6.1
Show newest version
/************************************************************************
 * © 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