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

com.sap.cds.ql.impl.CqnBuilderImpl Maven / Gradle / Ivy

/*******************************************************************
 * © 2019 SAP SE or an SAP affiliate company. All rights reserved. *
 *******************************************************************/
package com.sap.cds.ql.impl;

import static com.sap.cds.impl.builder.model.ElementRefImpl.element;
import static com.sap.cds.impl.builder.model.StructuredTypeImpl.structuredType;
import static com.sap.cds.impl.builder.model.StructuredTypeRefImpl.typeRef;

import java.time.Instant;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

import com.sap.cds.impl.builder.model.ArithmeticExpr;
import com.sap.cds.impl.builder.model.BooleanFunctionCall;
import com.sap.cds.impl.builder.model.ComparisonPredicate;
import com.sap.cds.impl.builder.model.Connective;
import com.sap.cds.impl.builder.model.CqnParam;
import com.sap.cds.impl.builder.model.ElementRefImpl;
import com.sap.cds.impl.builder.model.ExistsSubQuery;
import com.sap.cds.impl.builder.model.ExpressionImpl;
import com.sap.cds.impl.builder.model.InPredicate;
import com.sap.cds.impl.builder.model.ListValue;
import com.sap.cds.impl.builder.model.LiteralImpl;
import com.sap.cds.impl.builder.model.Negation;
import com.sap.cds.impl.builder.model.ScalarFunctionCall;
import com.sap.cds.impl.builder.model.SearchPredicate;
import com.sap.cds.impl.builder.model.StructuredTypeProxy;
import com.sap.cds.impl.parser.token.CqnPlainImpl;
import com.sap.cds.impl.parser.token.RefSegmentImpl;
import com.sap.cds.ql.BooleanFunction;
import com.sap.cds.ql.CqnBuilder;
import com.sap.cds.ql.CqnParser;
import com.sap.cds.ql.Delete;
import com.sap.cds.ql.ElementRef;
import com.sap.cds.ql.FunctionCall;
import com.sap.cds.ql.Insert;
import com.sap.cds.ql.Literal;
import com.sap.cds.ql.Parameter;
import com.sap.cds.ql.Predicate;
import com.sap.cds.ql.RefSegment;
import com.sap.cds.ql.Select;
import com.sap.cds.ql.Source;
import com.sap.cds.ql.StructuredType;
import com.sap.cds.ql.StructuredTypeRef;
import com.sap.cds.ql.Update;
import com.sap.cds.ql.Upsert;
import com.sap.cds.ql.Value;
import com.sap.cds.ql.cqn.CqnArithmeticExpression;
import com.sap.cds.ql.cqn.CqnComparisonPredicate;
import com.sap.cds.ql.cqn.CqnConnectivePredicate.Operator;
import com.sap.cds.ql.cqn.CqnListValue;
import com.sap.cds.ql.cqn.CqnModifier;
import com.sap.cds.ql.cqn.CqnPredicate;
import com.sap.cds.ql.cqn.CqnReference.Segment;
import com.sap.cds.ql.cqn.CqnSelect;
import com.sap.cds.ql.cqn.CqnStatement;
import com.sap.cds.ql.cqn.CqnStructuredTypeRef;
import com.sap.cds.ql.cqn.CqnValue;
import com.sap.cds.reflect.CdsBaseType;
import com.sap.cds.reflect.CdsEntity;

public class CqnBuilderImpl implements CqnBuilder {

	private final CqnParserImpl parser = new CqnParserImpl();

	@Override
	public Select> select(CqnStructuredTypeRef ref) {
		return SelectBuilder.from(ref);
	}

	@Override
	public Insert insert(CqnStructuredTypeRef ref) {
		return XsertBuilder.insert(ref);
	}

	@Override
	public Upsert upsert(CqnStructuredTypeRef ref) {
		return XsertBuilder.upsert(ref);
	}

	@Override
	public Update> update(CqnStructuredTypeRef ref) {
		return UpdateBuilder.entity(ref);
	}

	@Override
	public Delete> delete(CqnStructuredTypeRef ref) {
		return DeleteBuilder.from(ref);
	}

	@Override
	public > Select select(Source source) {
		return SelectBuilder.from(source);
	}

	@Override
	public Select> select(String entityName) {
		return SelectBuilder.from(entityName);
	}

	@Override
	public Select> select(String entityName, UnaryOperator> path) {
		return SelectBuilder.from(entityName, path);
	}

	@Override
	public Insert insert(String entityName, UnaryOperator> path) {
		CqnStructuredTypeRef structType = applyPath(entityName, path);
		return XsertBuilder.insert(structType);
	}

	@Override
	public Upsert upsert(String entityName, UnaryOperator> path) {
		CqnStructuredTypeRef structType = applyPath(entityName, path);
		return XsertBuilder.upsert(structType);
	}

	@Override
	public Update> update(String entityName, UnaryOperator> path) {
		CqnStructuredTypeRef structType = applyPath(entityName, path);
		return UpdateBuilder.entity(structType);
	}

	@Override
	public Update> update(CdsEntity entity, UnaryOperator> path) {
		return update(entity.getQualifiedName(), path);
	}

	@Override
	public Delete> delete(String entityName, UnaryOperator> path) {
		StructuredTypeRef structType = applyPath(entityName, path);
		return DeleteBuilder.from(structType);
	}

	private static StructuredTypeRef applyPath(String entityName, UnaryOperator> path) {
		StructuredType root = structuredType(entityName);

		return typeRef(path.apply(root));
	}

	@Override
	public > Select select(Class entity) {
		return select(StructuredTypeProxy.create(entity));
	}

	@Override
	public , R extends StructuredType> Select select(Class entity,
			Function path) {
		return select(path.apply(StructuredTypeProxy.create(entity)));
	}

	@Override
	public Select> select(CqnSelect select) {
		return SelectBuilder.from(select);
	}

	@Override
	public , R extends StructuredType> Insert insert(Class entity,
			Function path) {
		return XsertBuilder.insert(path.apply(StructuredTypeProxy.create(entity)));
	}

	@Override
	public , R extends StructuredType> Upsert upsert(Class entity,
			Function path) {
		return XsertBuilder.upsert(path.apply(StructuredTypeProxy.create(entity)));
	}

	@Override
	public , R extends StructuredType> Update update(Class entity,
			Function path) {
		return UpdateBuilder.entity(path.apply(StructuredTypeProxy.create(entity)));
	}

	@Override
	public , R extends StructuredType> Delete delete(Class entity,
			Function path) {
		return DeleteBuilder.from(path.apply(StructuredTypeProxy.create(entity)));
	}

	@Override
	public Select> select(CdsEntity entity) {
		return select(entity.getQualifiedName());
	}

	@Override
	public Select> select(CdsEntity entity, UnaryOperator> path) {
		return select(entity.getQualifiedName(), path);
	}

	@Override
	public Insert insert(CdsEntity entity, UnaryOperator> path) {
		return insert(entity.getQualifiedName(), path);
	}

	@Override
	public Upsert upsert(CdsEntity entity, UnaryOperator> path) {
		return upsert(entity.getQualifiedName(), path);
	}

	@Override
	public Delete> delete(CdsEntity entity, UnaryOperator> path) {
		return delete(entity.getQualifiedName(), path);
	}

	@Override
	public > Delete delete(E entity) {
		return DeleteBuilder.from(entity);
	}

	@Override
	public > Insert insert(E entity) {
		return XsertBuilder.insert(entity);
	}

	@Override
	public > Upsert upsert(E entity) {
		return XsertBuilder.upsert(entity);
	}

	@Override
	public > Update update(E entity) {
		return UpdateBuilder.entity(entity);
	}

	@Override
	public  R copy(S statement) {
		return copy(statement, ExpressionVisitor.COPY);
	}

	@Override
	@SuppressWarnings("unchecked")
	public  R copy(S statement, CqnModifier modifier) {
		if (statement.isSelect()) {
			return (R) SelectBuilder.copy(statement.asSelect(), modifier);
		}
		if (statement.isInsert()) {
			return (R) XsertBuilder.copy(statement.asInsert(), modifier);
		}
		if (statement.isUpsert()) {
			return (R) XsertBuilder.copy(statement.asUpsert(), modifier);
		}
		if (statement.isUpdate()) {
			return (R) UpdateBuilder.copy(statement.asUpdate(), modifier);
		}
		if (statement.isDelete()) {
			return (R) DeleteBuilder.copy(statement.asDelete(), modifier);
		}
		throw new UnsupportedOperationException("Cannot copy statement " + statement);
	}

	@Override
	public Predicate copy(CqnPredicate pred) {
		return ExpressionVisitor.copy(pred);
	}

	@Override
	public Predicate copy(CqnPredicate pred, CqnModifier modifier) {
		return ExpressionVisitor.copy(pred, modifier);
	}

	@Override
	public CqnParser parse() {
		return parser;
	}

	@Override
	public QueryBuilderSupport support() {
		return new QueryBuilderSupport() {
			@Override
			public  Parameter param() {
				return CqnParam.param();
			}

			@Override
			public  Parameter param(String name) {
				return CqnParam.param(name);
			}

			@Override
			public  FunctionCall func(String functionName, Iterable args) {
				FunctionCall func = ScalarFunctionCall.create(functionName, args);
				if ("max".equalsIgnoreCase(functionName) || "min".equalsIgnoreCase(functionName)) {
					args.iterator().next().type().ifPresent(func::type);
				}
				return func;
			}

			@Override
			public BooleanFunction booleanFunc(String functionName, List args) {
				return BooleanFunctionCall.create(functionName, args);
			}

			@Override
			public CqnListValue list(List values) {
				return ListValue.of(values);
			}

			@Override
			public  Literal literal(T val) {
				return LiteralImpl.literal(val);
			}

			@Override
			public Value plain(String val) {
				return CqnPlainImpl.plain(val);
			}

			@Override
			public Predicate not(CqnPredicate p) {
				return Negation.not(p);
			}

			@Override
			public Predicate connect(Operator operator, Iterable predicates) {
				return Connective.create(operator, predicates);
			}

			@Override
			public Value toLower(Value val) {
				return ScalarFunctionCall.create("tolower", val).type(CdsBaseType.STRING);
			}

			@Override
			public Value toUpper(Value val) {
				return ScalarFunctionCall.create("toupper", val).type(CdsBaseType.STRING);
			}

			@Override
			public StructuredType entity(String qualifiedName) {
				return structuredType(qualifiedName);
			}

			@Override
			public  ElementRef get(String path) {
				return ElementRefImpl.parse(path);
			}

			@Override
			public  ElementRef get(List segments) {
				return element(segments);
			}

			@Override
			public StructuredType to(String path) {
				return structuredType(typeRef(path.split("\\.")));
			}

			@Override
			public StructuredType to(List segments) {
				return structuredType(typeRef(segments));
			}

			@Override
			public RefSegment refSegment(String id) {
				return RefSegmentImpl.refSegment(id);
			}

			@Override
			public List refSegments(List segmentIds) {
				return segmentIds.stream().map(this::refSegment).collect(Collectors.toList());
			}

			@Override
			public Value expression(CqnValue left, CqnArithmeticExpression.Operator op, CqnValue right) {
				return ArithmeticExpr.expression(left, op, right);
			}

			@Override
			public Predicate comparison(CqnValue lhs, CqnComparisonPredicate.Operator op, CqnValue rhs) {
				return ComparisonPredicate.pred(lhs, op, rhs);
			}

			@Override
			public Predicate in(CqnValue lhs, Collection values) {
				return InPredicate.in(lhs, values.stream());
			}

			@Override
			public Predicate search(String term) {
				return new SearchPredicate(term);
			}

			@Override
			public Predicate exists(CqnSelect subQuery) {
				return new ExistsSubQuery(subQuery);
			}

			public ElementRef now() {
				return get("$now");
			}

			@Override
			public ElementRef validFrom() {
				return element("$at", "from");
			}

			@Override
			public ElementRef validTo() {
				return element("$at", "to");
			}

			@Override
			public ElementRef userLocale() {
				return element("$user", "locale");
			}

			@Override
			public ElementRef userId() {
				return element("$user", "id");
			}

			@Override
			public Value countDistinct(CqnValue value) {
				return ScalarFunctionCall.create("countDistinct", value).type(Long.class);
			}

		};
	}

	public Predicate matching(Map keyValueMap) {
		return ExpressionImpl.matching(keyValueMap);
	}

}