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

com.sap.cds.reflect.impl.CdsEntityBuilder Maven / Gradle / Ivy

/************************************************************************
 * © 2020-2024 SAP SE or an SAP affiliate company. All rights reserved. *
 ************************************************************************/
package com.sap.cds.reflect.impl;

import static com.sap.cds.impl.localized.LocaleUtils.isLocalizedEntityName;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sap.cds.ql.CQL;
import com.sap.cds.ql.Select;
import com.sap.cds.ql.StructuredType;
import com.sap.cds.ql.cqn.CqnSelect;
import com.sap.cds.ql.cqn.Modifier;
import com.sap.cds.reflect.CdsAction;
import com.sap.cds.reflect.CdsAnnotation;
import com.sap.cds.reflect.CdsEntity;
import com.sap.cds.reflect.CdsFunction;
import com.sap.cds.reflect.CdsKind;
import com.sap.cds.reflect.CdsOperationNotFoundException;
import com.sap.cds.reflect.CdsParameter;
import com.sap.cds.util.ConstantLiteralSealingModifier;
import com.sap.cds.util.ProjectionQueryNormalizer;

public class CdsEntityBuilder extends CdsStructuredTypeBuilder {

	private static final Logger logger = LoggerFactory.getLogger(CdsEntityBuilder.class);
	public static final Modifier LITERAL_SEALING_MODIFIER = new ConstantLiteralSealingModifier();
	private final boolean isAbstract;
	private final boolean isView;
	private final CqnSelect query;
	private final String name;
	private final Map> actions = new HashMap<>();
	private final Map> functions = new HashMap<>();
	private final List params = new ArrayList<>();
	private CdsEntityImpl impl;

	private CdsEntityBuilder(List> annotations, String name, String qualifiedName, boolean isAbstract,
			CqnSelect query, boolean isView, String doc) {
		super(annotations, qualifiedName, name, CdsKind.ENTITY, doc);
		this.isAbstract = isAbstract;
		this.query = query;
		this.isView = isView;
		this.name = name;
	}

	public static CdsEntityBuilder create(String name, String qualifiedName, List> annotations,
			boolean isAbstract, String query, String doc) {
		CqnSelect select = null;
		boolean isView = query != null;
		if (isView) {
			try {
				Select> parsedStatement = Select.cqn(query);
				if (parsedStatement.from().isJoin()) {
					select = parsedStatement; // Join cannot be copied
				} else {
					select = CQL.copy(parsedStatement, LITERAL_SEALING_MODIFIER);
					if (!select.items().isEmpty() && select.from().isRef()) {
						select = CQL.copy(select, new ProjectionQueryNormalizer(select.from().asRef()));
					}
				}
			} catch (RuntimeException e) {
				logger.warn(
						"Query in view '{}' is not supported by CDS model reader and cannot be accessed via reflection: {}",
						qualifiedName, query);
			}
		}
		return new CdsEntityBuilder(annotations, name, qualifiedName, isAbstract, select, isView, doc);
	}

	public boolean isAbstract() {
		return isAbstract;
	}

	public Stream> actions() {
		return actions.values().stream();
	}

	void addAction(CdsOperationBuilder action) {
		this.actions.put(action.getName(), action);
	}

	void addActions(List> actions) {
		actions.forEach(this::addAction);
	}

	public Stream> functions() {
		return functions.values().stream();
	}

	void addFunction(CdsOperationBuilder function) {
		this.functions.put(function.getName(), function);
	}

	void addFunctions(List> functions) {
		functions.forEach(this::addFunction);
	}

	void addParams(List params) {
		this.params.addAll(params);
	}

	@Override
	public CdsEntity build() {
		if (impl == null) {
			impl = new CdsEntityImpl(annotations, name, qualifiedName, isAbstract(), query, params, isView, doc);
			putElements(impl);
			actions.forEach((n, ab) -> impl.actions.put(ab.getName(), ab.build()));
			functions.forEach((n, fb) -> impl.functions.put(fb.getName(), fb.build()));
		}
		return impl;
	}

	@Override
	boolean toBeIgnored(String path) {
		return super.toBeIgnored(path) || isLocalizedEntityName(path);
	}

	private static class CdsEntityImpl extends CdsStructuredTypeBuilder.CdsStructuredTypeImpl implements CdsEntity {

		private final boolean isAbstract;
		private final boolean isView;
		private final CqnSelect query;
		private final List params;
		private final Map actions = new HashMap<>();
		private final Map functions = new HashMap<>();

		private CdsEntityImpl(Collection> annotations, String name, String qualifiedName,
				boolean isAbstract, CqnSelect query, List params, boolean isView, String doc) {
			super(annotations, qualifiedName, name, doc);
			this.isAbstract = isAbstract;
			this.query = query;
			this.params = params;
			this.isView = isView;
		}

		@Override
		public boolean isAbstract() {
			return isAbstract;
		}

		@Override
		public boolean isView() {
			return isView;
		}

		@Override
		public boolean isProjection() {
			throw new UnsupportedOperationException();
		}

		@Override
		public Optional query() {
			return Optional.ofNullable(query);
		}

		@Override
		public Stream params() {
			return params.stream();
		}

		@Override
		public Stream actions() {
			return actions.values().stream();
		}

		@Override
		public CdsAction getAction(String name) {
			return findAction(name).orElseThrow(() -> new CdsOperationNotFoundException(CdsKind.ACTION, name, this));
		}

		@Override
		public Optional findAction(String name) {
			return Optional.ofNullable(actions.get(name));
		}

		@Override
		public Stream functions() {
			return functions.values().stream();
		}

		@Override
		public CdsFunction getFunction(String name) {
			return findFunction(name)
					.orElseThrow(() -> new CdsOperationNotFoundException(CdsKind.FUNCTION, name, this));
		}

		@Override
		public Optional findFunction(String name) {
			return Optional.ofNullable(functions.get(name));
		}

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy