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

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

There is a newer version: 3.6.1
Show newest version
/*******************************************************************
 * © 2020 SAP SE or an SAP affiliate company. All rights reserved. *
 *******************************************************************/
package com.sap.cds.util;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.sap.cds.CdsException;
import com.sap.cds.impl.parser.VersionParser;
import com.sap.cds.ql.cqn.CqnElementRef;
import com.sap.cds.ql.cqn.CqnPredicate;
import com.sap.cds.ql.cqn.CqnReference.Segment;
import com.sap.cds.ql.cqn.CqnStructuredTypeRef;
import com.sap.cds.ql.cqn.CqnVisitor;
import com.sap.cds.reflect.CdsAssociationType;
import com.sap.cds.reflect.CdsElement;
import com.sap.cds.reflect.CdsEntity;
import com.sap.cds.reflect.CdsModel;
import com.sap.cds.reflect.CdsStructuredType;
import com.sap.cds.reflect.CdsType;
import com.sap.cds.reflect.impl.CdsVersion;
import com.sap.cds.reflect.impl.DraftAdapter;
import com.sap.cds.reflect.impl.reader.model.CdsConstants;

public class CdsModelUtils {

	private static final CdsVersion DEFAULT_COMPILER_VERSION = new CdsVersion(1, 0, 0, 0);

	private CdsModelUtils() {
	}

	public static boolean isSingleValued(CdsType associationElement) {
		return associationElement.as(CdsAssociationType.class).getCardinality().getTargetMax().equals("1");
	}

	public static Set targetKeys(CdsElement association) {
		CdsEntity target = association.getType().as(CdsAssociationType.class).getTarget();
		return resolveKeys(target).collect(Collectors.toSet());
	}

	public static Set keyNames(CdsStructuredType entity) {
		return resolveKeys(entity).collect(Collectors.toSet());
	}

	private static Stream resolveKeys(CdsStructuredType entity) {
		return entity.keyElements().filter(k -> !k.isVirtual()).flatMap(CdsModelUtils::resolveKeys);
	}

	private static Stream resolveKeys(CdsElement element) {
		if (element.getType().isAssociation()) {
			return resolveKeys(element.getType().as(CdsAssociationType.class).getTarget())
					.map(k -> element.getName() + "_" + k);
		}
		return Stream.of(element.getName());
	}

	public static Optional findElement(CdsStructuredType root, CqnElementRef ref) {
		try {
			return Optional.of(element(root, ref));
		} catch (CdsException e) {
			return Optional.empty();
		}
	}

	public static CdsElement element(CdsStructuredType root, CqnElementRef ref) {
		return element(root, ref.segments());
	}

	public static CdsElement element(CdsStructuredType root, List segments) {
		CdsStructuredType type = root;
		Iterator iter = segments.iterator();
		boolean firstSegment = true;
		while (iter.hasNext()) {
			Segment segment = iter.next();
			if (firstSegment && (segment.id().equals(root.getQualifiedName()))) {
				firstSegment = false;
				continue;
			}
			if (iter.hasNext()) {
				CdsElement element = type.getElement(segment.id());
				CdsType elementType = element.getType();
				if (elementType.isAssociation()) {
					type = elementType.as(CdsAssociationType.class).getTarget();
				} else if (elementType.isStructured()) {
					type = elementType.as(CdsStructuredType.class);
				}
				firstSegment = false;
			} else {
				return type.getElement(segment.id());
			}
		}
		throw new CdsException("Cannot find element " + segments + " of entity " + root);
	}

	public static boolean isContextElementRef(CqnElementRef ref) {
		switch (ref.firstSegment()) {
		case "$now":
		case "$at":
		case "$user":
			return true;
		default:
			return false;
		}
	}

	public static List entities(CdsModel model, List segments) {
		List entities = new ArrayList<>(segments.size());
		Iterator iter = segments.iterator();
		if (iter.hasNext()) {
			CdsEntity e = model.getEntity(iter.next().id());
			entities.add(e);
			while (iter.hasNext()) {
				e = e.getTargetOf(iter.next().id());
				entities.add(e);
			}
		}
		return entities;
	}

	public static List entities(CdsEntity root, List segments) {
		LinkedList entities = new LinkedList<>();
		entities.add(root);
		boolean firstSegment = true;
		for (Segment seg : segments) {
			if (firstSegment && root.getQualifiedName().equals(seg.id())) {
				continue;
			}
			entities.add(entities.getLast().getTargetOf(seg.id()));
			firstSegment = false;
		}
		return entities;
	}

	public static CdsEntity entity(CdsEntity root, List segments) {
		return ((LinkedList) entities(root, segments)).getLast();
	}

	public static CdsStructuredType target(CdsStructuredType root, List segments) {
		CdsStructuredType target = root;
		for (Segment seg : segments) {
			target = target.getTargetOf(seg.id());
		}

		return target;
	}

	public static CdsEntity entity(CdsModel model, List segments) {
		CdsEntity entity = model.getEntity(segments.get(0).id());

		return entity(entity, segments);
	}

	public static CdsEntity entity(CdsModel model, CqnStructuredTypeRef ref) {
		CdsEntity entity = model.getEntity(ref.firstSegment());

		return entity(entity, ref.segments());
	}

	public static boolean isReverseAssociation(CdsElement assoc) {
		CdsAssociationType association = assoc.getType();
		if (association.getCardinality().getTargetMax().equalsIgnoreCase("*")) {
			return true;
		}

		return referencesAllKeysOfSource(assoc);
	}

	public static CdsVersion compilerVersion(CdsModel model) {
		String creator = model.getMeta(CdsConstants.CREATOR);
		if (creator == null) {
			return DEFAULT_COMPILER_VERSION;
		}
		try {
			return VersionParser.parse(creator.substring("CDS Compiler v".length()));
		} catch (IllegalArgumentException e) {
			return DEFAULT_COMPILER_VERSION;
		}
	}

	private static boolean referencesAllKeysOfSource(CdsElement assoc) {
		CdsAssociationType association = assoc.getType();
		Optional onCond = association.onCondition();
		if (!onCond.isPresent()) {

			return false;
		}

		Set sourceKeys = keyNames(assoc.getDeclaringType());
		sourceKeys.remove(DraftAdapter.IS_ACTIVE_ENTITY); // TODO CDSJAVA-2385
		CqnVisitor visitor = new CqnVisitor() {
			@Override
			public void visit(CqnElementRef ref) {
				if (ref.lastSegment().equals("$self")) {
					sourceKeys.clear();
				} else if (ref.segments().size() == 1) {
					sourceKeys.remove(ref.lastSegment());
				}
			}
		};
		onCond.get().accept(visitor);

		return sourceKeys.isEmpty();
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy