/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.facebook.presto.sql.planner.assertions; import com.facebook.presto.sql.tree.Expression; import com.facebook.presto.sql.tree.FunctionCall; import com.facebook.presto.sql.tree.QualifiedName; import com.facebook.presto.sql.tree.WindowFrame; import com.google.common.base.Joiner; import java.util.List; import java.util.Objects; import java.util.Optional; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.toSymbolReferences; import static java.lang.String.format; import static java.util.Objects.requireNonNull; class FunctionCallProvider implements ExpectedValueProvider<FunctionCall> { private boolean isWindowFunction; private final QualifiedName name; private final Optional<WindowFrame> frame; private final boolean distinct; private final List<PlanTestSymbol> args; private FunctionCallProvider(boolean isWindowFunction, QualifiedName name, Optional<WindowFrame> frame, boolean distinct, List<PlanTestSymbol> args) { this.isWindowFunction = isWindowFunction; this.name = requireNonNull(name, "name is null"); this.frame = requireNonNull(frame, "frame is null"); this.distinct = distinct; this.args = requireNonNull(args, "args is null"); } FunctionCallProvider(QualifiedName name, Optional<WindowFrame> frame, boolean distinct, List<PlanTestSymbol> args) { this(true, name, frame, distinct, args); } FunctionCallProvider(QualifiedName name, boolean distinct, List<PlanTestSymbol> args) { this(false, name, Optional.empty(), distinct, args); } FunctionCallProvider(QualifiedName name, List<PlanTestSymbol> args) { this(false, name, Optional.empty(), false, args); } @Override public String toString() { return format("%s%s (%s) %s", distinct ? "DISTINCT" : "", name, Joiner.on(", ").join(args), frame.isPresent() ? frame.get().toString() : ""); } public FunctionCall getExpectedValue(SymbolAliases aliases) { List<Expression> symbolReferences = toSymbolReferences(args, aliases); if (isWindowFunction) { return new ExpectedWindowFunctionCall(symbolReferences); } return new FunctionCall(name, symbolReferences); } private class ExpectedWindowFunctionCall extends FunctionCall { private ExpectedWindowFunctionCall(List<Expression> args) { super(name, distinct, args); } @Override public boolean equals(Object object) { if (this == object) { return true; } if (object == null || !(object instanceof FunctionCall)) { return false; } FunctionCall other = (FunctionCall) object; return Objects.equals(name, other.getName()) && other.getWindow().isPresent() && Objects.equals(frame, other.getWindow().get().getFrame()) && Objects.equals(distinct, other.isDistinct()) && Objects.equals(getArguments(), other.getArguments()); } @Override public int hashCode() { /* * Putting this in a hash table is probably not a useful thing to do, * especially not if you want to compare this with an actual WindowFunction. * This is because (by necessity) ExpectedWindowFunctionCalls don't have the * same fields as FunctionCalls, and can't hash the same as a result. * * If you find a useful case for putting this in a hash table, feel free to * add an implementation. Until then, it would just be dead and untested code. */ throw new UnsupportedOperationException("Test object"); } } }