use of io.confluent.ksql.function.types.ParamType in project ksql by confluentinc.
the class UdfIndex method addFunction.
void addFunction(final T function) {
final List<ParamType> parameters = function.parameters();
if (allFunctions.put(parameters, function) != null) {
throw new KsqlFunctionException("Can't add function " + function.name() + " with parameters " + function.parameters() + " as a function with the same name and parameter types already exists " + allFunctions.get(parameters));
}
Node curr = root;
Node parent = curr;
for (final ParamType parameter : parameters) {
final Parameter param = new Parameter(parameter, false);
parent = curr;
curr = curr.children.computeIfAbsent(param, ignored -> new Node());
}
if (function.isVariadic()) {
// first add the function to the parent to address the
// case of empty varargs
parent.update(function);
// then add a new child node with the parameter value type
// and add this function to that node
final ParamType varargSchema = Iterables.getLast(parameters);
final Parameter vararg = new Parameter(varargSchema, true);
final Node leaf = parent.children.computeIfAbsent(vararg, ignored -> new Node());
leaf.update(function);
// add a self referential loop for varargs so that we can
// add as many of the same param at the end and still retrieve
// this node
leaf.children.putIfAbsent(vararg, leaf);
}
curr.update(function);
}
use of io.confluent.ksql.function.types.ParamType in project ksql by confluentinc.
the class GenericsUtilTest method shouldFindNoConstituentGenerics.
@Test
public void shouldFindNoConstituentGenerics() {
// Given:
final StructType struct = StructType.builder().field("a", ParamTypes.LONG).field("b", ParamTypes.DECIMAL).build();
// When:
final Set<ParamType> generics = GenericsUtil.constituentGenerics(struct);
// Then:
assertThat(generics, empty());
}
use of io.confluent.ksql.function.types.ParamType in project ksql by confluentinc.
the class GenericsUtilTest method shouldFindAllConstituentGenericsInLambdaType.
@Test
public void shouldFindAllConstituentGenericsInLambdaType() {
// Given:
final GenericType a = GenericType.of("A");
final GenericType b = GenericType.of("B");
final GenericType c = GenericType.of("C");
final GenericType d = GenericType.of("D");
final ParamType lambda = LambdaType.of(ImmutableList.of(GenericType.of("C"), GenericType.of("A"), GenericType.of("B")), GenericType.of("D"));
// When:
final Set<ParamType> generics = GenericsUtil.constituentGenerics(lambda);
// Then:
assertThat(generics, containsInAnyOrder(a, b, c, d));
}
use of io.confluent.ksql.function.types.ParamType in project ksql by confluentinc.
the class GenericsUtilTest method shouldResolveMapSchemaWithMapping.
@Test
public void shouldResolveMapSchemaWithMapping() {
// Given:
final GenericType a = GenericType.of("A");
final GenericType b = GenericType.of("B");
final ParamType map = MapType.of(a, b);
final ImmutableMap<GenericType, SqlType> mapping = ImmutableMap.of(a, SqlTypes.INTEGER, b, SqlTypes.DOUBLE);
// When:
final SqlType resolved = GenericsUtil.applyResolved(map, mapping);
// Then:
assertThat(resolved, is(SqlTypes.map(SqlTypes.INTEGER, SqlTypes.DOUBLE)));
}
use of io.confluent.ksql.function.types.ParamType in project ksql by confluentinc.
the class FunctionLoaderUtils method handleUdfReturnSchema.
// CHECKSTYLE_RULES.OFF: CyclomaticComplexity
static SchemaProvider handleUdfReturnSchema(final Class theClass, final ParamType javaReturnSchema, final String annotationSchema, final SqlTypeParser parser, final String schemaProviderFunctionName, final String functionName, final boolean isVariadic) {
// CHECKSTYLE_RULES.ON: CyclomaticComplexity
final Function<List<SqlArgument>, SqlType> schemaProvider;
if (!Udf.NO_SCHEMA_PROVIDER.equals(schemaProviderFunctionName)) {
schemaProvider = handleUdfSchemaProviderAnnotation(schemaProviderFunctionName, theClass, functionName);
} else if (!Udf.NO_SCHEMA.equals(annotationSchema)) {
final SqlType sqlType = parser.parse(annotationSchema).getSqlType();
schemaProvider = args -> sqlType;
} else if (!GenericsUtil.hasGenerics(javaReturnSchema)) {
// it is important to do this eagerly and not in the lambda so that
// we can fail early (when loading the UDF) instead of when the user
// attempts to use the UDF
final SqlType sqlType = fromJavaType(javaReturnSchema, functionName);
schemaProvider = args -> sqlType;
} else {
schemaProvider = null;
}
return (parameters, arguments) -> {
if (schemaProvider != null) {
final SqlType returnType = schemaProvider.apply(arguments);
if (!(ParamTypes.areCompatible(SqlArgument.of(returnType), javaReturnSchema, false))) {
throw new KsqlException(String.format("Return type %s of UDF %s does not match the declared " + "return type %s.", returnType, functionName.toUpperCase(), SchemaConverters.functionToSqlConverter().toSqlType(javaReturnSchema)));
}
return returnType;
}
final Map<GenericType, SqlType> genericMapping = new HashMap<>();
for (int i = 0; i < Math.min(parameters.size(), arguments.size()); i++) {
final ParamType schema = parameters.get(i);
if (schema instanceof LambdaType) {
if (isVariadic && i == parameters.size() - 1) {
throw new KsqlException(String.format("Lambda function %s cannot be variadic.", arguments.get(i).toString()));
}
genericMapping.putAll(GenericsUtil.reserveGenerics(schema, arguments.get(i)));
} else {
// we resolve any variadic as if it were an array so that the type
// structure matches the input type
final SqlType instance = isVariadic && i == parameters.size() - 1 ? SqlTypes.array(arguments.get(i).getSqlTypeOrThrow()) : arguments.get(i).getSqlTypeOrThrow();
genericMapping.putAll(GenericsUtil.reserveGenerics(schema, SqlArgument.of(instance)));
}
}
return GenericsUtil.applyResolved(javaReturnSchema, genericMapping);
};
}
Aggregations