org.elasticsearch.xpack.esql.expression.function.UnresolvedFunction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of x-pack-esql Show documentation
Show all versions of x-pack-esql Show documentation
The plugin that powers ESQL for Elasticsearch
The newest version!
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
package org.elasticsearch.xpack.esql.expression.function;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.xpack.esql.core.capabilities.Unresolvable;
import org.elasticsearch.xpack.esql.core.capabilities.UnresolvedException;
import org.elasticsearch.xpack.esql.core.expression.Expression;
import org.elasticsearch.xpack.esql.core.expression.Nullability;
import org.elasticsearch.xpack.esql.core.expression.function.Function;
import org.elasticsearch.xpack.esql.core.session.Configuration;
import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
import org.elasticsearch.xpack.esql.core.tree.Source;
import org.elasticsearch.xpack.esql.core.type.DataType;
import org.elasticsearch.xpack.esql.core.util.StringUtils;
import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
public class UnresolvedFunction extends Function implements Unresolvable {
private final String name;
private final String unresolvedMsg;
private final FunctionResolutionStrategy resolution;
/**
* Flag to indicate analysis has been applied and there's no point in
* doing it again this is an optimization to prevent searching for a
* better unresolved message over and over again.
*/
private final boolean analyzed;
public UnresolvedFunction(Source source, String name, FunctionResolutionStrategy resolutionStrategy, List children) {
this(source, name, resolutionStrategy, children, false, null);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public String getWriteableName() {
throw new UnsupportedOperationException();
}
/**
* Constructor used for specifying a more descriptive message (typically
* 'did you mean') instead of the default one.
*
* @see #withMessage(String)
*/
public UnresolvedFunction(
Source source,
String name,
FunctionResolutionStrategy resolutionStrategy,
List children,
boolean analyzed,
String unresolvedMessage
) {
super(source, children);
this.name = name;
this.resolution = resolutionStrategy;
this.analyzed = analyzed;
this.unresolvedMsg = unresolvedMessage == null ? "Unknown " + resolutionStrategy.kind() + " [" + name + "]" : unresolvedMessage;
}
@Override
protected NodeInfo info() {
return NodeInfo.create(this, UnresolvedFunction::new, name, resolution, children(), analyzed, unresolvedMsg);
}
@Override
public Expression replaceChildren(List newChildren) {
return new UnresolvedFunction(source(), name, resolution, newChildren, analyzed, unresolvedMsg);
}
public UnresolvedFunction withMessage(String message) {
return new UnresolvedFunction(source(), name(), resolution, children(), true, message);
}
/**
* Build a function to replace this one after resolving the function.
*/
public Function buildResolved(Configuration configuration, FunctionDefinition def) {
return resolution.buildResolved(this, configuration, def);
}
/**
* Build a marker {@link UnresolvedFunction} with an error message
* about the function being missing.
*/
public UnresolvedFunction missing(String normalizedName, Iterable alternatives) {
// try to find alternatives
Set names = new LinkedHashSet<>();
for (FunctionDefinition def : alternatives) {
if (resolution.isValidAlternative(def)) {
names.add(def.name());
names.addAll(def.aliases());
}
}
List matches = StringUtils.findSimilar(normalizedName, names);
if (matches.isEmpty()) {
return this;
}
String matchesMessage = matches.size() == 1 ? "[" + matches.get(0) + "]" : "any of " + matches;
return withMessage("Unknown " + resolution.kind() + " [" + name + "], did you mean " + matchesMessage + "?");
}
@Override
public boolean resolved() {
return false;
}
public String name() {
return name;
}
public FunctionResolutionStrategy resolutionStrategy() {
return resolution;
}
public boolean analyzed() {
return analyzed;
}
@Override
protected TypeResolution resolveType() {
return new TypeResolution("unresolved function [" + name + "]");
}
@Override
public DataType dataType() {
throw new UnresolvedException("dataType", this);
}
@Override
public Nullability nullable() {
throw new UnresolvedException("nullable", this);
}
@Override
public String unresolvedMessage() {
return unresolvedMsg;
}
@Override
public String toString() {
return UNRESOLVED_PREFIX + name + children();
}
@Override
public String nodeString() {
return toString();
}
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != getClass()) {
return false;
}
UnresolvedFunction other = (UnresolvedFunction) obj;
return name.equals(other.name)
&& resolution.equals(other.resolution)
&& children().equals(other.children())
&& analyzed == other.analyzed
&& Objects.equals(unresolvedMsg, other.unresolvedMsg);
}
@Override
public int hashCode() {
return Objects.hash(name, resolution, children(), analyzed, unresolvedMsg);
}
}