/*
* Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. Crate licenses
* this file to you 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.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial agreement.
*/
package io.crate.operation.scalar.cast;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import io.crate.analyze.symbol.Symbol;
import io.crate.metadata.FunctionIdent;
import io.crate.metadata.FunctionInfo;
import io.crate.types.ArrayType;
import io.crate.types.DataType;
import io.crate.types.DataTypes;
import io.crate.types.SetType;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
public class CastFunctionResolver {
public static final String TRY_CAST_PREFIX = "try_";
public static class FunctionNames {
public static final String TO_STRING = "to_string";
public static final String TO_INTEGER = "to_int";
public static final String TO_LONG = "to_long";
public static final String TO_TIMESTAMP = "to_timestamp";
public static final String TO_DOUBLE = "to_double";
public static final String TO_BOOLEAN = "to_boolean";
public static final String TO_FLOAT = "to_float";
public static final String TO_BYTE = "to_byte";
public static final String TO_SHORT = "to_short";
public static final String TO_IP = "to_ip";
public static final String TO_OBJECT = "to_object";
public static final String TO_STRING_ARRAY = "to_string_array";
public static final String TO_LONG_ARRAY = "to_long_array";
public static final String TO_INTEGER_ARRAY = "to_int_array";
public static final String TO_DOUBLE_ARRAY = "to_double_array";
public static final String TO_BOOLEAN_ARRAY = "to_boolean_array";
public static final String TO_BYTE_ARRAY = "to_byte_array";
public static final String TO_FLOAT_ARRAY = "to_float_array";
public static final String TO_SHORT_ARRAY = "to_short_array";
public static final String TO_IP_ARRAY = "to_ip_array";
public static final String TO_TIMESTAMP_ARRAY = "to_timestamp_array";
public static final String TO_GEO_POINT = "to_geo_point";
public static final String TO_GEO_SHAPE = "to_geo_shape";
static final String TO_STRING_SET = "to_string_set";
static final String TO_LONG_SET = "to_long_set";
static final String TO_INTEGER_SET = "to_integer_set";
static final String TO_DOUBLE_SET = "to_double_set";
static final String TO_BOOLEAN_SET = "to_boolean_set";
static final String TO_BYTE_SET = "to_byte_set";
static final String TO_FLOAT_SET = "to_float_set";
static final String TO_SHORT_SET = "to_short_set";
static final String TO_IP_SET = "to_ip_set";
}
private static final ImmutableMap<DataType, String> PRIMITIVE_FUNCTION_MAP = new ImmutableMap.Builder<DataType, String>()
.put(DataTypes.STRING, FunctionNames.TO_STRING)
.put(DataTypes.INTEGER, FunctionNames.TO_INTEGER)
.put(DataTypes.LONG, FunctionNames.TO_LONG)
.put(DataTypes.TIMESTAMP, FunctionNames.TO_TIMESTAMP)
.put(DataTypes.DOUBLE, FunctionNames.TO_DOUBLE)
.put(DataTypes.BOOLEAN, FunctionNames.TO_BOOLEAN)
.put(DataTypes.FLOAT, FunctionNames.TO_FLOAT)
.put(DataTypes.BYTE, FunctionNames.TO_BYTE)
.put(DataTypes.SHORT, FunctionNames.TO_SHORT)
.put(DataTypes.IP, FunctionNames.TO_IP)
.build();
private static final ImmutableMap<DataType, String> GEO_FUNCTION_MAP = new ImmutableMap.Builder<DataType, String>()
.put(DataTypes.GEO_POINT, FunctionNames.TO_GEO_POINT)
.put(DataTypes.GEO_SHAPE, FunctionNames.TO_GEO_SHAPE)
.build();
private static final ImmutableMap<DataType, String> ARRAY_FUNCTION_MAP = new ImmutableMap.Builder<DataType, String>()
.put(new ArrayType(DataTypes.STRING), FunctionNames.TO_STRING_ARRAY)
.put(new ArrayType(DataTypes.LONG), FunctionNames.TO_LONG_ARRAY)
.put(new ArrayType(DataTypes.INTEGER), FunctionNames.TO_INTEGER_ARRAY)
.put(new ArrayType(DataTypes.DOUBLE), FunctionNames.TO_DOUBLE_ARRAY)
.put(new ArrayType(DataTypes.BOOLEAN), FunctionNames.TO_BOOLEAN_ARRAY)
.put(new ArrayType(DataTypes.BYTE), FunctionNames.TO_BYTE_ARRAY)
.put(new ArrayType(DataTypes.FLOAT), FunctionNames.TO_FLOAT_ARRAY)
.put(new ArrayType(DataTypes.SHORT), FunctionNames.TO_SHORT_ARRAY)
.put(new ArrayType(DataTypes.IP), FunctionNames.TO_IP_ARRAY)
.put(new ArrayType(DataTypes.TIMESTAMP), FunctionNames.TO_TIMESTAMP_ARRAY)
.build();
private static final ImmutableMap<DataType, String> SET_FUNCTION_MAP = new ImmutableMap.Builder<DataType, String>()
.put(new SetType(DataTypes.STRING), FunctionNames.TO_STRING_SET)
.put(new SetType(DataTypes.LONG), FunctionNames.TO_LONG_SET)
.put(new SetType(DataTypes.INTEGER), FunctionNames.TO_INTEGER_SET)
.put(new SetType(DataTypes.DOUBLE), FunctionNames.TO_DOUBLE_SET)
.put(new SetType(DataTypes.BOOLEAN), FunctionNames.TO_BOOLEAN_SET)
.put(new SetType(DataTypes.BYTE), FunctionNames.TO_BYTE_SET)
.put(new SetType(DataTypes.FLOAT), FunctionNames.TO_FLOAT_SET)
.put(new SetType(DataTypes.SHORT), FunctionNames.TO_SHORT_SET)
.put(new SetType(DataTypes.IP), FunctionNames.TO_IP_SET)
.build();
static final ImmutableMap<DataType, String> FUNCTION_MAP = new ImmutableMap.Builder<DataType, String>()
.putAll(PRIMITIVE_FUNCTION_MAP)
.putAll(GEO_FUNCTION_MAP)
.putAll(ARRAY_FUNCTION_MAP)
.putAll(SET_FUNCTION_MAP)
.put(DataTypes.OBJECT, FunctionNames.TO_OBJECT)
.build();
public static Symbol generateCastFunction(Symbol sourceSymbol, DataType targetType, boolean tryCast) {
DataType sourceType = sourceSymbol.valueType();
FunctionInfo functionInfo = functionInfo(sourceType, targetType, tryCast);
//noinspection ArraysAsListWithZeroOrOneArgument # arguments of Function must be mutable
return new io.crate.analyze.symbol.Function(functionInfo, Arrays.asList(sourceSymbol));
}
/**
* resolve the needed conversion function info based on the wanted return data type
*/
@VisibleForTesting
static FunctionInfo functionInfo(DataType dataType, DataType returnType, boolean tryCast) {
String functionName = FUNCTION_MAP.get(returnType);
if (functionName == null) {
throw new IllegalArgumentException(
String.format(Locale.ENGLISH, "No cast function found for return type %s",
returnType.getName()));
}
functionName = tryCast ? TRY_CAST_PREFIX + functionName : functionName;
return new FunctionInfo(new FunctionIdent(functionName, ImmutableList.of(dataType)), returnType);
}
public static boolean supportsExplicitConversion(DataType returnType) {
return FUNCTION_MAP.get(returnType) != null;
}
private static Function<String, String> TO_TRY_CAST_MAP = new Function<String, String>() {
@Override
public String apply(String functionName) {
return TRY_CAST_PREFIX + functionName;
}
};
public static Map<DataType, String> tryFunctionsMap() {
return Maps.transformValues(FUNCTION_MAP, TO_TRY_CAST_MAP);
}
}